From 9f59f90bf57cff8be07faddc608c400b6e7c5d05 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 6 Dec 2009 10:16:51 +0100 Subject: security/selinux/ss: correct size computation The size argument to kcalloc should be the size of desired structure, not the pointer to it. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @expression@ expression *x; @@ x = <+... -sizeof(x) +sizeof(*x) ...+>// Signed-off-by: Julia Lawall Acked-by: Eric Paris Signed-off-by: James Morris --- security/selinux/ss/services.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d6bb20cbad62..07ddc81d7b57 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2555,7 +2555,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 +2602,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; -- cgit v1.2.2 From 08e3daff217059c84c360cc71212686e0a7995af Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 3 Dec 2009 03:48:28 -0500 Subject: selinux: remove a useless return The last return is unreachable, remove the 'return' in default, let it fall through. Signed-off-by: WANG Cong Acked-by: Eric Paris Signed-off-by: James Morris --- security/selinux/ss/mls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 3f2b2706b5bb..e6654b543aed 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -541,8 +541,8 @@ int mls_compute_sid(struct context *scontext, case AVTAB_MEMBER: /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); - default: - return -EINVAL; + + /* fall through */ } return -EINVAL; } -- cgit v1.2.2 From 19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 14 Jan 2010 17:28:10 -0500 Subject: selinux: change the handling of unknown classes If allow_unknown==deny, SELinux treats an undefined kernel security class as an error condition rather than as a typical permission denial and thus does not allow permissions on undefined classes even when in permissive mode. Change the SELinux logic so that this case is handled as a typical permission denial, subject to the usual permissive mode and permissive domain handling. Also drop the 'requested' argument from security_compute_av() and helpers as it is a legacy of the original security server interface and is unused. Changes: - Handle permissive domains consistently by moving up the test for a permissive domain. - Make security_compute_av_user() consistent with security_compute_av(); the only difference now is that security_compute_av() performs mapping between the kernel-private class and permission indices and the policy values. In the userspace case, this mapping is handled by libselinux. - Moved avd_init inside the policy lock. Based in part on a patch by Paul Moore . Reported-by: Andrew Worsley Signed-off-by: Stephen D. Smalley Reviewed-by: Paul Moore Signed-off-by: James Morris --- security/selinux/ss/services.c | 186 ++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 105 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 07ddc81d7b57..9ec24169ccd7 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -87,11 +87,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 +195,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<allowed) == avd->allowed) return; /* no masked permission */ @@ -569,7 +549,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 +565,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 +585,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 +599,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 +677,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, @@ -886,110 +856,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; } /* -- cgit v1.2.2 From 2f3e82d694d3d7a2db019db1bb63385fbc1066f3 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 7 Jan 2010 15:55:16 -0500 Subject: selinux: convert range transition list to a hashtab Per https://bugzilla.redhat.com/show_bug.cgi?id=548145 there are sufficient range transition rules in modern (Fedora) policy to make mls_compute_sid a significant factor on the shmem file setup path due to the length of the range_tr list. Replace the simple range_tr list with a hashtab inside the security server to help mitigate this problem. Signed-off-by: Stephen D. Smalley Signed-off-by: James Morris --- security/selinux/ss/mls.c | 18 ++++--- security/selinux/ss/policydb.c | 103 ++++++++++++++++++++++++++++++----------- security/selinux/ss/policydb.h | 6 +-- 3 files changed, 86 insertions(+), 41 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index e6654b543aed..443ae7370144 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -513,7 +513,8 @@ int mls_compute_sid(struct context *scontext, u32 specified, struct context *newcontext) { - struct range_trans *rtr; + struct range_trans rtr; + struct mls_range *r; if (!selinux_mls_enabled) return 0; @@ -521,15 +522,12 @@ int mls_compute_sid(struct context *scontext, switch (specified) { case AVTAB_TRANSITION: /* Look for a range transition rule. */ - for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { - if (rtr->source_type == scontext->type && - rtr->target_type == tcontext->type && - rtr->target_class == tclass) { - /* Set the range from the rule */ - return mls_range_set(newcontext, - &rtr->target_range); - } - } + rtr.source_type = scontext->type; + rtr.target_type = tcontext->type; + rtr.target_class = tclass; + r = hashtab_search(policydb.range_tr, &rtr); + if (r) + return mls_range_set(newcontext, r); /* Fallthrough */ case AVTAB_CHANGE: if (tclass == policydb.process_class) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea8..5b92c0219207 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -177,6 +177,21 @@ out_free_role: goto out; } +static u32 rangetr_hash(struct hashtab *h, const void *k) +{ + const struct range_trans *key = k; + return (key->source_type + (key->target_type << 3) + + (key->target_class << 5)) & (h->size - 1); +} + +static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) +{ + const struct range_trans *key1 = k1, *key2 = k2; + return (key1->source_type != key2->source_type || + key1->target_type != key2->target_type || + key1->target_class != key2->target_class); +} + /* * Initialize a policy database structure. */ @@ -204,6 +219,10 @@ static int policydb_init(struct policydb *p) if (rc) goto out_free_symtab; + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); + if (!p->range_tr) + goto out_free_symtab; + ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); @@ -408,6 +427,20 @@ static void symtab_hash_eval(struct symtab *s) info.slots_used, h->size, info.max_chain_len); } } + +static void rangetr_hash_eval(struct hashtab *h) +{ + struct hashtab_info info; + + hashtab_stat(h, &info); + printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " + "longest chain length %d\n", h->nel, + info.slots_used, h->size, info.max_chain_len); +} +#else +static inline void rangetr_hash_eval(struct hashtab *h) +{ +} #endif /* @@ -612,6 +645,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = cat_destroy, }; +static int range_tr_destroy(void *key, void *datum, void *p) +{ + struct mls_range *rt = datum; + kfree(key); + ebitmap_destroy(&rt->level[0].cat); + ebitmap_destroy(&rt->level[1].cat); + kfree(datum); + cond_resched(); + return 0; +} + static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); @@ -632,7 +676,6 @@ void policydb_destroy(struct policydb *p) int i; struct role_allow *ra, *lra = NULL; struct role_trans *tr, *ltr = NULL; - struct range_trans *rt, *lrt = NULL; for (i = 0; i < SYM_NUM; i++) { cond_resched(); @@ -693,20 +736,8 @@ void policydb_destroy(struct policydb *p) } kfree(lra); - for (rt = p->range_tr; rt; rt = rt->next) { - cond_resched(); - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } - lrt = rt; - } - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } + hashtab_map(p->range_tr, range_tr_destroy, NULL); + hashtab_destroy(p->range_tr); if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) @@ -1689,7 +1720,8 @@ int policydb_read(struct policydb *p, void *fp) u32 len, len2, config, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; - struct range_trans *rt, *lrt; + struct range_trans *rt; + struct mls_range *r; config = 0; @@ -2122,44 +2154,61 @@ int policydb_read(struct policydb *p, void *fp) if (rc < 0) goto bad; nel = le32_to_cpu(buf[0]); - lrt = NULL; for (i = 0; i < nel; i++) { rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (!rt) { rc = -ENOMEM; goto bad; } - if (lrt) - lrt->next = rt; - else - p->range_tr = rt; rc = next_entry(buf, fp, (sizeof(u32) * 2)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->source_type = le32_to_cpu(buf[0]); rt->target_type = le32_to_cpu(buf[1]); if (new_rangetr) { rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->target_class = le32_to_cpu(buf[0]); } else rt->target_class = p->process_class; if (!policydb_type_isvalid(p, rt->source_type) || !policydb_type_isvalid(p, rt->target_type) || !policydb_class_isvalid(p, rt->target_class)) { + kfree(rt); rc = -EINVAL; goto bad; } - rc = mls_read_range_helper(&rt->target_range, fp); - if (rc) + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + kfree(rt); + rc = -ENOMEM; goto bad; - if (!mls_range_isvalid(p, &rt->target_range)) { + } + rc = mls_read_range_helper(r, fp); + if (rc) { + kfree(rt); + kfree(r); + goto bad; + } + if (!mls_range_isvalid(p, r)) { printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); + kfree(rt); + kfree(r); + goto bad; + } + rc = hashtab_insert(p->range_tr, rt, r); + if (rc) { + kfree(rt); + kfree(r); goto bad; } - lrt = rt; } + rangetr_hash_eval(p->range_tr); } p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946f..193736b64de8 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -113,8 +113,6 @@ struct range_trans { u32 source_type; u32 target_type; u32 target_class; - struct mls_range target_range; - struct range_trans *next; }; /* Boolean data type */ @@ -240,8 +238,8 @@ struct policydb { fixed labeling behavior. */ struct genfs *genfs; - /* range transitions */ - struct range_trans *range_tr; + /* range transitions table (range_trans_key -> mls_range) */ + struct hashtab *range_tr; /* type -> attribute reverse mapping */ struct ebitmap *type_attr_map; -- cgit v1.2.2 From 7d52a155e38d5a165759dbbee656455861bf7801 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 21 Jan 2010 15:00:15 +0900 Subject: selinux: remove dead code in type_attribute_bounds_av() This patch removes dead code in type_attribute_bounds_av(). Due to the historical reason, the type boundary feature is delivered from hierarchical types in libsepol, it has supported boundary features both of subject type (domain; in most cases) and target type. However, we don't have any actual use cases in bounded target types, and it tended to make conceptual confusion. So, this patch removes the dead code to apply boundary checks on the target types. I makes clear the TYPEBOUNDS restricts privileges of a certain domain bounded to any other domain. Signed-off-by: KaiGai Kohei Acked-by: Stephen Smalley -- security/selinux/ss/services.c | 43 +++------------------------------------ 1 files changed, 4 insertions(+), 39 deletions(-) Signed-off-by: James Morris --- security/selinux/ss/services.c | 43 ++++-------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 3b42b154d87c..4a2bf212057b 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -516,16 +516,14 @@ static void type_attribute_bounds_av(struct context *scontext, u16 tclass, struct av_decision *avd) { - struct context lo_scontext; - struct context lo_tcontext; - struct av_decision lo_avd; struct type_datum *source = policydb.type_val_to_struct[scontext->type - 1]; - struct type_datum *target - = policydb.type_val_to_struct[tcontext->type - 1]; - u32 masked = 0; if (source->bounds) { + struct context lo_scontext; + struct av_decision lo_avd; + u32 masked; + memset(&lo_avd, 0, sizeof(lo_avd)); memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); @@ -538,40 +536,7 @@ static void type_attribute_bounds_av(struct context *scontext, if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; - } - - if (target->bounds) { - memset(&lo_avd, 0, sizeof(lo_avd)); - - memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); - lo_tcontext.type = target->bounds; - - context_struct_compute_av(scontext, - &lo_tcontext, - tclass, - &lo_avd); - if ((lo_avd.allowed & avd->allowed) == avd->allowed) - return; /* no masked permission */ - masked = ~lo_avd.allowed & avd->allowed; - } - - if (source->bounds && target->bounds) { - memset(&lo_avd, 0, sizeof(lo_avd)); - /* - * lo_scontext and lo_tcontext are already - * set up. - */ - - context_struct_compute_av(&lo_scontext, - &lo_tcontext, - tclass, - &lo_avd); - if ((lo_avd.allowed & avd->allowed) == avd->allowed) - return; /* no masked permission */ - masked = ~lo_avd.allowed & avd->allowed; - } - if (masked) { /* mask violated permissions */ avd->allowed &= ~masked; -- cgit v1.2.2 From 42596eafdd75257a640f64701b9b07090bcd84b0 Mon Sep 17 00:00:00 2001 From: Guido Trentalancia Date: Wed, 3 Feb 2010 17:06:01 +0100 Subject: selinux: load the initial SIDs upon every policy load Always load the initial SIDs, even in the case of a policy reload and not just at the initial policy load. This comes particularly handy after the introduction of a recent patch for enabling runtime switching between different policy types, although this patch is in theory independent from that feature. Signed-off-by: Guido Trentalancia Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/ss/services.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4a2bf212057b..2abbc49914e6 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1506,7 +1506,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) @@ -1552,7 +1555,10 @@ static int convert_context(u32 key, struct user_datum *usrdatum; char *s; u32 len; - int rc; + int rc = 0; + + if (key <= SECINITSID_NUM) + goto out; args = p; @@ -1712,9 +1718,11 @@ int security_load_policy(void *data, size_t len) if (policydb_read(&newpolicydb, fp)) return -EINVAL; - if (sidtab_init(&newsidtab)) { + 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, -- cgit v1.2.2 From 0719aaf5ead7555b7b7a4a080ebf2826a871384e Mon Sep 17 00:00:00 2001 From: Guido Trentalancia Date: Wed, 3 Feb 2010 16:40:20 +0100 Subject: selinux: allow MLS->non-MLS and vice versa upon policy reload Allow runtime switching between different policy types (e.g. from a MLS/MCS policy to a non-MLS/non-MCS policy or viceversa). Signed-off-by: Guido Trentalancia Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/ss/context.h | 12 -------- security/selinux/ss/mls.c | 26 ++++++++--------- security/selinux/ss/mls.h | 2 ++ security/selinux/ss/mls_types.h | 7 +---- security/selinux/ss/policydb.c | 24 +++------------- security/selinux/ss/policydb.h | 4 +++ security/selinux/ss/services.c | 62 +++++++++++++++++++++++++++++++++++++---- 7 files changed, 80 insertions(+), 57 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index d9dd7a2f6a8a..45e8fb0515f8 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -82,9 +76,6 @@ out: static inline int mls_context_cmp(struct context *c1, struct context *c2) { - if (!selinux_mls_enabled) - return 1; - return ((c1->range.level[0].sens == c2->range.level[0].sens) && ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && (c1->range.level[1].sens == c2->range.level[1].sens) && @@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) static inline void mls_context_destroy(struct context *c) { - if (!selinux_mls_enabled) - return; - ebitmap_destroy(&c->range.level[0].cat); ebitmap_destroy(&c->range.level[1].cat); mls_context_init(c); diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 443ae7370144..372b773f8210 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context) struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; len = 1; /* for the beginning ":" */ @@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; scontextp = *scontext; @@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) { struct user_datum *usrdatum; - if (!selinux_mls_enabled) + if (!p->mls_enabled) return 1; if (!mls_range_isvalid(p, &c->range)) @@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol, struct cat_datum *catdatum, *rngdatum; int l, rc = -EINVAL; - if (!selinux_mls_enabled) { + if (!pol->mls_enabled) { if (def_sid != SECSID_NULL && oldc) *scontext += strlen(*scontext)+1; return 0; @@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) char *tmpstr, *freestr; int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return -EINVAL; /* we need freestr because mls_context_to_sid will change @@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) /* * Copies the MLS range `range' into `context'. */ -static inline int mls_range_set(struct context *context, +int mls_range_set(struct context *context, struct mls_range *range) { int l, rc = 0; @@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct context *usercon) { - if (selinux_mls_enabled) { + if (policydb.mls_enabled) { struct mls_level *fromcon_sen = &(fromcon->range.level[0]); struct mls_level *fromcon_clr = &(fromcon->range.level[1]); struct mls_level *user_low = &(user->range.level[0]); @@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, struct ebitmap_node *node; int l, i; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; for (l = 0; l < 2; l++) { @@ -516,7 +516,7 @@ int mls_compute_sid(struct context *scontext, struct range_trans rtr; struct mls_range *r; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; switch (specified) { @@ -559,7 +559,7 @@ int mls_compute_sid(struct context *scontext, void mls_export_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; secattr->attr.mls.lvl = context->range.level[0].sens - 1; @@ -579,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; context->range.level[0].sens = secattr->attr.mls.lvl + 1; @@ -601,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_export(&context->range.level[0].cat, @@ -629,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_import(&context->range.level[0].cat, diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 1276715aaa8b..cd9152632e54 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p, int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); +int mls_range_set(struct context *context, struct mls_range *range); + int mls_convert_context(struct policydb *oldp, struct policydb *newp, struct context *context); diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index b6e943a21061..03bed52a8052 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -15,6 +15,7 @@ #define _SS_MLS_TYPES_H_ #include "security.h" +#include "ebitmap.h" struct mls_level { u32 sens; /* sensitivity */ @@ -27,18 +28,12 @@ struct mls_range { static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); } static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat)); } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 5b92c0219207..23c6e53c102c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { }; #endif -int selinux_mls_enabled; - static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, @@ -455,7 +453,7 @@ static int policydb_index_others(struct policydb *p) printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - if (selinux_mls_enabled) + if (p->mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); @@ -1717,14 +1715,12 @@ int policydb_read(struct policydb *p, void *fp) int i, j, rc; __le32 buf[4]; u32 nodebuf[8]; - u32 len, len2, config, nprim, nel, nel2; + u32 len, len2, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; struct range_trans *rt; struct mls_range *r; - config = 0; - rc = policydb_init(p); if (rc) goto out; @@ -1772,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) kfree(policydb_str); policydb_str = NULL; - /* Read the version, config, and table sizes. */ + /* Read the version and table sizes. */ rc = next_entry(buf, fp, sizeof(u32)*4); if (rc < 0) goto bad; @@ -1787,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) } if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { - if (ss_initialized && !selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between non-MLS" - " and MLS policies\n"); - goto bad; - } - selinux_mls_enabled = 1; - config |= POLICYDB_CONFIG_MLS; + p->mls_enabled = 1; if (p->policyvers < POLICYDB_VERSION_MLS) { printk(KERN_ERR "SELinux: security policydb version %d " @@ -1801,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers); goto bad; } - } else { - if (ss_initialized && selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between MLS and" - " non-MLS policies\n"); - goto bad; - } } p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 193736b64de8..26d9adf8542b 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -27,6 +27,8 @@ #include "symtab.h" #include "avtab.h" #include "sidtab.h" +#include "ebitmap.h" +#include "mls_types.h" #include "context.h" #include "constraint.h" @@ -185,6 +187,8 @@ struct genfs { /* The policy database */ struct policydb { + int mls_enabled; + /* symbol tables */ struct symtab symtab[SYM_NUM]; #define p_commons symtab[SYM_COMMONS] diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2abbc49914e6..4e976f58b980 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 + * + * 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. @@ -232,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 @@ -1550,6 +1558,8 @@ 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; @@ -1620,9 +1630,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)) { @@ -1718,6 +1758,12 @@ int security_load_policy(void *data, size_t len) if (policydb_read(&newpolicydb, fp)) return -EINVAL; + /* 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"); @@ -1749,8 +1795,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); @@ -2346,7 +2396,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; } @@ -2447,7 +2497,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; } -- cgit v1.2.2 From 2da5d31bc72d0a36dc16af7f5d5baa4f86df9c76 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 16 Feb 2010 17:29:06 +1100 Subject: security: fix a couple of sparse warnings Fix a couple of sparse warnings for callers of context_struct_to_string, which takes a *u32, not an *int. These cases are harmless as the values are not used. Signed-off-by: James Morris Acked-by: KaiGai Kohei --- security/selinux/ss/services.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4e976f58b980..0e5c3a422a8e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -455,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) @@ -807,7 +808,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) && -- cgit v1.2.2 From 2ae3ba39389b51d8502123de0a59374bec899c4d Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Wed, 17 Feb 2010 08:49:41 +0900 Subject: selinux: libsepol: remove dead code in check_avtab_hierarchy_callback() This patch revert the commit of 7d52a155e38d5a165759dbbee656455861bf7801 which removed a part of type_attribute_bounds_av as a dead code. However, at that time, we didn't find out the target side boundary allows to handle some of pseudo /proc//* entries with its process's security context well. Signed-off-by: KaiGai Kohei Acked-by: Stephen Smalley -- security/selinux/ss/services.c | 43 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 39 insertions(+), 4 deletions(-) Signed-off-by: James Morris --- security/selinux/ss/services.c | 43 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'security/selinux/ss') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0e5c3a422a8e..cf27b3ee1a95 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -525,14 +525,16 @@ static void type_attribute_bounds_av(struct context *scontext, u16 tclass, struct av_decision *avd) { + struct context lo_scontext; + struct context lo_tcontext; + struct av_decision lo_avd; struct type_datum *source = policydb.type_val_to_struct[scontext->type - 1]; + struct type_datum *target + = policydb.type_val_to_struct[tcontext->type - 1]; + u32 masked = 0; if (source->bounds) { - struct context lo_scontext; - struct av_decision lo_avd; - u32 masked; - memset(&lo_avd, 0, sizeof(lo_avd)); memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); @@ -545,7 +547,40 @@ static void type_attribute_bounds_av(struct context *scontext, if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; + } + + if (target->bounds) { + memset(&lo_avd, 0, sizeof(lo_avd)); + + memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); + lo_tcontext.type = target->bounds; + + context_struct_compute_av(scontext, + &lo_tcontext, + tclass, + &lo_avd); + if ((lo_avd.allowed & avd->allowed) == avd->allowed) + return; /* no masked permission */ + masked = ~lo_avd.allowed & avd->allowed; + } + + if (source->bounds && target->bounds) { + memset(&lo_avd, 0, sizeof(lo_avd)); + /* + * lo_scontext and lo_tcontext are already + * set up. + */ + + context_struct_compute_av(&lo_scontext, + &lo_tcontext, + tclass, + &lo_avd); + if ((lo_avd.allowed & avd->allowed) == avd->allowed) + return; /* no masked permission */ + masked = ~lo_avd.allowed & avd->allowed; + } + if (masked) { /* mask violated permissions */ avd->allowed &= ~masked; -- cgit v1.2.2