summaryrefslogtreecommitdiff
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c159
1 files changed, 87 insertions, 72 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f62adf3cfce8..a0afe49309c8 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2251,6 +2251,43 @@ size_t security_policydb_len(struct selinux_state *state)
}
/**
+ * ocontext_to_sid - Helper to safely get sid for an ocontext
+ * @sidtab: SID table
+ * @c: ocontext structure
+ * @index: index of the context entry (0 or 1)
+ * @out_sid: pointer to the resulting SID value
+ *
+ * For all ocontexts except OCON_ISID the SID fields are populated
+ * on-demand when needed. Since updating the SID value is an SMP-sensitive
+ * operation, this helper must be used to do that safely.
+ *
+ * WARNING: This function may return -ESTALE, indicating that the caller
+ * must retry the operation after re-acquiring the policy pointer!
+ */
+static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
+ size_t index, u32 *out_sid)
+{
+ int rc;
+ u32 sid;
+
+ /* Ensure the associated sidtab entry is visible to this thread. */
+ sid = smp_load_acquire(&c->sid[index]);
+ if (!sid) {
+ rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
+ if (rc)
+ return rc;
+
+ /*
+ * Ensure the new sidtab entry is visible to other threads
+ * when they see the SID.
+ */
+ smp_store_release(&c->sid[index], sid);
+ }
+ *out_sid = sid;
+ return 0;
+}
+
+/**
* security_port_sid - Obtain the SID for a port.
* @protocol: protocol number
* @port: port number
@@ -2262,10 +2299,12 @@ int security_port_sid(struct selinux_state *state,
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
- int rc = 0;
+ int rc;
read_lock(&state->ss->policy_rwlock);
+retry:
+ rc = 0;
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2279,14 +2318,11 @@ int security_port_sid(struct selinux_state *state,
}
if (c) {
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab,
- &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- }
- *out_sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else {
*out_sid = SECINITSID_PORT;
}
@@ -2308,10 +2344,12 @@ int security_ib_pkey_sid(struct selinux_state *state,
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
- int rc = 0;
+ int rc;
read_lock(&state->ss->policy_rwlock);
+retry:
+ rc = 0;
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2326,14 +2364,11 @@ int security_ib_pkey_sid(struct selinux_state *state,
}
if (c) {
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab,
- &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- }
- *out_sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else
*out_sid = SECINITSID_UNLABELED;
@@ -2354,10 +2389,12 @@ int security_ib_endport_sid(struct selinux_state *state,
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
- int rc = 0;
+ int rc;
read_lock(&state->ss->policy_rwlock);
+retry:
+ rc = 0;
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2373,14 +2410,11 @@ int security_ib_endport_sid(struct selinux_state *state,
}
if (c) {
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab,
- &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- }
- *out_sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else
*out_sid = SECINITSID_UNLABELED;
@@ -2399,11 +2433,13 @@ int security_netif_sid(struct selinux_state *state,
{
struct policydb *policydb;
struct sidtab *sidtab;
- int rc = 0;
+ int rc;
struct ocontext *c;
read_lock(&state->ss->policy_rwlock);
+retry:
+ rc = 0;
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2415,19 +2451,11 @@ int security_netif_sid(struct selinux_state *state,
}
if (c) {
- if (!c->sid[0] || !c->sid[1]) {
- rc = sidtab_context_to_sid(sidtab,
- &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- rc = sidtab_context_to_sid(sidtab,
- &c->context[1],
- &c->sid[1]);
- if (rc)
- goto out;
- }
- *if_sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, if_sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else
*if_sid = SECINITSID_NETIF;
@@ -2469,6 +2497,7 @@ int security_node_sid(struct selinux_state *state,
read_lock(&state->ss->policy_rwlock);
+retry:
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2511,14 +2540,11 @@ int security_node_sid(struct selinux_state *state,
}
if (c) {
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab,
- &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- }
- *out_sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else {
*out_sid = SECINITSID_NODE;
}
@@ -2677,7 +2703,7 @@ static inline int __security_genfs_sid(struct selinux_state *state,
u16 sclass;
struct genfs *genfs;
struct ocontext *c;
- int rc, cmp = 0;
+ int cmp = 0;
while (path[0] == '/' && path[1] == '/')
path++;
@@ -2691,9 +2717,8 @@ static inline int __security_genfs_sid(struct selinux_state *state,
break;
}
- rc = -ENOENT;
if (!genfs || cmp)
- goto out;
+ return -ENOENT;
for (c = genfs->head; c; c = c->next) {
len = strlen(c->u.name);
@@ -2702,20 +2727,10 @@ static inline int __security_genfs_sid(struct selinux_state *state,
break;
}
- rc = -ENOENT;
if (!c)
- goto out;
-
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
- if (rc)
- goto out;
- }
+ return -ENOENT;
- *sid = c->sid[0];
- rc = 0;
-out:
- return rc;
+ return ocontext_to_sid(sidtab, c, 0, sid);
}
/**
@@ -2750,13 +2765,15 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
{
struct policydb *policydb;
struct sidtab *sidtab;
- int rc = 0;
+ int rc;
struct ocontext *c;
struct superblock_security_struct *sbsec = sb->s_security;
const char *fstype = sb->s_type->name;
read_lock(&state->ss->policy_rwlock);
+retry:
+ rc = 0;
policydb = &state->ss->policydb;
sidtab = state->ss->sidtab;
@@ -2769,13 +2786,11 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
if (c) {
sbsec->behavior = c->v.behavior;
- if (!c->sid[0]) {
- rc = sidtab_context_to_sid(sidtab, &c->context[0],
- &c->sid[0]);
- if (rc)
- goto out;
- }
- sbsec->sid = c->sid[0];
+ rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
+ if (rc == -ESTALE)
+ goto retry;
+ if (rc)
+ goto out;
} else {
rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
&sbsec->sid);