int security_mls_enabled(struct selinux_state *state)
{
- struct policydb *p = &state->ss->policydb;
+ int mls_enabled;
- return p->mls_enabled;
+ 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);
+ return mls_enabled;
}
/*
struct sidtab_entry *tentry,
u16 tclass)
{
- struct policydb *p = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *p = &state->ss->policy->policydb;
+ struct sidtab *sidtab = &state->ss->policy->sidtab;
char *o = NULL, *n = NULL, *t = NULL;
u32 olen, nlen, tlen;
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
if (!user)
- tclass = unmap_class(&state->ss->map, orig_tclass);
+ tclass = unmap_class(&state->ss->policy->map, orig_tclass);
else
tclass = orig_tclass;
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
rc = -EINVAL;
old_entry = sidtab_search_entry(sidtab, old_sid);
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto out;
}
- tclass = unmap_class(&state->ss->map, orig_tclass);
+ tclass = unmap_class(&state->ss->policy->map, orig_tclass);
if (unlikely(orig_tclass && !tclass)) {
if (policydb->allow_unknown)
goto allow;
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto out;
}
- tclass = unmap_class(&state->ss->map, orig_tclass);
+ tclass = unmap_class(&state->ss->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->map, orig_tclass, avd,
+ map_decision(&state->ss->policy->map, orig_tclass, avd,
policydb->allow_unknown);
out:
read_unlock(&state->ss->policy_rwlock);
if (!selinux_initialized(state))
goto allow;
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
}
read_lock(&state->ss->policy_rwlock);
- rc = sidtab_hash_stats(state->ss->sidtab, page);
+ rc = sidtab_hash_stats(&state->ss->policy->sidtab, page);
read_unlock(&state->ss->policy_rwlock);
return rc;
return -EINVAL;
}
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
if (force)
entry = sidtab_search_entry_force(sidtab, sid);
goto out;
}
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
&context, def_sid);
if (rc == -EINVAL && force) {
u16 tclass,
struct context *newcontext)
{
- struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *policydb = &state->ss->policy->policydb;
+ struct sidtab *sidtab = &state->ss->policy->sidtab;
char *s = NULL, *t = NULL, *n = NULL;
u32 slen, tlen, nlen;
struct audit_buffer *ab;
read_lock(&state->ss->policy_rwlock);
if (kern) {
- tclass = unmap_class(&state->ss->map, orig_tclass);
+ tclass = unmap_class(&state->ss->policy->map, orig_tclass);
sock = security_is_socket_class(orig_tclass);
} else {
tclass = orig_tclass;
- sock = security_is_socket_class(map_class(&state->ss->map,
+ sock = security_is_socket_class(map_class(&state->ss->policy->map,
tclass));
}
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
sentry = sidtab_search_entry(sidtab, ssid);
if (!sentry) {
struct selinux_state *state,
struct context *context)
{
- struct policydb *policydb = &state->ss->policydb;
+ struct policydb *policydb = &state->ss->policy->policydb;
char *s;
u32 len;
static void security_load_policycaps(struct selinux_state *state)
{
- struct policydb *p = &state->ss->policydb;
+ struct policydb *p;
unsigned int i;
struct ebitmap_node *node;
+ read_lock(&state->ss->policy_rwlock);
+
+ p = &state->ss->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 void selinux_policy_free(struct selinux_policy *policy)
+{
+ if (!policy)
+ return;
+
+ policydb_destroy(&policy->policydb);
+ sidtab_destroy(&policy->sidtab);
+ kfree(policy->map.mapping);
+ kfree(policy);
+}
+
+static void selinux_policy_commit(struct selinux_state *state,
+ struct selinux_policy *newpolicy)
+{
+ struct selinux_policy *oldpolicy;
+ u32 seqno;
+
+ /*
+ * 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.
+ */
+
+ /* 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");
+ else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
+ pr_info("SELinux: Enabling MLS support...\n");
+ }
+
+ /* 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);
+
+ /* Load the policycaps from the new policy */
+ security_load_policycaps(state);
+
+ if (!selinux_initialized(state)) {
+ /*
+ * After first policy load, the security server is
+ * marked as initialized and ready to handle requests and
+ * any objects created prior to policy load are then labeled.
+ */
+ selinux_mark_initialized(state);
+ selinux_complete_init();
+ }
+
+ /* Free the old policy */
+ selinux_policy_free(oldpolicy);
+
+ /* Flush external caches and notify userspace of policy load */
+ avc_ss_reset(state->avc, seqno);
+ selnl_notify_policyload(seqno);
+ selinux_status_update_policyload(state, seqno);
+ selinux_netlbl_cache_invalidate();
+ selinux_xfrm_notify_policyload();
+}
+
/**
* security_load_policy - Load a security policy configuration.
* @data: binary policy data
*/
int security_load_policy(struct selinux_state *state, void *data, size_t len)
{
- struct policydb *policydb;
- struct sidtab *oldsidtab, *newsidtab;
- struct policydb *oldpolicydb, *newpolicydb;
- struct selinux_mapping *oldmapping;
- struct selinux_map newmap;
+ struct selinux_policy *newpolicy;
struct sidtab_convert_params convert_params;
struct convert_context_args args;
- u32 seqno;
int rc = 0;
struct policy_file file = { data, len }, *fp = &file;
- policydb = &state->ss->policydb;
-
- newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL);
- if (!newsidtab)
+ newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
+ if (!newpolicy)
return -ENOMEM;
- if (!selinux_initialized(state)) {
- rc = policydb_read(policydb, fp);
- if (rc) {
- kfree(newsidtab);
- return rc;
- }
-
- policydb->len = len;
- rc = selinux_set_mapping(policydb, secclass_map,
- &state->ss->map);
- if (rc) {
- kfree(newsidtab);
- policydb_destroy(policydb);
- return rc;
- }
-
- rc = policydb_load_isids(policydb, newsidtab);
- if (rc) {
- kfree(newsidtab);
- policydb_destroy(policydb);
- return rc;
- }
-
- state->ss->sidtab = newsidtab;
- security_load_policycaps(state);
- selinux_mark_initialized(state);
- seqno = ++state->ss->latest_granting;
- selinux_complete_init();
- avc_ss_reset(state->avc, seqno);
- selnl_notify_policyload(seqno);
- selinux_status_update_policyload(state, seqno);
- selinux_netlbl_cache_invalidate();
- selinux_xfrm_notify_policyload();
- return 0;
- }
+ rc = policydb_read(&newpolicy->policydb, fp);
+ if (rc)
+ goto err;
- oldpolicydb = kcalloc(2, sizeof(*oldpolicydb), GFP_KERNEL);
- if (!oldpolicydb) {
- kfree(newsidtab);
- return -ENOMEM;
- }
- newpolicydb = oldpolicydb + 1;
+ newpolicy->policydb.len = len;
+ rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
+ &newpolicy->map);
+ if (rc)
+ goto err;
- rc = policydb_read(newpolicydb, fp);
+ rc = policydb_load_isids(&newpolicy->policydb, &newpolicy->sidtab);
if (rc) {
- kfree(newsidtab);
- goto out;
+ pr_err("SELinux: unable to load the initial SIDs\n");
+ goto err;
}
- newpolicydb->len = len;
- /* If switching between different policy types, log MLS status */
- if (policydb->mls_enabled && !newpolicydb->mls_enabled)
- pr_info("SELinux: Disabling MLS support...\n");
- else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
- pr_info("SELinux: Enabling MLS support...\n");
- rc = policydb_load_isids(newpolicydb, newsidtab);
- if (rc) {
- pr_err("SELinux: unable to load the initial SIDs\n");
- policydb_destroy(newpolicydb);
- kfree(newsidtab);
- goto out;
+ if (!selinux_initialized(state)) {
+ /* First policy load, so no need to preserve state from old policy */
+ selinux_policy_commit(state, newpolicy);
+ return 0;
}
- rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap);
- if (rc)
- goto err;
-
- rc = security_preserve_bools(state, newpolicydb);
+ /* Preserve active boolean values from the old policy */
+ rc = security_preserve_bools(state, &newpolicy->policydb);
if (rc) {
pr_err("SELinux: unable to preserve booleans\n");
goto err;
}
- oldsidtab = state->ss->sidtab;
-
/*
* 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 = policydb;
- args.newp = newpolicydb;
+ args.oldp = &state->ss->policy->policydb;
+ args.newp = &newpolicy->policydb;
convert_params.func = convert_context;
convert_params.args = &args;
- convert_params.target = newsidtab;
+ convert_params.target = &newpolicy->sidtab;
- rc = sidtab_convert(oldsidtab, &convert_params);
+ rc = sidtab_convert(&state->ss->policy->sidtab, &convert_params);
if (rc) {
pr_err("SELinux: unable to convert the internal"
" representation of contexts in the new SID"
goto err;
}
- /* Save the old policydb and SID table to free later. */
- memcpy(oldpolicydb, policydb, sizeof(*policydb));
-
- /* Install the new policydb and SID table. */
- write_lock_irq(&state->ss->policy_rwlock);
- memcpy(policydb, newpolicydb, sizeof(*policydb));
- state->ss->sidtab = newsidtab;
- security_load_policycaps(state);
- oldmapping = state->ss->map.mapping;
- state->ss->map.mapping = newmap.mapping;
- state->ss->map.size = newmap.size;
- seqno = ++state->ss->latest_granting;
- write_unlock_irq(&state->ss->policy_rwlock);
-
- /* Free the old policydb and SID table. */
- policydb_destroy(oldpolicydb);
- sidtab_destroy(oldsidtab);
- kfree(oldsidtab);
- kfree(oldmapping);
-
- avc_ss_reset(state->avc, seqno);
- selnl_notify_policyload(seqno);
- selinux_status_update_policyload(state, seqno);
- selinux_netlbl_cache_invalidate();
- selinux_xfrm_notify_policyload();
-
- rc = 0;
- goto out;
-
+ selinux_policy_commit(state, newpolicy);
+ return 0;
err:
- kfree(newmap.mapping);
- sidtab_destroy(newsidtab);
- kfree(newsidtab);
- policydb_destroy(newpolicydb);
-
-out:
- kfree(oldpolicydb);
+ selinux_policy_free(newpolicy);
return rc;
}
size_t security_policydb_len(struct selinux_state *state)
{
- struct policydb *p = &state->ss->policydb;
size_t len;
read_lock(&state->ss->policy_rwlock);
- len = p->len;
+ len = state->ss->policy->policydb.len;
read_unlock(&state->ss->policy_rwlock);
return len;
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
c = policydb->ocontexts[OCON_PORT];
while (c) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
c = policydb->ocontexts[OCON_IBPKEY];
while (c) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
c = policydb->ocontexts[OCON_IBENDPORT];
while (c) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
c = policydb->ocontexts[OCON_NETIF];
while (c) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
switch (domain) {
case AF_INET: {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
context_init(&usercon);
u16 orig_sclass,
u32 *sid)
{
- struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *policydb = &state->ss->policy->policydb;
+ struct sidtab *sidtab = &state->ss->policy->sidtab;
int len;
u16 sclass;
struct genfs *genfs;
while (path[0] == '/' && path[1] == '/')
path++;
- sclass = unmap_class(&state->ss->map, orig_sclass);
+ sclass = unmap_class(&state->ss->policy->map, orig_sclass);
*sid = SECINITSID_UNLABELED;
for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
- sidtab = state->ss->sidtab;
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
c = policydb->ocontexts[OCON_FSUSE];
while (c) {
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
+ policydb = &state->ss->policy->policydb;
*names = NULL;
*values = NULL;
write_lock_irq(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
+ policydb = &state->ss->policy->policydb;
rc = -EFAULT;
lenp = policydb->p_bools.nprim;
read_lock(&state->ss->policy_rwlock);
- policydb = &state->ss->policydb;
+ policydb = &state->ss->policy->policydb;
rc = -EFAULT;
len = policydb->p_bools.nprim;
int security_sid_mls_copy(struct selinux_state *state,
u32 sid, u32 mls_sid, u32 *new_sid)
{
- struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *policydb;
+ struct sidtab *sidtab;
struct context *context1;
struct context *context2;
struct context newcon;
int rc;
rc = 0;
- if (!selinux_initialized(state) || !policydb->mls_enabled) {
+ if (!selinux_initialized(state)) {
*new_sid = sid;
goto out;
}
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
+
+ if (!policydb->mls_enabled) {
+ *new_sid = sid;
+ goto out_unlock;
+ }
+
rc = -EINVAL;
context1 = sidtab_search(sidtab, sid);
if (!context1) {
u32 xfrm_sid,
u32 *peer_sid)
{
- struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *policydb;
+ struct sidtab *sidtab;
int rc;
struct context *nlbl_ctx;
struct context *xfrm_ctx;
return 0;
}
+ read_lock(&state->ss->policy_rwlock);
+
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
+
/*
* We don't need to check initialized here since the only way both
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
* security server was initialized and state->initialized was true.
*/
- if (!policydb->mls_enabled)
- return 0;
-
- read_lock(&state->ss->policy_rwlock);
+ if (!policydb->mls_enabled) {
+ rc = 0;
+ goto out;
+ }
rc = -EINVAL;
nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
int security_get_classes(struct selinux_state *state,
char ***classes, int *nclasses)
{
- struct policydb *policydb = &state->ss->policydb;
+ struct policydb *policydb;
int rc;
if (!selinux_initialized(state)) {
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+
rc = -ENOMEM;
*nclasses = policydb->p_classes.nprim;
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
int security_get_permissions(struct selinux_state *state,
char *class, char ***perms, int *nperms)
{
- struct policydb *policydb = &state->ss->policydb;
+ struct policydb *policydb;
int rc, i;
struct class_datum *match;
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+
rc = -EINVAL;
match = symtab_search(&policydb->p_classes, class);
if (!match) {
int security_get_reject_unknown(struct selinux_state *state)
{
- return state->ss->policydb.reject_unknown;
+ int value;
+
+ read_lock(&state->ss->policy_rwlock);
+ value = state->ss->policy->policydb.reject_unknown;
+ read_unlock(&state->ss->policy_rwlock);
+ return value;
}
int security_get_allow_unknown(struct selinux_state *state)
{
- return state->ss->policydb.allow_unknown;
+ int value;
+
+ read_lock(&state->ss->policy_rwlock);
+ value = state->ss->policy->policydb.allow_unknown;
+ read_unlock(&state->ss->policy_rwlock);
+ return value;
}
/**
int security_policycap_supported(struct selinux_state *state,
unsigned int req_cap)
{
- struct policydb *policydb = &state->ss->policydb;
int rc;
read_lock(&state->ss->policy_rwlock);
- rc = ebitmap_get_bit(&policydb->policycaps, req_cap);
+ rc = ebitmap_get_bit(&state->ss->policy->policydb.policycaps, req_cap);
read_unlock(&state->ss->policy_rwlock);
return rc;
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
{
struct selinux_state *state = &selinux_state;
- struct policydb *policydb = &state->ss->policydb;
+ struct policydb *policydb;
struct selinux_audit_rule *tmprule;
struct role_datum *roledatum;
struct type_datum *typedatum;
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+
tmprule->au_seqno = state->ss->latest_granting;
switch (field) {
goto out;
}
- ctxt = sidtab_search(state->ss->sidtab, sid);
+ ctxt = sidtab_search(&state->ss->policy->sidtab, sid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
sid);
struct netlbl_lsm_secattr *secattr,
u32 *sid)
{
- struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = state->ss->sidtab;
+ struct policydb *policydb;
+ struct sidtab *sidtab;
int rc;
struct context *ctx;
struct context ctx_new;
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+ sidtab = &state->ss->policy->sidtab;
+
if (secattr->flags & NETLBL_SECATTR_CACHE)
*sid = *(u32 *)secattr->cache->data;
else if (secattr->flags & NETLBL_SECATTR_SECID)
int security_netlbl_sid_to_secattr(struct selinux_state *state,
u32 sid, struct netlbl_lsm_secattr *secattr)
{
- struct policydb *policydb = &state->ss->policydb;
+ struct policydb *policydb;
int rc;
struct context *ctx;
read_lock(&state->ss->policy_rwlock);
+ policydb = &state->ss->policy->policydb;
+
rc = -ENOENT;
- ctx = sidtab_search(state->ss->sidtab, sid);
+ ctx = sidtab_search(&state->ss->policy->sidtab, sid);
if (ctx == NULL)
goto out;
int security_read_policy(struct selinux_state *state,
void **data, size_t *len)
{
- struct policydb *policydb = &state->ss->policydb;
int rc;
struct policy_file fp;
fp.len = *len;
read_lock(&state->ss->policy_rwlock);
- rc = policydb_write(policydb, &fp);
+ rc = policydb_write(&state->ss->policy->policydb, &fp);
read_unlock(&state->ss->policy_rwlock);
if (rc)