X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=security%2Fselinux%2Fss%2Fmls.c;h=7bc5b6440f70ba1ab45a66d0a7b3152d394096af;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=5ef5bd5bcc1c45c9eff4ddce1e2d7b07c92b36d0;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 5ef5bd5bc..7bc5b6440 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -3,88 +3,66 @@ * * Author : Stephen Smalley, */ +/* + * Updated: Trusted Computer Solutions, Inc. + * + * Support for enhanced MLS infrastructure. + * + * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. + */ + #include #include #include #include +#include "sidtab.h" #include "mls.h" #include "policydb.h" #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; + struct ebitmap_node *node; + 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; - - 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; - - if (mls_level_relation(context->range.level[0], context->range.level[1]) - == MLS_RELATION_EQ) - break; + range = 0; + len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); + + ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { + if (ebitmap_node_get_bit(node, i)) { + if (range) { + range++; + continue; + } + + len += strlen(policydb.p_cat_val_to_name[i]) + 1; + range++; + } else { + if (range > 1) + len += strlen(policydb.p_cat_val_to_name[i - 1]) + 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 - 1]) + 1; + + if (l == 0) { + if (mls_level_eq(&context->range.level[0], + &context->range.level[1])) + break; + else + len++; + } } return len; @@ -95,40 +73,82 @@ int mls_compute_context_len(struct context * context) * 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; + struct ebitmap_node *node; + + 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++) - if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) { - strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); - scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); - *scontextp = ','; - scontextp++; + + /* categories */ + ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { + if (ebitmap_node_get_bit(node, i)) { + if (range) { + range++; + continue; + } + + if (!wrote_sep) { + *scontextp++ = ':'; + wrote_sep = 1; + } else + *scontextp++ = ','; + strcpy(scontextp, policydb.p_cat_val_to_name[i]); + scontextp += strlen(policydb.p_cat_val_to_name[i]); + range++; + } else { + if (range > 1) { + if (range > 2) + *scontextp++ = '.'; + else + *scontextp++ = ','; + + strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); + scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); + } + 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 - 1]); + scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); + } + + 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 +157,20 @@ int mls_sid_to_context(struct context *context, */ 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; + struct ebitmap_node *node; 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; @@ -162,11 +182,11 @@ int mls_context_isvalid(struct policydb *p, struct context *c) if (!levdatum) return 0; - for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) { - if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) { + ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { + if (ebitmap_node_get_bit(node, i)) { if (i > p->p_cats.nprim) return 0; - if (!ebitmap_get_bit(&levdatum->level->cat, i - 1)) + if (!ebitmap_get_bit(&levdatum->level->cat, i)) /* * Category may not be associated with * sensitivity in low level. @@ -185,17 +205,31 @@ int mls_context_isvalid(struct policydb *p, struct context *c) 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; } +/* + * Copies the MLS range from `src' into `dst'. + */ +static inline int mls_copy_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[l].sens; + rc = ebitmap_cpy(&dst->range.level[l].cat, + &src->range.level[l].cat); + if (rc) + break; + } + + return rc; +} /* * Set the MLS fields in the security context structure @@ -206,28 +240,49 @@ int mls_context_isvalid(struct policydb *p, struct context *c) * * This function modifies the string in place, inserting * NULL characters to terminate the MLS fields. + * + * If a def_sid is provided and no MLS field is present, + * copy the MLS field of the associated default context. + * Used for upgraded to MLS systems where objects may lack + * MLS fields. + * + * Policy read-lock must be held for sidtab lookup. + * */ int mls_context_to_sid(char oldc, char **scontext, - struct context *context) + struct context *context, + struct sidtab *s, + u32 def_sid) { 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 (!selinux_mls_enabled) { + if (def_sid != SECSID_NULL && oldc) + *scontext += strlen(*scontext)+1; + return 0; + } + + /* + * No MLS component to the security context, try and map to + * default if provided. + */ 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) + struct context *defcon; + + if (def_sid == SECSID_NULL) goto out; - context->range.level[0].sens = levdatum->level->sens; - context->range.level[1].sens = context->range.level[0].sens; - rc = 0; + + defcon = sidtab_search(s, def_sid); + if (!defcon) + goto out; + + rc = mls_copy_context(context, defcon); goto out; } @@ -242,13 +297,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 +314,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; } @@ -297,19 +385,66 @@ out: } /* - * Copies the MLS range from `src' into `dst'. + * Set the MLS fields in the security context structure + * `context' based on the string representation in + * the string `str'. This function will allocate temporary memory with the + * given constraints of gfp_mask. */ -static inline int mls_copy_context(struct context *dst, - struct context *src) +int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) +{ + char *tmpstr, *freestr; + int rc; + + if (!selinux_mls_enabled) + return -EINVAL; + + /* we need freestr because mls_context_to_sid will change + the value of tmpstr */ + tmpstr = freestr = kstrdup(str, gfp_mask); + if (!tmpstr) { + rc = -ENOMEM; + } else { + rc = mls_context_to_sid(':', &tmpstr, context, + NULL, SECSID_NULL); + kfree(freestr); + } + + return rc; +} + +/* + * 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[l].sens; + dst->range.level[l].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[l].cat, - &src->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; } @@ -317,6 +452,44 @@ static inline int mls_copy_context(struct context *dst, 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 @@ -329,8 +502,12 @@ int mls_convert_context(struct policydb *oldp, struct level_datum *levdatum; struct cat_datum *catdatum; struct ebitmap bitmap; + struct ebitmap_node *node; 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]); @@ -340,12 +517,12 @@ int mls_convert_context(struct policydb *oldp, c->range.level[l].sens = levdatum->level->sens; ebitmap_init(&bitmap); - for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) { - if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) { + ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { + if (ebitmap_node_get_bit(node, i)) { int rc; catdatum = hashtab_search(newp->p_cats.table, - oldp->p_cat_val_to_name[i - 1]); + oldp->p_cat_val_to_name[i]); if (!catdatum) return -EINVAL; rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); @@ -366,17 +543,38 @@ int mls_compute_sid(struct context *scontext, 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 +585,3 @@ int mls_compute_sid(struct context *scontext, 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; -}