#include "audit.h"
#include "policycap_names.h"
-static struct selinux_ss selinux_ss;
-
-void selinux_ss_init(struct selinux_ss **ss)
-{
- rwlock_init(&selinux_ss.policy_rwlock);
- *ss = &selinux_ss;
-}
-
/* Forward declaration. */
static int context_struct_to_string(struct policydb *policydb,
struct context *context,
int security_mls_enabled(struct selinux_state *state)
{
int mls_enabled;
+ struct selinux_policy *policy;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
- mls_enabled = state->ss->policy->policydb.mls_enabled;
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ mls_enabled = policy->policydb.mls_enabled;
+ rcu_read_unlock();
return mls_enabled;
}
}
static int security_validtrans_handle_fail(struct selinux_state *state,
- struct sidtab_entry *oentry,
- struct sidtab_entry *nentry,
- struct sidtab_entry *tentry,
- u16 tclass)
+ struct selinux_policy *policy,
+ struct sidtab_entry *oentry,
+ struct sidtab_entry *nentry,
+ struct sidtab_entry *tentry,
+ u16 tclass)
{
- struct policydb *p = &state->ss->policy->policydb;
- struct sidtab *sidtab = state->ss->policy->sidtab;
+ struct policydb *p = &policy->policydb;
+ struct sidtab *sidtab = policy->sidtab;
char *o = NULL, *n = NULL, *t = NULL;
u32 olen, nlen, tlen;
u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass, bool user)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct sidtab_entry *oentry;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
+ rcu_read_lock();
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
if (!user)
- tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+ tclass = unmap_class(&policy->map, orig_tclass);
else
tclass = orig_tclass;
rc = -EPERM;
else
rc = security_validtrans_handle_fail(state,
- oentry,
- nentry,
- tentry,
- tclass);
+ policy,
+ oentry,
+ nentry,
+ tentry,
+ tclass);
goto out;
}
constraint = constraint->next;
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_bounded_transition(struct selinux_state *state,
u32 old_sid, u32 new_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct sidtab_entry *old_entry, *new_entry;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
rc = -EINVAL;
old_entry = sidtab_search_entry(sidtab, old_sid);
kfree(old_name);
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
-static void avd_init(struct selinux_state *state, struct av_decision *avd)
+static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
{
avd->allowed = 0;
avd->auditallow = 0;
avd->auditdeny = 0xffffffff;
- avd->seqno = state->ss->latest_granting;
+ if (policy)
+ avd->seqno = policy->latest_granting;
+ else
+ avd->seqno = 0;
avd->flags = 0;
}
u8 driver,
struct extended_perms_decision *xpermd)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
u16 tclass;
memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
- read_lock(&state->ss->policy_rwlock);
+ rcu_read_lock();
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto out;
}
- tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+ tclass = unmap_class(&policy->map, orig_tclass);
if (unlikely(orig_tclass && !tclass)) {
if (policydb->allow_unknown)
goto allow;
}
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return;
allow:
memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
struct av_decision *avd,
struct extended_perms *xperms)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
u16 tclass;
struct context *scontext = NULL, *tcontext = NULL;
- read_lock(&state->ss->policy_rwlock);
- avd_init(state, avd);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ avd_init(policy, avd);
xperms->len = 0;
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto out;
}
- tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+ tclass = unmap_class(&policy->map, orig_tclass);
if (unlikely(orig_tclass && !tclass)) {
if (policydb->allow_unknown)
goto allow;
}
context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
xperms);
- map_decision(&state->ss->policy->map, orig_tclass, avd,
+ map_decision(&policy->map, orig_tclass, avd,
policydb->allow_unknown);
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return;
allow:
avd->allowed = 0xffffffff;
u16 tclass,
struct av_decision *avd)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct context *scontext = NULL, *tcontext = NULL;
- read_lock(&state->ss->policy_rwlock);
- avd_init(state, avd);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ avd_init(policy, avd);
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
NULL);
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return;
allow:
avd->allowed = 0xffffffff;
int security_sidtab_hash_stats(struct selinux_state *state, char *page)
{
+ struct selinux_policy *policy;
int rc;
if (!selinux_initialized(state)) {
return -EINVAL;
}
- read_lock(&state->ss->policy_rwlock);
- rc = sidtab_hash_stats(state->ss->policy->sidtab, page);
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ rc = sidtab_hash_stats(policy->sidtab, page);
+ rcu_read_unlock();
return rc;
}
u32 *scontext_len, int force,
int only_invalid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct sidtab_entry *entry;
"load_policy on unknown SID %d\n", __func__, sid);
return -EINVAL;
}
- read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
if (force)
entry = sidtab_search_entry_force(sidtab, sid);
scontext_len);
out_unlock:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
u32 *sid, u32 def_sid, gfp_t gfp_flags,
int force)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
char *scontext2, *str = NULL;
if (!str)
goto out;
}
- read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
&context, def_sid);
if (rc == -EINVAL && force) {
rc = sidtab_context_to_sid(sidtab, &context, sid);
context_destroy(&context);
out_unlock:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
out:
kfree(scontext2);
kfree(str);
static int compute_sid_handle_invalid_context(
struct selinux_state *state,
+ struct selinux_policy *policy,
struct sidtab_entry *sentry,
struct sidtab_entry *tentry,
u16 tclass,
struct context *newcontext)
{
- struct policydb *policydb = &state->ss->policy->policydb;
- struct sidtab *sidtab = state->ss->policy->sidtab;
+ struct policydb *policydb = &policy->policydb;
+ struct sidtab *sidtab = policy->sidtab;
char *s = NULL, *t = NULL, *n = NULL;
u32 slen, tlen, nlen;
struct audit_buffer *ab;
u32 *out_sid,
bool kern)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct class_datum *cladatum = NULL;
context_init(&newcontext);
- read_lock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+
+ policy = rcu_dereference(state->policy);
if (kern) {
- tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+ tclass = unmap_class(&policy->map, orig_tclass);
sock = security_is_socket_class(orig_tclass);
} else {
tclass = orig_tclass;
- sock = security_is_socket_class(map_class(&state->ss->policy->map,
+ sock = security_is_socket_class(map_class(&policy->map,
tclass));
}
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
sentry = sidtab_search_entry(sidtab, ssid);
if (!sentry) {
/* Check the validity of the context. */
if (!policydb_context_isvalid(policydb, &newcontext)) {
- rc = compute_sid_handle_invalid_context(state, sentry, tentry,
- tclass, &newcontext);
+ rc = compute_sid_handle_invalid_context(state, policy, sentry,
+ tentry, tclass,
+ &newcontext);
if (rc)
goto out_unlock;
}
/* Obtain the sid for the context. */
rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
out_unlock:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
context_destroy(&newcontext);
out:
return rc;
static inline int convert_context_handle_invalid_context(
struct selinux_state *state,
+ struct policydb *policydb,
struct context *context)
{
- struct policydb *policydb = &state->ss->policy->policydb;
char *s;
u32 len;
/* Check the validity of the new context. */
if (!policydb_context_isvalid(args->newp, newc)) {
- rc = convert_context_handle_invalid_context(args->state, oldc);
+ rc = convert_context_handle_invalid_context(args->state,
+ args->oldp,
+ oldc);
if (rc)
goto bad;
}
return 0;
}
-static void security_load_policycaps(struct selinux_state *state)
+static void security_load_policycaps(struct selinux_state *state,
+ struct selinux_policy *policy)
{
struct policydb *p;
unsigned int i;
struct ebitmap_node *node;
- read_lock(&state->ss->policy_rwlock);
-
- p = &state->ss->policy->policydb;
+ p = &policy->policydb;
for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
pr_info("SELinux: unknown policy capability %u\n",
i);
}
-
- read_unlock(&state->ss->policy_rwlock);
}
-static int security_preserve_bools(struct selinux_state *state,
- struct policydb *newpolicydb);
+static int security_preserve_bools(struct selinux_policy *oldpolicy,
+ struct selinux_policy *newpolicy);
static void selinux_policy_free(struct selinux_policy *policy)
{
kfree(policy);
}
+static void selinux_policy_cond_free(struct selinux_policy *policy)
+{
+ cond_policydb_destroy_dup(&policy->policydb);
+ kfree(policy);
+}
+
void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *policy)
{
- sidtab_cancel_convert(state->ss->policy->sidtab);
+ struct selinux_policy *oldpolicy;
+
+ /*
+ * NOTE: We do not need to take the rcu read lock
+ * around the code below because other policy-modifying
+ * operations are already excluded by selinuxfs via
+ * fsi->mutex.
+ */
+ oldpolicy = rcu_dereference_check(state->policy, 1);
+
+ sidtab_cancel_convert(oldpolicy->sidtab);
selinux_policy_free(policy);
}
u32 seqno;
/*
- * NOTE: We do not need to take the policy read-lock
+ * NOTE: We do not need to take the rcu read lock
* around the code below because other policy-modifying
* operations are already excluded by selinuxfs via
* fsi->mutex.
*/
+ oldpolicy = rcu_dereference_check(state->policy, 1);
/* If switching between different policy types, log MLS status */
- oldpolicy = state->ss->policy;
if (oldpolicy) {
if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
pr_info("SELinux: Disabling MLS support...\n");
pr_info("SELinux: Enabling MLS support...\n");
}
+ /* Set latest granting seqno for new policy. */
+ if (oldpolicy)
+ newpolicy->latest_granting = oldpolicy->latest_granting + 1;
+ else
+ newpolicy->latest_granting = 1;
+ seqno = newpolicy->latest_granting;
+
/* Install the new policy. */
- write_lock_irq(&state->ss->policy_rwlock);
- state->ss->policy = newpolicy;
- seqno = ++state->ss->latest_granting;
- write_unlock_irq(&state->ss->policy_rwlock);
+ rcu_assign_pointer(state->policy, newpolicy);
/* Load the policycaps from the new policy */
- security_load_policycaps(state);
+ security_load_policycaps(state, newpolicy);
if (!selinux_initialized(state)) {
/*
}
/* Free the old policy */
+ synchronize_rcu();
selinux_policy_free(oldpolicy);
/* Notify others of the policy change */
int security_load_policy(struct selinux_state *state, void *data, size_t len,
struct selinux_policy **newpolicyp)
{
- struct selinux_policy *newpolicy;
+ struct selinux_policy *newpolicy, *oldpolicy;
struct sidtab_convert_params convert_params;
struct convert_context_args args;
int rc = 0;
return 0;
}
+ /*
+ * NOTE: We do not need to take the rcu read lock
+ * around the code below because other policy-modifying
+ * operations are already excluded by selinuxfs via
+ * fsi->mutex.
+ */
+ oldpolicy = rcu_dereference_check(state->policy, 1);
+
/* Preserve active boolean values from the old policy */
- rc = security_preserve_bools(state, &newpolicy->policydb);
+ rc = security_preserve_bools(oldpolicy, newpolicy);
if (rc) {
pr_err("SELinux: unable to preserve booleans\n");
goto err;
/*
* Convert the internal representations of contexts
* in the new SID table.
- *
- * NOTE: We do not need to take the policy read-lock
- * around the code below because other policy-modifying
- * operations are already excluded by selinuxfs via
- * fsi->mutex.
*/
args.state = state;
- args.oldp = &state->ss->policy->policydb;
+ args.oldp = &oldpolicy->policydb;
args.newp = &newpolicy->policydb;
convert_params.func = convert_context;
convert_params.args = &args;
convert_params.target = newpolicy->sidtab;
- rc = sidtab_convert(state->ss->policy->sidtab, &convert_params);
+ rc = sidtab_convert(oldpolicy->sidtab, &convert_params);
if (rc) {
pr_err("SELinux: unable to convert the internal"
" representation of contexts in the new SID"
size_t security_policydb_len(struct selinux_state *state)
{
+ struct selinux_policy *policy;
size_t len;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
- len = state->ss->policy->policydb.len;
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ len = policy->policydb.len;
+ rcu_read_unlock();
return len;
}
int security_port_sid(struct selinux_state *state,
u8 protocol, u16 port, u32 *out_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
c = policydb->ocontexts[OCON_PORT];
while (c) {
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_ib_pkey_sid(struct selinux_state *state,
u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
c = policydb->ocontexts[OCON_IBPKEY];
while (c) {
*out_sid = SECINITSID_UNLABELED;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_ib_endport_sid(struct selinux_state *state,
const char *dev_name, u8 port_num, u32 *out_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
c = policydb->ocontexts[OCON_IBENDPORT];
while (c) {
*out_sid = SECINITSID_UNLABELED;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_netif_sid(struct selinux_state *state,
char *name, u32 *if_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc = 0;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
c = policydb->ocontexts[OCON_NETIF];
while (c) {
*if_sid = SECINITSID_NETIF;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
u32 addrlen,
u32 *out_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
switch (domain) {
case AF_INET: {
rc = 0;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
u32 **sids,
u32 *nel)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct context *fromcon, usercon;
if (!selinux_initialized(state))
goto out;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
context_init(&usercon);
}
rc = 0;
out_unlock:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
if (rc || !mynel) {
kfree(mysids);
goto out;
u16 orig_sclass,
u32 *sid)
{
+ struct selinux_policy *policy;
int retval;
if (!selinux_initialized(state)) {
return 0;
}
- read_lock(&state->ss->policy_rwlock);
- retval = __security_genfs_sid(state->ss->policy,
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ retval = __security_genfs_sid(policy,
fstype, path, orig_sclass, sid);
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return retval;
}
*/
int security_fs_use(struct selinux_state *state, struct super_block *sb)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc = 0;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
c = policydb->ocontexts[OCON_FSUSE];
while (c) {
}
sbsec->sid = c->sid[0];
} else {
- rc = __security_genfs_sid(state->ss->policy, fstype, "/",
+ rc = __security_genfs_sid(policy, fstype, "/",
SECCLASS_DIR, &sbsec->sid);
if (rc) {
sbsec->behavior = SECURITY_FS_USE_NONE;
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
return -EINVAL;
/*
- * NOTE: We do not need to take the policy read-lock
+ * NOTE: We do not need to take the rcu read lock
* around the code below because other policy-modifying
* operations are already excluded by selinuxfs via
* fsi->mutex.
*/
+ oldpolicy = rcu_dereference_check(state->policy, 1);
+
/* Consistency check on number of booleans, should never fail */
- if (WARN_ON(len != state->ss->policy->policydb.p_bools.nprim))
+ if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
return -EINVAL;
- newpolicy = kmemdup(state->ss->policy, sizeof(*newpolicy),
- GFP_KERNEL);
+ newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
if (!newpolicy)
return -ENOMEM;
- oldpolicy = state->ss->policy;
-
/*
* Deep copy only the parts of the policydb that might be
* modified as a result of changing booleans.
/* Re-evaluate the conditional rules in the copy */
evaluate_cond_nodes(&newpolicy->policydb);
+ /* Set latest granting seqno for new policy */
+ newpolicy->latest_granting = oldpolicy->latest_granting + 1;
+ seqno = newpolicy->latest_granting;
+
/* Install the new policy */
- write_lock_irq(&state->ss->policy_rwlock);
- state->ss->policy = newpolicy;
- seqno = ++state->ss->latest_granting;
- write_unlock_irq(&state->ss->policy_rwlock);
+ rcu_assign_pointer(state->policy, newpolicy);
/*
* Free the conditional portions of the old policydb
- * that were copied for the new policy.
+ * that were copied for the new policy, and the oldpolicy
+ * structure itself but not what it references.
*/
- cond_policydb_destroy_dup(&oldpolicy->policydb);
-
- /* Free the old policy structure but not what it references. */
- kfree(oldpolicy);
+ synchronize_rcu();
+ selinux_policy_cond_free(oldpolicy);
/* Notify others of the policy change */
selinux_notify_policy_change(state, seqno);
int security_get_bool_value(struct selinux_state *state,
u32 index)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
int rc;
u32 len;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
rc = -EFAULT;
len = policydb->p_bools.nprim;
rc = policydb->bool_val_to_struct[index]->state;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
-static int security_preserve_bools(struct selinux_state *state,
- struct policydb *policydb)
+static int security_preserve_bools(struct selinux_policy *oldpolicy,
+ struct selinux_policy *newpolicy)
{
int rc, *bvalues = NULL;
char **bnames = NULL;
struct cond_bool_datum *booldatum;
u32 i, nbools = 0;
- read_lock(&state->ss->policy_rwlock);
- rc = security_get_bools(state->ss->policy, &nbools, &bnames, &bvalues);
- read_unlock(&state->ss->policy_rwlock);
+ rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
if (rc)
goto out;
for (i = 0; i < nbools; i++) {
- booldatum = symtab_search(&policydb->p_bools, bnames[i]);
+ booldatum = symtab_search(&newpolicy->policydb.p_bools,
+ bnames[i]);
if (booldatum)
booldatum->state = bvalues[i];
}
- evaluate_cond_nodes(policydb);
+ evaluate_cond_nodes(&newpolicy->policydb);
out:
if (bnames) {
int security_sid_mls_copy(struct selinux_state *state,
u32 sid, u32 mls_sid, u32 *new_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
struct context *context1;
context_init(&newcon);
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
if (!policydb->mls_enabled) {
*new_sid = sid;
/* Check the validity of the new context. */
if (!policydb_context_isvalid(policydb, &newcon)) {
- rc = convert_context_handle_invalid_context(state, &newcon);
+ rc = convert_context_handle_invalid_context(state, policydb,
+ &newcon);
if (rc) {
if (!context_struct_to_string(policydb, &newcon, &s,
&len)) {
}
rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
out_unlock:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
context_destroy(&newcon);
out:
return rc;
u32 xfrm_sid,
u32 *peer_sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
/*
* We don't need to check initialized here since the only way both
* expressive */
*peer_sid = xfrm_sid;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_get_reject_unknown(struct selinux_state *state)
{
+ struct selinux_policy *policy;
int value;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
- value = state->ss->policy->policydb.reject_unknown;
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ value = policy->policydb.reject_unknown;
+ rcu_read_unlock();
return value;
}
int security_get_allow_unknown(struct selinux_state *state)
{
+ struct selinux_policy *policy;
int value;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
- value = state->ss->policy->policydb.allow_unknown;
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ value = policy->policydb.allow_unknown;
+ rcu_read_unlock();
return value;
}
int security_policycap_supported(struct selinux_state *state,
unsigned int req_cap)
{
+ struct selinux_policy *policy;
int rc;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
- rc = ebitmap_get_bit(&state->ss->policy->policydb.policycaps, req_cap);
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
+ rcu_read_unlock();
return rc;
}
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
{
struct selinux_state *state = &selinux_state;
+ struct selinux_policy *policy;
struct policydb *policydb;
struct selinux_audit_rule *tmprule;
struct role_datum *roledatum;
context_init(&tmprule->au_ctxt);
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
- tmprule->au_seqno = state->ss->latest_granting;
+ tmprule->au_seqno = policy->latest_granting;
switch (field) {
case AUDIT_SUBJ_USER:
}
rc = 0;
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
if (rc) {
selinux_audit_rule_free(tmprule);
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
{
struct selinux_state *state = &selinux_state;
+ struct selinux_policy *policy;
struct context *ctxt;
struct mls_level *level;
struct selinux_audit_rule *rule = vrule;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+
+ policy = rcu_dereference(state->policy);
- if (rule->au_seqno < state->ss->latest_granting) {
+ if (rule->au_seqno < policy->latest_granting) {
match = -ESTALE;
goto out;
}
- ctxt = sidtab_search(state->ss->policy->sidtab, sid);
+ ctxt = sidtab_search(policy->sidtab, sid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
sid);
}
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return match;
}
struct netlbl_lsm_secattr *secattr,
u32 *sid)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc;
return 0;
}
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
- sidtab = state->ss->policy->sidtab;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
+ sidtab = policy->sidtab;
if (secattr->flags & NETLBL_SECATTR_CACHE)
*sid = *(u32 *)secattr->cache->data;
} else
*sid = SECSID_NULL;
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return 0;
out_free:
ebitmap_destroy(&ctx_new.range.level[0].cat);
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
int security_netlbl_sid_to_secattr(struct selinux_state *state,
u32 sid, struct netlbl_lsm_secattr *secattr)
{
+ struct selinux_policy *policy;
struct policydb *policydb;
int rc;
struct context *ctx;
if (!selinux_initialized(state))
return 0;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ policydb = &policy->policydb;
rc = -ENOENT;
- ctx = sidtab_search(state->ss->policy->sidtab, sid);
+ ctx = sidtab_search(policy->sidtab, sid);
if (ctx == NULL)
goto out;
mls_export_netlbl_lvl(policydb, ctx, secattr);
rc = mls_export_netlbl_cat(policydb, ctx, secattr);
out:
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_unlock();
return rc;
}
#endif /* CONFIG_NETLABEL */
int security_read_policy(struct selinux_state *state,
void **data, size_t *len)
{
+ struct selinux_policy *policy;
int rc;
struct policy_file fp;
fp.data = *data;
fp.len = *len;
- read_lock(&state->ss->policy_rwlock);
- rc = policydb_write(&state->ss->policy->policydb, &fp);
- read_unlock(&state->ss->policy_rwlock);
+ rcu_read_lock();
+ policy = rcu_dereference(state->policy);
+ rc = policydb_write(&policy->policydb, &fp);
+ rcu_read_unlock();
if (rc)
return rc;