From: Darrel Goeddel This patch replaces the original experimental Multi-Level Security (MLS) implementation in SELinux with an enhanced MLS implementation contributed by Trusted Computer Solutions (TCS). The enhanced MLS implementation replaces the hardcoded MLS logic with a flexible constraint-based system and replaces the compile-time option for MLS support with a policy load-time enable based on whether MLS support was enabled in the policy when it was built. The latter change allows a single kernel and policy toolchain to support both MLS and non-MLS policies. Compatibility is still provided as usual for existing policies. Signed-off-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton --- 25-akpm/security/selinux/Kconfig | 9 25-akpm/security/selinux/hooks.c | 7 25-akpm/security/selinux/include/security.h | 13 25-akpm/security/selinux/ss/Makefile | 4 25-akpm/security/selinux/ss/constraint.h | 7 25-akpm/security/selinux/ss/context.h | 30 - 25-akpm/security/selinux/ss/mls.c | 726 +++++++++------------------- 25-akpm/security/selinux/ss/mls.h | 79 --- 25-akpm/security/selinux/ss/mls_types.h | 76 +- 25-akpm/security/selinux/ss/policydb.c | 575 +++++++++++++++++----- 25-akpm/security/selinux/ss/policydb.h | 58 -- 25-akpm/security/selinux/ss/services.c | 266 +++++++--- 12 files changed, 1013 insertions(+), 837 deletions(-) diff -puN security/selinux/hooks.c~selinux-enhanced-mls-support security/selinux/hooks.c --- 25/security/selinux/hooks.c~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/hooks.c Mon Mar 7 15:19:07 2005 @@ -10,6 +10,8 @@ * * Copyright (C) 2001,2002 Networks Associates Technology, Inc. * Copyright (C) 2003 Red Hat, Inc., James Morris + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -2204,6 +2206,11 @@ static int selinux_inode_setxattr(struct if (rc) return rc; + rc = security_validate_transition(isec->sid, newsid, tsec->sid, + isec->sclass); + if (rc) + return rc; + return avc_has_perm(newsid, sbsec->sid, SECCLASS_FILESYSTEM, diff -puN security/selinux/include/security.h~selinux-enhanced-mls-support security/selinux/include/security.h --- 25/security/selinux/include/security.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/include/security.h Mon Mar 7 15:19:07 2005 @@ -21,10 +21,12 @@ #define POLICYDB_VERSION_BOOL 16 #define POLICYDB_VERSION_IPV6 17 #define POLICYDB_VERSION_NLCLASS 18 +#define POLICYDB_VERSION_VALIDATETRANS 19 +#define POLICYDB_VERSION_MLS 19 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_NLCLASS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_MLS #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM extern int selinux_enabled; @@ -32,11 +34,7 @@ extern int selinux_enabled; #define selinux_enabled 1 #endif -#ifdef CONFIG_SECURITY_SELINUX_MLS -#define selinux_mls_enabled 1 -#else -#define selinux_mls_enabled 0 -#endif +extern int selinux_mls_enabled; int security_load_policy(void * data, size_t len); @@ -79,6 +77,9 @@ int security_netif_sid(char *name, u32 * int security_node_sid(u16 domain, void *addr, u32 addrlen, u32 *out_sid); +int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, + u16 tclass); + #define SECURITY_FS_USE_XATTR 1 /* use xattr */ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ diff -puN security/selinux/Kconfig~selinux-enhanced-mls-support security/selinux/Kconfig --- 25/security/selinux/Kconfig~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/Kconfig Mon Mar 7 15:19:07 2005 @@ -76,12 +76,3 @@ config SECURITY_SELINUX_AVC_STATS /selinux/avc/cache_stats, which may be monitored via tools such as avcstat. -config SECURITY_SELINUX_MLS - bool "NSA SELinux MLS policy (EXPERIMENTAL)" - depends on SECURITY_SELINUX && EXPERIMENTAL - default n - help - This enables the NSA SELinux Multi-Level Security (MLS) policy in - addition to the default RBAC/TE policy. This policy is - experimental and has not been configured for use. Unless you - specifically want to experiment with MLS, say N. diff -puN security/selinux/ss/constraint.h~selinux-enhanced-mls-support security/selinux/ss/constraint.h --- 25/security/selinux/ss/constraint.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/constraint.h Mon Mar 7 15:19:07 2005 @@ -31,6 +31,13 @@ struct constraint_expr { #define CEXPR_ROLE 2 /* role */ #define CEXPR_TYPE 4 /* type */ #define CEXPR_TARGET 8 /* target if set, source otherwise */ +#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */ +#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */ +#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */ +#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */ +#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */ +#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */ +#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */ u32 attr; /* attribute */ #define CEXPR_EQ 1 /* == or eq */ diff -puN security/selinux/ss/context.h~selinux-enhanced-mls-support security/selinux/ss/context.h --- 25/security/selinux/ss/context.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/context.h Mon Mar 7 15:19:07 2005 @@ -17,6 +17,7 @@ #include "ebitmap.h" #include "mls_types.h" +#include "security.h" /* * A security context consists of an authenticated user @@ -26,13 +27,9 @@ struct context { u32 user; u32 role; u32 type; -#ifdef CONFIG_SECURITY_SELINUX_MLS struct mls_range range; -#endif }; -#ifdef CONFIG_SECURITY_SELINUX_MLS - static inline void mls_context_init(struct context *c) { memset(&c->range, 0, sizeof(c->range)); @@ -42,6 +39,9 @@ static inline int mls_context_cpy(struct { 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) @@ -57,6 +57,9 @@ 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) && @@ -65,27 +68,14 @@ static inline int mls_context_cmp(struct 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); } -#else - -static inline void mls_context_init(struct context *c) -{ } - -static inline int mls_context_cpy(struct context *dst, struct context *src) -{ return 0; } - -static inline int mls_context_cmp(struct context *c1, struct context *c2) -{ return 1; } - -static inline void mls_context_destroy(struct context *c) -{ } - -#endif - static inline void context_init(struct context *c) { memset(c, 0, sizeof(*c)); diff -puN security/selinux/ss/Makefile~selinux-enhanced-mls-support security/selinux/ss/Makefile --- 25/security/selinux/ss/Makefile~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/Makefile Mon Mar 7 15:19:07 2005 @@ -5,7 +5,5 @@ EXTRA_CFLAGS += -Isecurity/selinux/include obj-y := ss.o -ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o - -ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o +ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o diff -puN security/selinux/ss/mls.c~selinux-enhanced-mls-support security/selinux/ss/mls.c --- 25/security/selinux/ss/mls.c~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/mls.c Mon Mar 7 15:19:07 2005 @@ -3,6 +3,14 @@ * * Author : Stephen Smalley, */ +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + */ + #include #include #include @@ -12,79 +20,47 @@ #include "services.h" /* - * Remove any permissions from `allowed' that are - * denied by the MLS policy. - */ -void mls_compute_av(struct context *scontext, - struct context *tcontext, - struct class_datum *tclass, - u32 *allowed) -{ - unsigned int rel[2]; - int l; - - for (l = 0; l < 2; l++) - rel[l] = mls_level_relation(scontext->range.level[l], - tcontext->range.level[l]); - - if (rel[1] != MLS_RELATION_EQ) { - if (rel[1] != MLS_RELATION_DOM && - !ebitmap_get_bit(&policydb.trustedreaders, scontext->type - 1) && - !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) { - /* read(s,t) = (s.high >= t.high) = False */ - *allowed = (*allowed) & ~(tclass->mlsperms.read); - } - if (rel[1] != MLS_RELATION_DOMBY && - !ebitmap_get_bit(&policydb.trustedreaders, tcontext->type - 1) && - !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) { - /* readby(s,t) = read(t,s) = False */ - *allowed = (*allowed) & ~(tclass->mlsperms.readby); - } - } - if (((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) || - ((!mls_level_eq(tcontext->range.level[0], - tcontext->range.level[1])) && - (rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ))) && - !ebitmap_get_bit(&policydb.trustedwriters, scontext->type - 1) && - !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) { - /* - * write(s,t) = ((s.low <= t.low = t.high) or (s.low - * <= t.low <= t.high <= s.high)) = False - */ - *allowed = (*allowed) & ~(tclass->mlsperms.write); - } - - if (((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) || - ((!mls_level_eq(scontext->range.level[0], - scontext->range.level[1])) && - (rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ))) && - !ebitmap_get_bit(&policydb.trustedwriters, tcontext->type - 1) && - !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) { - /* writeby(s,t) = write(t,s) = False */ - *allowed = (*allowed) & ~(tclass->mlsperms.writeby); - } -} - -/* * Return the length in bytes for the MLS fields of the * security context string representation of `context'. */ int mls_compute_context_len(struct context * context) { - int i, l, len; + int i, l, len, range; + if (!selinux_mls_enabled) + return 0; - len = 0; + len = 1; /* for the beginning ":" */ for (l = 0; l < 2; l++) { - len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1; + range = 0; + len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); - for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) - if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) - len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; + for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) { + if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) { + if (range) { + range++; + continue; + } - if (mls_level_relation(context->range.level[0], context->range.level[1]) - == MLS_RELATION_EQ) - break; + len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; + range++; + } else { + if (range > 1) + len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1; + range = 0; + } + } + /* Handle case where last category is the end of range */ + if (range > 1) + len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1; + + if (l == 0) { + if (mls_level_eq(&context->range.level[0], + &context->range.level[1])) + break; + else + len++; + } } return len; @@ -95,40 +71,81 @@ int mls_compute_context_len(struct conte * the MLS fields of `context' into the string `*scontext'. * Update `*scontext' to point to the end of the MLS fields. */ -int mls_sid_to_context(struct context *context, - char **scontext) +void mls_sid_to_context(struct context *context, + char **scontext) { char *scontextp; - int i, l; + int i, l, range, wrote_sep; + + if (!selinux_mls_enabled) + return; scontextp = *scontext; + *scontextp = ':'; + scontextp++; + for (l = 0; l < 2; l++) { + range = 0; + wrote_sep = 0; strcpy(scontextp, policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); - *scontextp = ':'; - scontextp++; - for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) + + /* categories */ + for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) { if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) { + if (range) { + range++; + continue; + } + + if (!wrote_sep) { + *scontextp++ = ':'; + wrote_sep = 1; + } else + *scontextp++ = ','; strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); - *scontextp = ','; - scontextp++; + range++; + } else { + if (range > 1) { + if (range > 2) + *scontextp++ = '.'; + else + *scontextp++ = ','; + + strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]); + scontextp += strlen(policydb.p_cat_val_to_name[i - 2]); + } + range = 0; } - if (mls_level_relation(context->range.level[0], context->range.level[1]) - != MLS_RELATION_EQ) { - scontextp--; - sprintf(scontextp, "-"); - scontextp++; + } - } else { - break; + /* Handle case where last category is the end of range */ + if (range > 1) { + if (range > 2) + *scontextp++ = '.'; + else + *scontextp++ = ','; + + strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]); + scontextp += strlen(policydb.p_cat_val_to_name[i - 2]); + } + + if (l == 0) { + if (mls_level_eq(&context->range.level[0], + &context->range.level[1])) + break; + else { + *scontextp = '-'; + scontextp++; + } } } *scontext = scontextp; - return 0; + return; } /* @@ -137,20 +154,19 @@ int mls_sid_to_context(struct context *c */ int mls_context_isvalid(struct policydb *p, struct context *c) { - unsigned int relation; struct level_datum *levdatum; struct user_datum *usrdatum; - struct mls_range_list *rnode; int i, l; + if (!selinux_mls_enabled) + return 1; + /* * MLS range validity checks: high must dominate low, low level must * be valid (category set <-> sensitivity check), and high level must * be valid (category set <-> sensitivity check) */ - relation = mls_level_relation(c->range.level[1], - c->range.level[0]); - if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ))) + if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) /* High does not dominate low. */ return 0; @@ -185,18 +201,12 @@ int mls_context_isvalid(struct policydb if (!c->user || c->user > p->p_users.nprim) return 0; usrdatum = p->user_val_to_struct[c->user - 1]; - for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) { - if (mls_range_contains(rnode->range, c->range)) - break; - } - if (!rnode) - /* user may not be associated with range */ - return 0; + if (!mls_range_contains(usrdatum->range, c->range)) + return 0; /* user may not be associated with range */ return 1; } - /* * Set the MLS fields in the security context structure * `context' based on the string representation in @@ -213,23 +223,17 @@ int mls_context_to_sid(char oldc, { char delim; - char *scontextp, *p; + char *scontextp, *p, *rngptr; struct level_datum *levdatum; - struct cat_datum *catdatum; + struct cat_datum *catdatum, *rngdatum; int l, rc = -EINVAL; - if (!oldc) { - /* No MLS component to the security context. Try - to use a default 'unclassified' value. */ - levdatum = hashtab_search(policydb.p_levels.table, - "unclassified"); - if (!levdatum) - goto out; - context->range.level[0].sens = levdatum->level->sens; - context->range.level[1].sens = context->range.level[0].sens; - rc = 0; + if (!selinux_mls_enabled) + return 0; + + /* No MLS component to the security context. */ + if (!oldc) goto out; - } /* Extract low sensitivity. */ scontextp = p = *scontext; @@ -242,13 +246,15 @@ int mls_context_to_sid(char oldc, for (l = 0; l < 2; l++) { levdatum = hashtab_search(policydb.p_levels.table, scontextp); - if (!levdatum) + if (!levdatum) { + rc = -EINVAL; goto out; + } context->range.level[l].sens = levdatum->level->sens; if (delim == ':') { - /* Extract low category set. */ + /* Extract category set. */ while (1) { scontextp = p; while (*p && *p != ',' && *p != '-') @@ -257,15 +263,46 @@ int mls_context_to_sid(char oldc, if (delim != 0) *p++ = 0; + /* Separate into range if exists */ + if ((rngptr = strchr(scontextp, '.')) != NULL) { + /* Remove '.' */ + *rngptr++ = 0; + } + catdatum = hashtab_search(policydb.p_cats.table, scontextp); - if (!catdatum) + if (!catdatum) { + rc = -EINVAL; goto out; + } rc = ebitmap_set_bit(&context->range.level[l].cat, catdatum->value - 1, 1); if (rc) goto out; + + /* If range, set all categories in range */ + if (rngptr) { + int i; + + rngdatum = hashtab_search(policydb.p_cats.table, rngptr); + if (!rngdatum) { + rc = -EINVAL; + goto out; + } + + if (catdatum->value >= rngdatum->value) { + rc = -EINVAL; + goto out; + } + + for (i = catdatum->value; i < rngdatum->value; i++) { + rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); + if (rc) + goto out; + } + } + if (delim != ',') break; } @@ -306,7 +343,6 @@ static inline int mls_copy_context(struc /* Copy the MLS range from the source context */ for (l = 0; l < 2; l++) { - dst->range.level[l].sens = src->range.level[l].sens; rc = ebitmap_cpy(&dst->range.level[l].cat, &src->range.level[l].cat); @@ -318,6 +354,84 @@ static inline int mls_copy_context(struc } /* + * Copies the effective MLS range from `src' into `dst'. + */ +static inline int mls_scopy_context(struct context *dst, + struct context *src) +{ + int l, rc = 0; + + /* Copy the MLS range from the source context */ + for (l = 0; l < 2; l++) { + dst->range.level[l].sens = src->range.level[0].sens; + rc = ebitmap_cpy(&dst->range.level[l].cat, + &src->range.level[0].cat); + if (rc) + break; + } + + return rc; +} + +/* + * Copies the MLS range `range' into `context'. + */ +static inline int mls_range_set(struct context *context, + struct mls_range *range) +{ + int l, rc = 0; + + /* Copy the MLS range into the context */ + for (l = 0; l < 2; l++) { + context->range.level[l].sens = range->level[l].sens; + rc = ebitmap_cpy(&context->range.level[l].cat, + &range->level[l].cat); + if (rc) + break; + } + + return rc; +} + +int mls_setup_user_range(struct context *fromcon, struct user_datum *user, + struct context *usercon) +{ + if (selinux_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]); + struct mls_level *user_clr = &(user->range.level[1]); + struct mls_level *user_def = &(user->dfltlevel); + struct mls_level *usercon_sen = &(usercon->range.level[0]); + struct mls_level *usercon_clr = &(usercon->range.level[1]); + + /* Honor the user's default level if we can */ + if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { + *usercon_sen = *user_def; + } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { + *usercon_sen = *fromcon_sen; + } else if (mls_level_between(fromcon_clr, user_low, user_def)) { + *usercon_sen = *user_low; + } else + return -EINVAL; + + /* Lower the clearance of available contexts + if the clearance of "fromcon" is lower than + that of the user's default clearance (but + only if the "fromcon" clearance dominates + the user's computed sensitivity level) */ + if (mls_level_dom(user_clr, fromcon_clr)) { + *usercon_clr = *fromcon_clr; + } else if (mls_level_dom(fromcon_clr, user_clr)) { + *usercon_clr = *user_clr; + } else + return -EINVAL; + } + + return 0; +} + +/* * Convert the MLS fields in the security context * structure `c' from the values specified in the * policy `oldp' to the values specified in the policy `newp'. @@ -331,6 +445,9 @@ int mls_convert_context(struct policydb struct ebitmap bitmap; int l, i; + if (!selinux_mls_enabled) + return 0; + for (l = 0; l < 2; l++) { levdatum = hashtab_search(newp->p_levels.table, oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); @@ -366,17 +483,38 @@ int mls_compute_sid(struct context *scon u32 specified, struct context *newcontext) { + if (!selinux_mls_enabled) + return 0; + switch (specified) { case AVTAB_TRANSITION: + if (tclass == SECCLASS_PROCESS) { + struct range_trans *rangetr; + /* Look for a range transition rule. */ + for (rangetr = policydb.range_tr; rangetr; + rangetr = rangetr->next) { + if (rangetr->dom == scontext->type && + rangetr->type == tcontext->type) { + /* Set the range from the rule */ + return mls_range_set(newcontext, + &rangetr->range); + } + } + } + /* Fallthrough */ case AVTAB_CHANGE: - /* Use the process MLS attributes. */ - return mls_copy_context(newcontext, scontext); + if (tclass == SECCLASS_PROCESS) + /* Use the process MLS attributes. */ + return mls_copy_context(newcontext, scontext); + else + /* Use the process effective MLS attributes. */ + return mls_scopy_context(newcontext, scontext); case AVTAB_MEMBER: /* Only polyinstantiate the MLS attributes if the type is being polyinstantiated */ if (newcontext->type != tcontext->type) { - /* Use the process MLS attributes. */ - return mls_copy_context(newcontext, scontext); + /* Use the process effective MLS attributes. */ + return mls_scopy_context(newcontext, scontext); } else { /* Use the related object MLS attributes. */ return mls_copy_context(newcontext, tcontext); @@ -387,365 +525,3 @@ int mls_compute_sid(struct context *scon return -EINVAL; } -void mls_user_destroy(struct user_datum *usrdatum) -{ - struct mls_range_list *rnode, *rtmp; - rnode = usrdatum->ranges; - while (rnode) { - rtmp = rnode; - rnode = rnode->next; - ebitmap_destroy(&rtmp->range.level[0].cat); - ebitmap_destroy(&rtmp->range.level[1].cat); - kfree(rtmp); - } -} - -int mls_read_perm(struct perm_datum *perdatum, void *fp) -{ - u32 buf[1]; - int rc; - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) - return -EINVAL; - perdatum->base_perms = le32_to_cpu(buf[0]); - return 0; -} - -/* - * Read a MLS level structure from a policydb binary - * representation file. - */ -struct mls_level *mls_read_level(void *fp) -{ - struct mls_level *l; - u32 buf[1]; - int rc; - - l = kmalloc(sizeof(*l), GFP_ATOMIC); - if (!l) { - printk(KERN_ERR "security: mls: out of memory\n"); - return NULL; - } - memset(l, 0, sizeof(*l)); - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) { - printk(KERN_ERR "security: mls: truncated level\n"); - goto bad; - } - l->sens = cpu_to_le32(buf[0]); - - if (ebitmap_read(&l->cat, fp)) { - printk(KERN_ERR "security: mls: error reading level " - "categories\n"); - goto bad; - } - return l; - -bad: - kfree(l); - return NULL; -} - - -/* - * Read a MLS range structure from a policydb binary - * representation file. - */ -static int mls_read_range_helper(struct mls_range *r, void *fp) -{ - u32 buf[2], items; - int rc; - - rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) - goto out; - - items = le32_to_cpu(buf[0]); - if (items > ARRAY_SIZE(buf)) { - printk(KERN_ERR "security: mls: range overflow\n"); - rc = -EINVAL; - goto out; - } - rc = next_entry(buf, fp, sizeof(u32) * items); - if (rc < 0) { - printk(KERN_ERR "security: mls: truncated range\n"); - goto out; - } - r->level[0].sens = le32_to_cpu(buf[0]); - if (items > 1) { - r->level[1].sens = le32_to_cpu(buf[1]); - } else { - r->level[1].sens = r->level[0].sens; - } - - rc = ebitmap_read(&r->level[0].cat, fp); - if (rc) { - printk(KERN_ERR "security: mls: error reading low " - "categories\n"); - goto out; - } - if (items > 1) { - rc = ebitmap_read(&r->level[1].cat, fp); - if (rc) { - printk(KERN_ERR "security: mls: error reading high " - "categories\n"); - goto bad_high; - } - } else { - rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); - if (rc) { - printk(KERN_ERR "security: mls: out of memory\n"); - goto bad_high; - } - } - - rc = 0; -out: - return rc; -bad_high: - ebitmap_destroy(&r->level[0].cat); - goto out; -} - -int mls_read_range(struct context *c, void *fp) -{ - return mls_read_range_helper(&c->range, fp); -} - - -/* - * Read a MLS perms structure from a policydb binary - * representation file. - */ -int mls_read_class(struct class_datum *cladatum, void *fp) -{ - struct mls_perms *p = &cladatum->mlsperms; - u32 buf[4]; - int rc; - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) { - printk(KERN_ERR "security: mls: truncated mls permissions\n"); - return -EINVAL; - } - p->read = le32_to_cpu(buf[0]); - p->readby = le32_to_cpu(buf[1]); - p->write = le32_to_cpu(buf[2]); - p->writeby = le32_to_cpu(buf[3]); - return 0; -} - -int mls_read_user(struct user_datum *usrdatum, void *fp) -{ - struct mls_range_list *r, *l; - int rc; - u32 nel, i; - u32 buf[1]; - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) - goto out; - nel = le32_to_cpu(buf[0]); - l = NULL; - for (i = 0; i < nel; i++) { - r = kmalloc(sizeof(*r), GFP_ATOMIC); - if (!r) { - rc = -ENOMEM; - goto out; - } - memset(r, 0, sizeof(*r)); - - rc = mls_read_range_helper(&r->range, fp); - if (rc) { - kfree(r); - goto out; - } - - if (l) - l->next = r; - else - usrdatum->ranges = r; - l = r; - } -out: - return rc; -} - -int mls_read_nlevels(struct policydb *p, void *fp) -{ - u32 buf[1]; - int rc; - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) - return -EINVAL; - p->nlevels = le32_to_cpu(buf[0]); - return 0; -} - -int mls_read_trusted(struct policydb *p, void *fp) -{ - int rc = 0; - - rc = ebitmap_read(&p->trustedreaders, fp); - if (rc) - goto out; - rc = ebitmap_read(&p->trustedwriters, fp); - if (rc) - goto bad; - rc = ebitmap_read(&p->trustedobjects, fp); - if (rc) - goto bad2; -out: - return rc; -bad2: - ebitmap_destroy(&p->trustedwriters); -bad: - ebitmap_destroy(&p->trustedreaders); - goto out; -} - -int sens_index(void *key, void *datum, void *datap) -{ - struct policydb *p; - struct level_datum *levdatum; - - - levdatum = datum; - p = datap; - - if (!levdatum->isalias) - p->p_sens_val_to_name[levdatum->level->sens - 1] = key; - - return 0; -} - -int cat_index(void *key, void *datum, void *datap) -{ - struct policydb *p; - struct cat_datum *catdatum; - - - catdatum = datum; - p = datap; - - - if (!catdatum->isalias) - p->p_cat_val_to_name[catdatum->value - 1] = key; - - return 0; -} - -int sens_destroy(void *key, void *datum, void *p) -{ - struct level_datum *levdatum; - - kfree(key); - levdatum = datum; - if (!levdatum->isalias) { - ebitmap_destroy(&levdatum->level->cat); - kfree(levdatum->level); - } - kfree(datum); - return 0; -} - -int cat_destroy(void *key, void *datum, void *p) -{ - kfree(key); - kfree(datum); - return 0; -} - -int sens_read(struct policydb *p, struct hashtab *h, void *fp) -{ - char *key = NULL; - struct level_datum *levdatum; - int rc; - u32 buf[2], len; - - levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC); - if (!levdatum) { - rc = -ENOMEM; - goto out; - } - memset(levdatum, 0, sizeof(*levdatum)); - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) - goto bad; - - len = le32_to_cpu(buf[0]); - levdatum->isalias = le32_to_cpu(buf[1]); - - key = kmalloc(len + 1,GFP_ATOMIC); - if (!key) { - rc = -ENOMEM; - goto bad; - } - rc = next_entry(key, fp, len); - if (rc < 0) - goto bad; - key[len] = 0; - - levdatum->level = mls_read_level(fp); - if (!levdatum->level) { - rc = -EINVAL; - goto bad; - } - - rc = hashtab_insert(h, key, levdatum); - if (rc) - goto bad; -out: - return rc; -bad: - sens_destroy(key, levdatum, NULL); - goto out; -} - - -int cat_read(struct policydb *p, struct hashtab *h, void *fp) -{ - char *key = NULL; - struct cat_datum *catdatum; - int rc; - u32 buf[3], len; - - catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC); - if (!catdatum) { - rc = -ENOMEM; - goto out; - } - memset(catdatum, 0, sizeof(*catdatum)); - - rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) - goto bad; - - len = le32_to_cpu(buf[0]); - catdatum->value = le32_to_cpu(buf[1]); - catdatum->isalias = le32_to_cpu(buf[2]); - - key = kmalloc(len + 1,GFP_ATOMIC); - if (!key) { - rc = -ENOMEM; - goto bad; - } - rc = next_entry(key, fp, len); - if (rc < 0) - goto bad; - key[len] = 0; - - rc = hashtab_insert(h, key, catdatum); - if (rc) - goto bad; -out: - return rc; - -bad: - cat_destroy(key, catdatum, NULL); - goto out; -} diff -puN security/selinux/ss/mls.h~selinux-enhanced-mls-support security/selinux/ss/mls.h --- 25/security/selinux/ss/mls.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/mls.h Mon Mar 7 15:19:07 2005 @@ -3,21 +3,22 @@ * * Author : Stephen Smalley, */ +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + */ + #ifndef _SS_MLS_H_ #define _SS_MLS_H_ #include "context.h" #include "policydb.h" -#ifdef CONFIG_SECURITY_SELINUX_MLS - -void mls_compute_av(struct context *scontext, - struct context *tcontext, - struct class_datum *tclass, - u32 *allowed); - int mls_compute_context_len(struct context *context); -int mls_sid_to_context(struct context *context, char **scontext); +void mls_sid_to_context(struct context *context, char **scontext); int mls_context_isvalid(struct policydb *p, struct context *c); int mls_context_to_sid(char oldc, @@ -34,66 +35,8 @@ int mls_compute_sid(struct context *scon u32 specified, struct context *newcontext); -int sens_index(void *key, void *datum, void *datap); -int cat_index(void *key, void *datum, void *datap); -int sens_destroy(void *key, void *datum, void *p); -int cat_destroy(void *key, void *datum, void *p); -int sens_read(struct policydb *p, struct hashtab *h, void *fp); -int cat_read(struct policydb *p, struct hashtab *h, void *fp); - -#define mls_for_user_ranges(user, usercon) { \ -struct mls_range_list *__ranges; \ -for (__ranges = user->ranges; __ranges; __ranges = __ranges->next) { \ -usercon.range = __ranges->range; - -#define mls_end_user_ranges } } - -#define mls_symtab_names "levels", "categories", -#define mls_symtab_sizes 16, 16, -#define mls_index_f sens_index, cat_index, -#define mls_destroy_f sens_destroy, cat_destroy, -#define mls_read_f sens_read, cat_read, -#define mls_write_f sens_write, cat_write, -#define mls_policydb_index_others(p) printk(", %d levels", p->nlevels); - -#define mls_set_config(config) config |= POLICYDB_CONFIG_MLS - -void mls_user_destroy(struct user_datum *usrdatum); -int mls_read_range(struct context *c, void *fp); -int mls_read_perm(struct perm_datum *perdatum, void *fp); -int mls_read_class(struct class_datum *cladatum, void *fp); -int mls_read_user(struct user_datum *usrdatum, void *fp); -int mls_read_nlevels(struct policydb *p, void *fp); -int mls_read_trusted(struct policydb *p, void *fp); - -#else - -#define mls_compute_av(scontext, tcontext, tclass_datum, allowed) -#define mls_compute_context_len(context) 0 -#define mls_sid_to_context(context, scontextpp) -#define mls_context_isvalid(p, c) 1 -#define mls_context_to_sid(oldc, context_str, context) 0 -#define mls_convert_context(oldp, newp, c) 0 -#define mls_compute_sid(scontext, tcontext, tclass, specified, newcontextp) 0 -#define mls_for_user_ranges(user, usercon) -#define mls_end_user_ranges -#define mls_symtab_names -#define mls_symtab_sizes -#define mls_index_f -#define mls_destroy_f -#define mls_read_f -#define mls_write_f -#define mls_policydb_index_others(p) -#define mls_set_config(config) -#define mls_user_destroy(usrdatum) -#define mls_read_range(c, fp) 0 -#define mls_read_perm(p, fp) 0 -#define mls_read_class(c, fp) 0 -#define mls_read_user(u, fp) 0 -#define mls_read_nlevels(p, fp) 0 -#define mls_read_trusted(p, fp) 0 - -#endif +int mls_setup_user_range(struct context *fromcon, struct user_datum *user, + struct context *usercon); #endif /* _SS_MLS_H */ diff -puN security/selinux/ss/mls_types.h~selinux-enhanced-mls-support security/selinux/ss/mls_types.h --- 25/security/selinux/ss/mls_types.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/mls_types.h Mon Mar 7 15:19:07 2005 @@ -3,9 +3,19 @@ * * Author : Stephen Smalley, */ +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + */ + #ifndef _SS_MLS_TYPES_H_ #define _SS_MLS_TYPES_H_ +#include "security.h" + struct mls_level { u32 sens; /* sensitivity */ struct ebitmap cat; /* category set */ @@ -15,44 +25,32 @@ struct mls_range { struct mls_level level[2]; /* low == level[0], high == level[1] */ }; -struct mls_range_list { - struct mls_range range; - struct mls_range_list *next; -}; - -#define MLS_RELATION_DOM 1 /* source dominates */ -#define MLS_RELATION_DOMBY 2 /* target dominates */ -#define MLS_RELATION_EQ 4 /* source and target are equivalent */ -#define MLS_RELATION_INCOMP 8 /* source and target are incomparable */ - -#define mls_level_eq(l1,l2) \ -(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat)) - -#define mls_level_relation(l1,l2) ( \ -(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat)) ? \ - MLS_RELATION_EQ : \ -(((l1).sens >= (l2).sens) && ebitmap_contains(&(l1).cat, &(l2).cat)) ? \ - MLS_RELATION_DOM : \ -(((l2).sens >= (l1).sens) && ebitmap_contains(&(l2).cat, &(l1).cat)) ? \ - MLS_RELATION_DOMBY : \ - MLS_RELATION_INCOMP ) - -#define mls_range_contains(r1,r2) \ -((mls_level_relation((r1).level[0], (r2).level[0]) & \ - (MLS_RELATION_EQ | MLS_RELATION_DOMBY)) && \ - (mls_level_relation((r1).level[1], (r2).level[1]) & \ - (MLS_RELATION_EQ | MLS_RELATION_DOM))) - -/* - * Every access vector permission is mapped to a set of MLS base - * permissions, based on the flow properties of the corresponding - * operation. - */ -struct mls_perms { - u32 read; /* permissions that map to `read' */ - u32 readby; /* permissions that map to `readby' */ - u32 write; /* permissions that map to `write' */ - u32 writeby; /* permissions that map to `writeby' */ -}; +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)); +} + +#define mls_level_incomp(l1, l2) \ +(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1))) + +#define mls_level_between(l1, l2, l3) \ +(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1))) + +#define mls_range_contains(r1, r2) \ +(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \ + mls_level_dom(&(r1).level[1], &(r2).level[1])) #endif /* _SS_MLS_TYPES_H_ */ diff -puN security/selinux/ss/policydb.c~selinux-enhanced-mls-support security/selinux/ss/policydb.c --- 25/security/selinux/ss/policydb.c~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/policydb.c Mon Mar 7 15:19:07 2005 @@ -4,10 +4,16 @@ * Author : Stephen Smalley, */ -/* Updated: Frank Mayer and Karl MacMillan +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,19 +39,23 @@ static char *symtab_name[SYM_NUM] = { "roles", "types", "users", - mls_symtab_names - "bools" + "bools", + "levels", + "categories", }; #endif +int selinux_mls_enabled = 0; + static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, 16, 512, 128, - mls_symtab_sizes - 16 + 16, + 16, + 16, }; struct policydb_compat_info { @@ -58,21 +68,26 @@ struct policydb_compat_info { static struct policydb_compat_info policydb_compat[] = { { .version = POLICYDB_VERSION_BASE, - .sym_num = SYM_NUM - 1, + .sym_num = SYM_NUM - 3, .ocon_num = OCON_NUM - 1, }, { .version = POLICYDB_VERSION_BOOL, - .sym_num = SYM_NUM, + .sym_num = SYM_NUM - 2, .ocon_num = OCON_NUM - 1, }, { .version = POLICYDB_VERSION_IPV6, - .sym_num = SYM_NUM, + .sym_num = SYM_NUM - 2, .ocon_num = OCON_NUM, }, { .version = POLICYDB_VERSION_NLCLASS, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_MLS, .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, @@ -252,6 +267,41 @@ static int user_index(void *key, void *d return 0; } +static int sens_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct level_datum *levdatum; + + levdatum = datum; + p = datap; + + if (!levdatum->isalias) { + if (!levdatum->level->sens || + levdatum->level->sens > p->p_levels.nprim) + return -EINVAL; + p->p_sens_val_to_name[levdatum->level->sens - 1] = key; + } + + return 0; +} + +static int cat_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct cat_datum *catdatum; + + catdatum = datum; + p = datap; + + if (!catdatum->isalias) { + if (!catdatum->value || catdatum->value > p->p_cats.nprim) + return -EINVAL; + p->p_cat_val_to_name[catdatum->value - 1] = key; + } + + return 0; +} + static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = { common_index, @@ -259,8 +309,9 @@ static int (*index_f[SYM_NUM]) (void *ke role_index, type_index, user_index, - mls_index_f - cond_index_bool + cond_index_bool, + sens_index, + cat_index, }; /* @@ -333,7 +384,9 @@ int policydb_index_others(struct policyd printk(KERN_INFO "security: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - mls_policydb_index_others(p); + if (selinux_mls_enabled) + printk(", %d sens, %d cats", p->p_levels.nprim, + p->p_cats.nprim); printk("\n"); printk(KERN_INFO "security: %d classes, %d rules\n", @@ -429,6 +482,21 @@ static int class_destroy(void *key, void constraint = constraint->next; kfree(ctemp); } + + constraint = cladatum->validatetrans; + while (constraint) { + e = constraint->expr; + while (e) { + ebitmap_destroy(&e->names); + etmp = e; + e = e->next; + kfree(etmp); + } + ctemp = constraint; + constraint = constraint->next; + kfree(ctemp); + } + kfree(cladatum->comkey); kfree(datum); return 0; @@ -460,7 +528,28 @@ static int user_destroy(void *key, void kfree(key); usrdatum = datum; ebitmap_destroy(&usrdatum->roles); - mls_user_destroy(usrdatum); + ebitmap_destroy(&usrdatum->range.level[0].cat); + ebitmap_destroy(&usrdatum->range.level[1].cat); + ebitmap_destroy(&usrdatum->dfltlevel.cat); + kfree(datum); + return 0; +} + +static int sens_destroy(void *key, void *datum, void *p) +{ + struct level_datum *levdatum; + + kfree(key); + levdatum = datum; + ebitmap_destroy(&levdatum->level->cat); + kfree(levdatum->level); + kfree(datum); + return 0; +} + +static int cat_destroy(void *key, void *datum, void *p) +{ + kfree(key); kfree(datum); return 0; } @@ -472,8 +561,9 @@ static int (*destroy_f[SYM_NUM]) (void * role_destroy, type_destroy, user_destroy, - mls_destroy_f - cond_destroy_bool + cond_destroy_bool, + sens_destroy, + cat_destroy, }; void ocontext_destroy(struct ocontext *c, int i) @@ -624,6 +714,65 @@ int policydb_context_isvalid(struct poli } /* + * Read a MLS range structure from a policydb binary + * representation file. + */ +static int mls_read_range_helper(struct mls_range *r, void *fp) +{ + u32 buf[2], items; + int rc; + + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) + goto out; + + items = le32_to_cpu(buf[0]); + if (items > ARRAY_SIZE(buf)) { + printk(KERN_ERR "security: mls: range overflow\n"); + rc = -EINVAL; + goto out; + } + rc = next_entry(buf, fp, sizeof(u32) * items); + if (rc < 0) { + printk(KERN_ERR "security: mls: truncated range\n"); + goto out; + } + r->level[0].sens = le32_to_cpu(buf[0]); + if (items > 1) + r->level[1].sens = le32_to_cpu(buf[1]); + else + r->level[1].sens = r->level[0].sens; + + rc = ebitmap_read(&r->level[0].cat, fp); + if (rc) { + printk(KERN_ERR "security: mls: error reading low " + "categories\n"); + goto out; + } + if (items > 1) { + rc = ebitmap_read(&r->level[1].cat, fp); + if (rc) { + printk(KERN_ERR "security: mls: error reading high " + "categories\n"); + goto bad_high; + } + } else { + rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); + if (rc) { + printk(KERN_ERR "security: mls: out of memory\n"); + goto bad_high; + } + } + + rc = 0; +out: + return rc; +bad_high: + ebitmap_destroy(&r->level[0].cat); + goto out; +} + +/* * Read and validate a security context structure * from a policydb binary representation file. */ @@ -642,11 +791,13 @@ static int context_read_and_validate(str c->user = le32_to_cpu(buf[0]); c->role = le32_to_cpu(buf[1]); c->type = le32_to_cpu(buf[2]); - if (mls_read_range(c, fp)) { - printk(KERN_ERR "security: error reading MLS range of " - "context\n"); - rc = -EINVAL; - goto out; + if (p->policyvers >= POLICYDB_VERSION_MLS) { + if (mls_read_range_helper(&c->range, fp)) { + printk(KERN_ERR "security: error reading MLS range of " + "context\n"); + rc = -EINVAL; + goto out; + } } if (!policydb_context_isvalid(p, c)) { @@ -684,9 +835,6 @@ static int perm_read(struct policydb *p, len = le32_to_cpu(buf[0]); perdatum->value = le32_to_cpu(buf[1]); - rc = mls_read_perm(perdatum, fp); - if (rc) - goto bad; key = kmalloc(len + 1,GFP_KERNEL); if (!key) { @@ -761,14 +909,97 @@ bad: goto out; } +static int read_cons_helper(struct constraint_node **nodep, int ncons, + int allowxtarget, void *fp) +{ + struct constraint_node *c, *lc; + struct constraint_expr *e, *le; + u32 buf[3], nexpr; + int rc, i, j, depth; + + lc = NULL; + for (i = 0; i < ncons; i++) { + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + memset(c, 0, sizeof(*c)); + + if (lc) { + lc->next = c; + } else { + *nodep = c; + } + + rc = next_entry(buf, fp, (sizeof(u32) * 2)); + if (rc < 0) + return rc; + c->permissions = le32_to_cpu(buf[0]); + nexpr = le32_to_cpu(buf[1]); + le = NULL; + depth = -1; + for (j = 0; j < nexpr; j++) { + e = kmalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return -ENOMEM; + memset(e, 0, sizeof(*e)); + + if (le) { + le->next = e; + } else { + c->expr = e; + } + + rc = next_entry(buf, fp, (sizeof(u32) * 3)); + if (rc < 0) + return rc; + e->expr_type = le32_to_cpu(buf[0]); + e->attr = le32_to_cpu(buf[1]); + e->op = le32_to_cpu(buf[2]); + + switch (e->expr_type) { + case CEXPR_NOT: + if (depth < 0) + return -EINVAL; + break; + case CEXPR_AND: + case CEXPR_OR: + if (depth < 1) + return -EINVAL; + depth--; + break; + case CEXPR_ATTR: + if (depth == (CEXPR_MAXDEPTH - 1)) + return -EINVAL; + depth++; + break; + case CEXPR_NAMES: + if (!allowxtarget && (e->attr & CEXPR_XTARGET)) + return -EINVAL; + if (depth == (CEXPR_MAXDEPTH - 1)) + return -EINVAL; + depth++; + if (ebitmap_read(&e->names, fp)) + return -EINVAL; + break; + default: + return -EINVAL; + } + le = e; + } + if (depth != 0) + return -EINVAL; + lc = c; + } + + return 0; +} + static int class_read(struct policydb *p, struct hashtab *h, void *fp) { char *key = NULL; struct class_datum *cladatum; - struct constraint_node *c, *lc; - struct constraint_expr *e, *le; - u32 buf[6], len, len2, ncons, nexpr, nel; - int i, j, depth, rc; + u32 buf[6], len, len2, ncons, nel; + int i, rc; cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL); if (!cladatum) { @@ -829,87 +1060,21 @@ static int class_read(struct policydb *p goto bad; } - lc = NULL; - for (i = 0; i < ncons; i++) { - c = kmalloc(sizeof(*c), GFP_KERNEL); - if (!c) { - rc = -ENOMEM; - goto bad; - } - memset(c, 0, sizeof(*c)); - - if (lc) { - lc->next = c; - } else { - cladatum->constraints = c; - } + rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); + if (rc) + goto bad; - rc = next_entry(buf, fp, sizeof(u32)*2); + if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) { + /* grab the validatetrans rules */ + rc = next_entry(buf, fp, sizeof(u32)); if (rc < 0) goto bad; - c->permissions = le32_to_cpu(buf[0]); - nexpr = le32_to_cpu(buf[1]); - le = NULL; - depth = -1; - for (j = 0; j < nexpr; j++) { - e = kmalloc(sizeof(*e), GFP_KERNEL); - if (!e) { - rc = -ENOMEM; - goto bad; - } - memset(e, 0, sizeof(*e)); - - if (le) { - le->next = e; - } else { - c->expr = e; - } - - rc = next_entry(buf, fp, sizeof(u32)*3); - if (rc < 0) - goto bad; - e->expr_type = le32_to_cpu(buf[0]); - e->attr = le32_to_cpu(buf[1]); - e->op = le32_to_cpu(buf[2]); - - rc = -EINVAL; - switch (e->expr_type) { - case CEXPR_NOT: - if (depth < 0) - goto bad; - break; - case CEXPR_AND: - case CEXPR_OR: - if (depth < 1) - goto bad; - depth--; - break; - case CEXPR_ATTR: - if (depth == (CEXPR_MAXDEPTH-1)) - goto bad; - depth++; - break; - case CEXPR_NAMES: - if (depth == (CEXPR_MAXDEPTH-1)) - goto bad; - depth++; - if (ebitmap_read(&e->names, fp)) - goto bad; - break; - default: - goto bad; - } - le = e; - } - if (depth != 0) + ncons = le32_to_cpu(buf[0]); + rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); + if (rc) goto bad; - lc = c; } - rc = mls_read_class(cladatum, fp); - if (rc) - goto bad; - rc = hashtab_insert(h, key, cladatum); if (rc) goto bad; @@ -1024,6 +1189,36 @@ bad: goto out; } + +/* + * Read a MLS level structure from a policydb binary + * representation file. + */ +static int mls_read_level(struct mls_level *lp, void *fp) +{ + u32 buf[1]; + int rc; + + memset(lp, 0, sizeof(*lp)); + + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) { + printk(KERN_ERR "security: mls: truncated level\n"); + goto bad; + } + lp->sens = le32_to_cpu(buf[0]); + + if (ebitmap_read(&lp->cat, fp)) { + printk(KERN_ERR "security: mls: error reading level " + "categories\n"); + goto bad; + } + return 0; + +bad: + return -EINVAL; +} + static int user_read(struct policydb *p, struct hashtab *h, void *fp) { char *key = NULL; @@ -1031,7 +1226,6 @@ static int user_read(struct policydb *p, int rc; u32 buf[2], len; - usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL); if (!usrdatum) { rc = -ENOMEM; @@ -1060,9 +1254,14 @@ static int user_read(struct policydb *p, if (rc) goto bad; - rc = mls_read_user(usrdatum, fp); - if (rc) - goto bad; + if (p->policyvers >= POLICYDB_VERSION_MLS) { + rc = mls_read_range_helper(&usrdatum->range, fp); + if (rc) + goto bad; + rc = mls_read_level(&usrdatum->dfltlevel, fp); + if (rc) + goto bad; + } rc = hashtab_insert(h, key, usrdatum); if (rc) @@ -1074,6 +1273,100 @@ bad: goto out; } +static int sens_read(struct policydb *p, struct hashtab *h, void *fp) +{ + char *key = NULL; + struct level_datum *levdatum; + int rc; + u32 buf[2], len; + + levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC); + if (!levdatum) { + rc = -ENOMEM; + goto out; + } + memset(levdatum, 0, sizeof(*levdatum)); + + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) + goto bad; + + len = le32_to_cpu(buf[0]); + levdatum->isalias = le32_to_cpu(buf[1]); + + key = kmalloc(len + 1,GFP_ATOMIC); + if (!key) { + rc = -ENOMEM; + goto bad; + } + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; + key[len] = 0; + + levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); + if (!levdatum->level) { + rc = -ENOMEM; + goto bad; + } + if (mls_read_level(levdatum->level, fp)) { + rc = -EINVAL; + goto bad; + } + + rc = hashtab_insert(h, key, levdatum); + if (rc) + goto bad; +out: + return rc; +bad: + sens_destroy(key, levdatum, NULL); + goto out; +} + +static int cat_read(struct policydb *p, struct hashtab *h, void *fp) +{ + char *key = NULL; + struct cat_datum *catdatum; + int rc; + u32 buf[3], len; + + catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC); + if (!catdatum) { + rc = -ENOMEM; + goto out; + } + memset(catdatum, 0, sizeof(*catdatum)); + + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) + goto bad; + + len = le32_to_cpu(buf[0]); + catdatum->value = le32_to_cpu(buf[1]); + catdatum->isalias = le32_to_cpu(buf[2]); + + key = kmalloc(len + 1,GFP_ATOMIC); + if (!key) { + rc = -ENOMEM; + goto bad; + } + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; + key[len] = 0; + + rc = hashtab_insert(h, key, catdatum); + if (rc) + goto bad; +out: + return rc; + +bad: + cat_destroy(key, catdatum, NULL); + goto out; +} + static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) = { common_read, @@ -1081,12 +1374,12 @@ static int (*read_f[SYM_NUM]) (struct po role_read, type_read, user_read, - mls_read_f - cond_read_bool + cond_read_bool, + sens_read, + cat_read, }; -#define mls_config(x) \ - ((x) & POLICYDB_CONFIG_MLS) ? "mls" : "no_mls" +extern int ss_initialized; /* * Read the configuration data from a policy database binary @@ -1102,9 +1395,9 @@ int policydb_read(struct policydb *p, vo u32 buf[8], len, len2, config, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; + struct range_trans *rt, *lrt; config = 0; - mls_set_config(config); rc = policydb_init(p); if (rc) @@ -1172,14 +1465,27 @@ int policydb_read(struct policydb *p, vo goto bad; } - if (buf[1] != config) { - printk(KERN_ERR "security: policydb configuration (%s) does " - "not match my configuration (%s)\n", - mls_config(buf[1]), - mls_config(config)); - goto bad; - } + if ((buf[1] & POLICYDB_CONFIG_MLS)) { + if (ss_initialized && !selinux_mls_enabled) { + printk(KERN_ERR "Cannot switch between non-MLS and MLS " + "policies\n"); + goto bad; + } + selinux_mls_enabled = 1; + config |= POLICYDB_CONFIG_MLS; + if (p->policyvers < POLICYDB_VERSION_MLS) { + printk(KERN_ERR "security policydb version %d (MLS) " + "not backwards compatible\n", p->policyvers); + goto bad; + } + } else { + if (ss_initialized && selinux_mls_enabled) { + printk(KERN_ERR "Cannot switch between MLS and non-MLS " + "policies\n"); + goto bad; + } + } info = policydb_lookup_compat(p->policyvers); if (!info) { @@ -1195,10 +1501,6 @@ int policydb_read(struct policydb *p, vo goto bad; } - rc = mls_read_nlevels(p, fp); - if (rc) - goto bad; - for (i = 0; i < info->sym_num; i++) { rc = next_entry(buf, fp, sizeof(u32)*2); if (rc < 0) @@ -1499,9 +1801,34 @@ int policydb_read(struct policydb *p, vo } } - rc = mls_read_trusted(p, fp); - if (rc) - goto bad; + if (p->policyvers >= POLICYDB_VERSION_MLS) { + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) + goto bad; + nel = le32_to_cpu(buf[0]); + lrt = NULL; + for (i = 0; i < nel; i++) { + rt = kmalloc(sizeof(*rt), GFP_KERNEL); + if (!rt) { + rc = -ENOMEM; + goto bad; + } + memset(rt, 0, sizeof(*rt)); + if (lrt) + lrt->next = rt; + else + p->range_tr = rt; + rc = next_entry(buf, fp, (sizeof(u32) * 2)); + if (rc < 0) + goto bad; + rt->dom = le32_to_cpu(buf[0]); + rt->type = le32_to_cpu(buf[1]); + rc = mls_read_range_helper(&rt->range, fp); + if (rc) + goto bad; + lrt = rt; + } + } rc = 0; out: diff -puN security/selinux/ss/policydb.h~selinux-enhanced-mls-support security/selinux/ss/policydb.h --- 25/security/selinux/ss/policydb.h~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/policydb.h Mon Mar 7 15:19:07 2005 @@ -5,10 +5,16 @@ * Author : Stephen Smalley, */ -/* Updated: Frank Mayer and Karl MacMillan +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,13 +40,6 @@ /* Permission attributes */ struct perm_datum { u32 value; /* permission bit + 1 */ -#ifdef CONFIG_SECURITY_SELINUX_MLS -#define MLS_BASE_READ 1 /* MLS base permission `read' */ -#define MLS_BASE_WRITE 2 /* MLS base permission `write' */ -#define MLS_BASE_READBY 4 /* MLS base permission `readby' */ -#define MLS_BASE_WRITEBY 8 /* MLS base permission `writeby' */ - u32 base_perms; /* MLS base permission mask */ -#endif }; /* Attributes of a common prefix for access vectors */ @@ -56,9 +55,7 @@ struct class_datum { struct common_datum *comdatum; /* common datum */ struct symtab permissions; /* class-specific permission symbol table */ struct constraint_node *constraints; /* constraints on class permissions */ -#ifdef CONFIG_SECURITY_SELINUX_MLS - struct mls_perms mlsperms; /* MLS base permission masks */ -#endif + struct constraint_node *validatetrans; /* special transition rules */ }; /* Role attributes */ @@ -91,13 +88,11 @@ struct type_datum { struct user_datum { u32 value; /* internal user value */ struct ebitmap roles; /* set of authorized roles for user */ -#ifdef CONFIG_SECURITY_SELINUX_MLS - struct mls_range_list *ranges; /* list of authorized MLS ranges for user */ -#endif + struct mls_range range; /* MLS range (min - max) for user */ + struct mls_level dfltlevel; /* default login MLS level for user */ }; -#ifdef CONFIG_SECURITY_SELINUX_MLS /* Sensitivity attributes */ struct level_datum { struct mls_level *level; /* sensitivity and associated categories */ @@ -109,7 +104,13 @@ struct cat_datum { u32 value; /* internal category bit + 1 */ unsigned char isalias; /* is this category an alias for another? */ }; -#endif + +struct range_trans { + u32 dom; /* current process domain */ + u32 type; /* program executable type */ + struct mls_range range; /* new range */ + struct range_trans *next; +}; /* Boolean data type */ struct cond_bool_datum { @@ -164,15 +165,10 @@ struct genfs { #define SYM_ROLES 2 #define SYM_TYPES 3 #define SYM_USERS 4 -#ifdef CONFIG_SECURITY_SELINUX_MLS -#define SYM_LEVELS 5 -#define SYM_CATS 6 -#define SYM_BOOLS 7 -#define SYM_NUM 8 -#else #define SYM_BOOLS 5 -#define SYM_NUM 6 -#endif +#define SYM_LEVELS 6 +#define SYM_CATS 7 +#define SYM_NUM 8 /* object context array indices */ #define OCON_ISID 0 /* initial SIDs */ @@ -193,9 +189,9 @@ struct policydb { #define p_roles symtab[SYM_ROLES] #define p_types symtab[SYM_TYPES] #define p_users symtab[SYM_USERS] +#define p_bools symtab[SYM_BOOLS] #define p_levels symtab[SYM_LEVELS] #define p_cats symtab[SYM_CATS] -#define p_bools symtab[SYM_BOOLS] /* symbol names indexed by (value - 1) */ char **sym_val_to_name[SYM_NUM]; @@ -204,9 +200,9 @@ struct policydb { #define p_role_val_to_name sym_val_to_name[SYM_ROLES] #define p_type_val_to_name sym_val_to_name[SYM_TYPES] #define p_user_val_to_name sym_val_to_name[SYM_USERS] +#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS] #define p_sens_val_to_name sym_val_to_name[SYM_LEVELS] #define p_cat_val_to_name sym_val_to_name[SYM_CATS] -#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS] /* class, role, and user attributes indexed by (value - 1) */ struct class_datum **class_val_to_struct; @@ -238,14 +234,8 @@ struct policydb { fixed labeling behavior. */ struct genfs *genfs; -#ifdef CONFIG_SECURITY_SELINUX_MLS - /* number of legitimate MLS levels */ - u32 nlevels; - - struct ebitmap trustedreaders; - struct ebitmap trustedwriters; - struct ebitmap trustedobjects; -#endif + /* range transitions */ + struct range_trans *range_tr; unsigned int policyvers; }; diff -puN security/selinux/ss/services.c~selinux-enhanced-mls-support security/selinux/ss/services.c --- 25/security/selinux/ss/services.c~selinux-enhanced-mls-support Mon Mar 7 15:19:07 2005 +++ 25-akpm/security/selinux/ss/services.c Mon Mar 7 15:19:07 2005 @@ -4,17 +4,17 @@ * Authors : Stephen Smalley, * James Morris * - * Copyright (C) 2003 Red Hat, Inc., James Morris + * Updated: Trusted Computer Solutions, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. + * Support for enhanced MLS infrastructure. * * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC + * Copyright (C) 2003 Red Hat, Inc., James Morris * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. @@ -64,18 +64,30 @@ int ss_initialized = 0; */ static u32 latest_granting = 0; +/* Forward declarations. */ +int context_struct_to_string(struct context *context, char **scontext, + u32 *scontext_len); + /* * Return the boolean value of a constraint expression * when it is applied to the specified source and target * security contexts. + * + * xcontext is a special beast... It is used by the validatetrans rules + * only. For these rules, scontext is the context before the transition, + * tcontext is the context after the transition, and xcontext is the context + * of the process performing the transition. All other callers of + * constraint_expr_eval should pass in NULL for xcontext. */ -static int constraint_expr_eval(struct context *scontext, - struct context *tcontext, - struct constraint_expr *cexpr) +int constraint_expr_eval(struct context *scontext, + struct context *tcontext, + struct context *xcontext, + struct constraint_expr *cexpr) { u32 val1, val2; struct context *c; struct role_datum *r1, *r2; + struct mls_level *l1, *l2; struct constraint_expr *e; int s[CEXPR_MAXDEPTH]; int sp = -1; @@ -132,6 +144,52 @@ static int constraint_expr_eval(struct c break; } break; + case CEXPR_L1L2: + l1 = &(scontext->range.level[0]); + l2 = &(tcontext->range.level[0]); + goto mls_ops; + case CEXPR_L1H2: + l1 = &(scontext->range.level[0]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; + case CEXPR_H1L2: + l1 = &(scontext->range.level[1]); + l2 = &(tcontext->range.level[0]); + goto mls_ops; + case CEXPR_H1H2: + l1 = &(scontext->range.level[1]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; + case CEXPR_L1H1: + l1 = &(scontext->range.level[0]); + l2 = &(scontext->range.level[1]); + goto mls_ops; + case CEXPR_L2H2: + l1 = &(tcontext->range.level[0]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; +mls_ops: + switch (e->op) { + case CEXPR_EQ: + s[++sp] = mls_level_eq(l1, l2); + continue; + case CEXPR_NEQ: + s[++sp] = !mls_level_eq(l1, l2); + continue; + case CEXPR_DOM: + s[++sp] = mls_level_dom(l1, l2); + continue; + case CEXPR_DOMBY: + s[++sp] = mls_level_dom(l2, l1); + continue; + case CEXPR_INCOMP: + s[++sp] = mls_level_incomp(l2, l1); + continue; + default: + BUG(); + return 0; + } + break; default: BUG(); return 0; @@ -155,6 +213,13 @@ static int constraint_expr_eval(struct c c = scontext; if (e->attr & CEXPR_TARGET) c = tcontext; + else if (e->attr & CEXPR_XTARGET) { + c = xcontext; + if (!c) { + BUG(); + return 0; + } + } if (e->attr & CEXPR_USER) val1 = c->user; else if (e->attr & CEXPR_ROLE) @@ -252,17 +317,13 @@ static int context_struct_compute_av(str cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); /* - * Remove any permissions prohibited by the MLS policy. - */ - mls_compute_av(scontext, tcontext, tclass_datum, &avd->allowed); - - /* - * Remove any permissions prohibited by a constraint. + * Remove any permissions prohibited by a constraint (this includes + * the MLS policy). */ constraint = tclass_datum->constraints; while (constraint) { if ((constraint->permissions & (avd->allowed)) && - !constraint_expr_eval(scontext, tcontext, + !constraint_expr_eval(scontext, tcontext, NULL, constraint->expr)) { avd->allowed = (avd->allowed) & ~(constraint->permissions); } @@ -290,6 +351,108 @@ static int context_struct_compute_av(str return 0; } +static int security_validtrans_handle_fail(struct context *ocontext, + struct context *ncontext, + struct context *tcontext, + u16 tclass) +{ + char *o = NULL, *n = NULL, *t = NULL; + u32 olen, nlen, tlen; + + if (context_struct_to_string(ocontext, &o, &olen) < 0) + goto out; + if (context_struct_to_string(ncontext, &n, &nlen) < 0) + goto out; + if (context_struct_to_string(tcontext, &t, &tlen) < 0) + goto out; + audit_log(current->audit_context, + "security_validate_transition: denied for" + " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", + o, n, t, policydb.p_class_val_to_name[tclass-1]); +out: + kfree(o); + kfree(n); + kfree(t); + + if (!selinux_enforcing) + return 0; + return -EPERM; +} + +int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, + u16 tclass) +{ + struct context *ocontext; + struct context *ncontext; + struct context *tcontext; + struct class_datum *tclass_datum; + struct constraint_node *constraint; + int rc = 0; + + if (!ss_initialized) + return 0; + + POLICY_RDLOCK; + + /* + * Remap extended Netlink classes for old policy versions. + * Do this here rather than socket_type_to_security_class() + * in case a newer policy version is loaded, allowing sockets + * to remain in the correct class. + */ + if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) + if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && + tclass <= SECCLASS_NETLINK_DNRT_SOCKET) + tclass = SECCLASS_NETLINK_SOCKET; + + if (!tclass || tclass > policydb.p_classes.nprim) { + printk(KERN_ERR "security_validate_transition: " + "unrecognized class %d\n", tclass); + rc = -EINVAL; + goto out; + } + tclass_datum = policydb.class_val_to_struct[tclass - 1]; + + ocontext = sidtab_search(&sidtab, oldsid); + if (!ocontext) { + printk(KERN_ERR "security_validate_transition: " + " unrecognized SID %d\n", oldsid); + rc = -EINVAL; + goto out; + } + + ncontext = sidtab_search(&sidtab, newsid); + if (!ncontext) { + printk(KERN_ERR "security_validate_transition: " + " unrecognized SID %d\n", newsid); + rc = -EINVAL; + goto out; + } + + tcontext = sidtab_search(&sidtab, tasksid); + if (!tcontext) { + printk(KERN_ERR "security_validate_transition: " + " unrecognized SID %d\n", tasksid); + rc = -EINVAL; + goto out; + } + + constraint = tclass_datum->validatetrans; + while (constraint) { + if (!constraint_expr_eval(ocontext, ncontext, tcontext, + constraint->expr)) { + rc = security_validtrans_handle_fail(ocontext, ncontext, + tcontext, tclass); + goto out; + } + constraint = constraint->next; + } + +out: + POLICY_RDUNLOCK; + return rc; +} + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier @@ -366,7 +529,7 @@ int context_struct_to_string(struct cont *scontext_len += mls_compute_context_len(context); /* Allocate space for the context; caller must free this space. */ - scontextp = kmalloc(*scontext_len+1,GFP_ATOMIC); + scontextp = kmalloc(*scontext_len, GFP_ATOMIC); if (!scontextp) { return -ENOMEM; } @@ -375,17 +538,16 @@ int context_struct_to_string(struct cont /* * Copy the user name, role name and type name into the context. */ - sprintf(scontextp, "%s:%s:%s:", + sprintf(scontextp, "%s:%s:%s", policydb.p_user_val_to_name[context->user - 1], policydb.p_role_val_to_name[context->role - 1], policydb.p_type_val_to_name[context->type - 1]); scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + - 1 + strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; + 1 + strlen(policydb.p_type_val_to_name[context->type - 1]); mls_sid_to_context(context, &scontextp); - scontextp--; *scontextp = 0; return 0; @@ -715,23 +877,8 @@ static int security_compute_sid(u32 ssid } } } - - if (!type_change && !roletr) { - /* No change in process role or type. */ - *out_sid = ssid; - goto out_unlock; - - } break; default: - if (!type_change && - (newcontext.user == tcontext->user) && - mls_context_cmp(scontext, tcontext)) { - /* No change in object type, owner, - or MLS attributes. */ - *out_sid = tsid; - goto out_unlock; - } break; } @@ -1363,36 +1510,37 @@ int security_get_user_sids(u32 fromsid, if (!ebitmap_get_bit(&role->types, j)) continue; usercon.type = j+1; - mls_for_user_ranges(user,usercon) { - rc = context_struct_compute_av(fromcon, &usercon, - SECCLASS_PROCESS, - PROCESS__TRANSITION, - &avd); - if (rc || !(avd.allowed & PROCESS__TRANSITION)) - continue; - rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); - if (rc) { + + if (mls_setup_user_range(fromcon, user, &usercon)) + continue; + + rc = context_struct_compute_av(fromcon, &usercon, + SECCLASS_PROCESS, + PROCESS__TRANSITION, + &avd); + if (rc || !(avd.allowed & PROCESS__TRANSITION)) + continue; + rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); + if (rc) { + kfree(mysids); + goto out_unlock; + } + if (mynel < maxnel) { + mysids[mynel++] = sid; + } else { + maxnel += SIDS_NEL; + mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC); + if (!mysids2) { + rc = -ENOMEM; kfree(mysids); goto out_unlock; } - if (mynel < maxnel) { - mysids[mynel++] = sid; - } else { - maxnel += SIDS_NEL; - mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC); - if (!mysids2) { - rc = -ENOMEM; - kfree(mysids); - goto out_unlock; - } - memset(mysids2, 0, maxnel*sizeof(*mysids2)); - memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); - kfree(mysids); - mysids = mysids2; - mysids[mynel++] = sid; - } + memset(mysids2, 0, maxnel*sizeof(*mysids2)); + memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); + kfree(mysids); + mysids = mysids2; + mysids[mynel++] = sid; } - mls_end_user_ranges; } } _