diff options
Diffstat (limited to '')
-rw-r--r-- | security/selinux/ss/services.c | 273 |
1 files changed, 154 insertions, 119 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b3efae204ac7..cf27b3ee1a95 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -26,6 +26,10 @@ * * Added support for bounds domain and audit messaged on masked permissions * + * Updated: Guido Trentalancia <guido@trentalancia.com> + * + * Added support for runtime switching of the policy type + * * Copyright (C) 2008, 2009 NEC Corporation * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. @@ -87,11 +91,10 @@ static u32 latest_granting; static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len); -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd); +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd); struct selinux_mapping { u16 value; /* policy value */ @@ -196,23 +199,6 @@ static u16 unmap_class(u16 tclass) return tclass; } -static u32 unmap_perm(u16 tclass, u32 tperm) -{ - if (tclass < current_mapping_size) { - unsigned i; - u32 kperm = 0; - - for (i = 0; i < current_mapping[tclass].num_perms; i++) - if (tperm & (1<<i)) { - kperm |= current_mapping[tclass].perms[i]; - tperm &= ~(1<<i); - } - return kperm; - } - - return tperm; -} - static void map_decision(u16 tclass, struct av_decision *avd, int allow_unknown) { @@ -250,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd, } } +int security_mls_enabled(void) +{ + return policydb.mls_enabled; +} /* * Return the boolean value of a constraint expression @@ -465,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext, char *scontext_name = NULL; char *tcontext_name = NULL; char *permission_names[32]; - int index, length; + int index; + u32 length; bool need_comma = false; if (!permissions) @@ -532,7 +523,6 @@ out: static void type_attribute_bounds_av(struct context *scontext, struct context *tcontext, u16 tclass, - u32 requested, struct av_decision *avd) { struct context lo_scontext; @@ -553,7 +543,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -569,7 +558,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -586,7 +574,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -607,11 +594,10 @@ static void type_attribute_bounds_av(struct context *scontext, * Compute access vectors based on a context structure pair for * the permissions in a particular class. */ -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd) { struct constraint_node *constraint; struct role_allow *ra; @@ -622,19 +608,14 @@ static int context_struct_compute_av(struct context *scontext, struct ebitmap_node *snode, *tnode; unsigned int i, j; - /* - * Initialize the access vectors to the default values. - */ avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (printk_ratelimit()) printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); - return -EINVAL; + return; } tclass_datum = policydb.class_val_to_struct[tclass - 1]; @@ -705,9 +686,7 @@ static int context_struct_compute_av(struct context *scontext, * permission and notice it to userspace via audit. */ type_attribute_bounds_av(scontext, tcontext, - tclass, requested, avd); - - return 0; + tclass, avd); } static int security_validtrans_handle_fail(struct context *ocontext, @@ -864,7 +843,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) if (rc) { char *old_name = NULL; char *new_name = NULL; - int length; + u32 length; if (!context_struct_to_string(old_context, &old_name, &length) && @@ -886,110 +865,116 @@ out: return rc; } - -static int security_compute_av_core(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void avd_init(struct av_decision *avd) { - struct context *scontext = NULL, *tcontext = NULL; - int rc = 0; - - scontext = sidtab_search(&sidtab, ssid); - if (!scontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, ssid); - return -EINVAL; - } - tcontext = sidtab_search(&sidtab, tsid); - if (!tcontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, tsid); - return -EINVAL; - } - - rc = context_struct_compute_av(scontext, tcontext, tclass, - requested, avd); - - /* permissive domain? */ - if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) - avd->flags |= AVD_FLAGS_PERMISSIVE; - - return rc; + avd->allowed = 0; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = latest_granting; + avd->flags = 0; } + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class - * @requested: requested permissions * @avd: access vector decisions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. - * Return -%EINVAL if any of the parameters are invalid or %0 - * if the access vector decisions were computed successfully. */ -int security_compute_av(u32 ssid, - u32 tsid, - u16 orig_tclass, - u32 orig_requested, - struct av_decision *avd) +void security_compute_av(u32 ssid, + u32 tsid, + u16 orig_tclass, + struct av_decision *avd) { u16 tclass; - u32 requested; - int rc; + struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); - + avd_init(avd); if (!ss_initialized) goto allow; - requested = unmap_perm(orig_tclass, orig_requested); + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + tclass = unmap_class(orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb.allow_unknown) goto allow; - rc = -EINVAL; goto out; } - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); - return rc; + return; allow: avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; - rc = 0; goto out; } -int security_compute_av_user(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +void security_compute_av_user(u32 ssid, + u32 tsid, + u16 tclass, + struct av_decision *avd) { - int rc; + struct context *scontext = NULL, *tcontext = NULL; - if (!ss_initialized) { - avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - return 0; + read_lock(&policy_rwlock); + avd_init(avd); + if (!ss_initialized) + goto allow; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; } - read_lock(&policy_rwlock); - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + + if (unlikely(!tclass)) { + if (policydb.allow_unknown) + goto allow; + goto out; + } + + context_struct_compute_av(scontext, tcontext, tclass, avd); + out: read_unlock(&policy_rwlock); - return rc; + return; +allow: + avd->allowed = 0xffffffff; + goto out; } /* @@ -1565,7 +1550,10 @@ static int clone_sid(u32 sid, { struct sidtab *s = arg; - return sidtab_insert(s, sid, context); + if (sid > SECINITSID_NUM) + return sidtab_insert(s, sid, context); + else + return 0; } static inline int convert_context_handle_invalid_context(struct context *context) @@ -1606,12 +1594,17 @@ static int convert_context(u32 key, { struct convert_context_args *args; struct context oldc; + struct ocontext *oc; + struct mls_range *range; struct role_datum *role; struct type_datum *typdatum; struct user_datum *usrdatum; char *s; u32 len; - int rc; + int rc = 0; + + if (key <= SECINITSID_NUM) + goto out; args = p; @@ -1673,9 +1666,39 @@ static int convert_context(u32 key, goto bad; c->type = typdatum->value; - rc = mls_convert_context(args->oldp, args->newp, c); - if (rc) - goto bad; + /* Convert the MLS fields if dealing with MLS policies */ + if (args->oldp->mls_enabled && args->newp->mls_enabled) { + rc = mls_convert_context(args->oldp, args->newp, c); + if (rc) + goto bad; + } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { + /* + * Switching between MLS and non-MLS policy: + * free any storage used by the MLS fields in the + * context for all existing entries in the sidtab. + */ + mls_context_destroy(c); + } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { + /* + * Switching between non-MLS and MLS policy: + * ensure that the MLS fields of the context for all + * existing entries in the sidtab are filled in with a + * suitable default value, likely taken from one of the + * initial SIDs. + */ + oc = args->newp->ocontexts[OCON_ISID]; + while (oc && oc->sid[0] != SECINITSID_UNLABELED) + oc = oc->next; + if (!oc) { + printk(KERN_ERR "SELinux: unable to look up" + " the initial SIDs list\n"); + goto bad; + } + range = &oc->context[0].range; + rc = mls_range_set(c, range); + if (rc) + goto bad; + } /* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, c)) { @@ -1771,9 +1794,17 @@ int security_load_policy(void *data, size_t len) if (policydb_read(&newpolicydb, fp)) return -EINVAL; - if (sidtab_init(&newsidtab)) { + /* If switching between different policy types, log MLS status */ + if (policydb.mls_enabled && !newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Disabling MLS support...\n"); + else if (!policydb.mls_enabled && newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Enabling MLS support...\n"); + + rc = policydb_load_isids(&newpolicydb, &newsidtab); + if (rc) { + printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); policydb_destroy(&newpolicydb); - return -ENOMEM; + return rc; } if (selinux_set_mapping(&newpolicydb, secclass_map, @@ -1800,8 +1831,12 @@ int security_load_policy(void *data, size_t len) args.oldp = &policydb; args.newp = &newpolicydb; rc = sidtab_map(&newsidtab, convert_context, &args); - if (rc) + if (rc) { + printk(KERN_ERR "SELinux: unable to convert the internal" + " representation of contexts in the new SID" + " table\n"); goto err; + } /* Save the old policydb and SID table to free later. */ memcpy(&oldpolicydb, &policydb, sizeof policydb); @@ -2397,7 +2432,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) u32 len; int rc = 0; - if (!ss_initialized || !selinux_mls_enabled) { + if (!ss_initialized || !policydb.mls_enabled) { *new_sid = sid; goto out; } @@ -2498,7 +2533,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, /* we don't need to check ss_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 ss_initialized was true */ - if (!selinux_mls_enabled) { + if (!policydb.mls_enabled) { *peer_sid = SECSID_NULL; return 0; } @@ -2555,7 +2590,7 @@ int security_get_classes(char ***classes, int *nclasses) read_lock(&policy_rwlock); *nclasses = policydb.p_classes.nprim; - *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); + *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); if (!*classes) goto out; @@ -2602,7 +2637,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) } *nperms = match->permissions.nprim; - *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); + *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); if (!*perms) goto out; |