diff options
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/conditional.c | 6 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 25 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 701 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 19 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 425 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.c | 39 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.h | 2 |
7 files changed, 626 insertions, 591 deletions
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 655fe1c6cc69..c3f845cbcd48 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -193,6 +193,7 @@ int cond_index_bool(void *key, void *datum, void *datap) { struct policydb *p; struct cond_bool_datum *booldatum; + struct flex_array *fa; booldatum = datum; p = datap; @@ -200,7 +201,10 @@ int cond_index_bool(void *key, void *datum, void *datap) if (!booldatum->value || booldatum->value > p->p_bools.nprim) return -EINVAL; - p->p_bool_val_to_name[booldatum->value - 1] = key; + fa = p->sym_val_to_name[SYM_BOOLS]; + if (flex_array_put_ptr(fa, booldatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); p->bool_val_to_struct[booldatum->value - 1] = booldatum; return 0; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index b4eff7a60c50..1ef8e4e89880 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -45,7 +45,7 @@ int mls_compute_context_len(struct context *context) len = 1; /* for the beginning ":" */ for (l = 0; l < 2; l++) { int index_sens = context->range.level[l].sens; - len += strlen(policydb.p_sens_val_to_name[index_sens - 1]); + len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1)); /* categories */ head = -2; @@ -55,17 +55,17 @@ int mls_compute_context_len(struct context *context) if (i - prev > 1) { /* one or more negative bits are skipped */ if (head != prev) { - nm = policydb.p_cat_val_to_name[prev]; + nm = sym_name(&policydb, SYM_CATS, prev); len += strlen(nm) + 1; } - nm = policydb.p_cat_val_to_name[i]; + nm = sym_name(&policydb, SYM_CATS, i); len += strlen(nm) + 1; head = i; } prev = i; } if (prev != head) { - nm = policydb.p_cat_val_to_name[prev]; + nm = sym_name(&policydb, SYM_CATS, prev); len += strlen(nm) + 1; } if (l == 0) { @@ -102,8 +102,8 @@ void mls_sid_to_context(struct context *context, scontextp++; for (l = 0; l < 2; l++) { - strcpy(scontextp, - policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); + strcpy(scontextp, sym_name(&policydb, SYM_LEVELS, + context->range.level[l].sens - 1)); scontextp += strlen(scontextp); /* categories */ @@ -118,7 +118,7 @@ void mls_sid_to_context(struct context *context, *scontextp++ = '.'; else *scontextp++ = ','; - nm = policydb.p_cat_val_to_name[prev]; + nm = sym_name(&policydb, SYM_CATS, prev); strcpy(scontextp, nm); scontextp += strlen(nm); } @@ -126,7 +126,7 @@ void mls_sid_to_context(struct context *context, *scontextp++ = ':'; else *scontextp++ = ','; - nm = policydb.p_cat_val_to_name[i]; + nm = sym_name(&policydb, SYM_CATS, i); strcpy(scontextp, nm); scontextp += strlen(nm); head = i; @@ -139,7 +139,7 @@ void mls_sid_to_context(struct context *context, *scontextp++ = '.'; else *scontextp++ = ','; - nm = policydb.p_cat_val_to_name[prev]; + nm = sym_name(&policydb, SYM_CATS, prev); strcpy(scontextp, nm); scontextp += strlen(nm); } @@ -166,7 +166,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l) if (!l->sens || l->sens > p->p_levels.nprim) return 0; levdatum = hashtab_search(p->p_levels.table, - p->p_sens_val_to_name[l->sens - 1]); + sym_name(p, SYM_LEVELS, l->sens - 1)); if (!levdatum) return 0; @@ -482,7 +482,8 @@ int mls_convert_context(struct policydb *oldp, 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]); + sym_name(oldp, SYM_LEVELS, + c->range.level[l].sens - 1)); if (!levdatum) return -EINVAL; @@ -493,7 +494,7 @@ int mls_convert_context(struct policydb *oldp, int rc; catdatum = hashtab_search(newp->p_cats.table, - oldp->p_cat_val_to_name[i]); + sym_name(oldp, SYM_CATS, i)); if (!catdatum) return -EINVAL; rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 94f630d93a5c..be9de3872837 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -148,32 +148,30 @@ static int roles_init(struct policydb *p) int rc; struct role_datum *role; + rc = -ENOMEM; role = kzalloc(sizeof(*role), GFP_KERNEL); - if (!role) { - rc = -ENOMEM; + if (!role) goto out; - } + + rc = -EINVAL; role->value = ++p->p_roles.nprim; - if (role->value != OBJECT_R_VAL) { - rc = -EINVAL; - goto out_free_role; - } + if (role->value != OBJECT_R_VAL) + goto out; + + rc = -ENOMEM; key = kstrdup(OBJECT_R, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; - goto out_free_role; - } + if (!key) + goto out; + rc = hashtab_insert(p->p_roles.table, key, role); if (rc) - goto out_free_key; -out: - return rc; + goto out; -out_free_key: + return 0; +out: kfree(key); -out_free_role: kfree(role); - goto out; + return rc; } static u32 rangetr_hash(struct hashtab *h, const void *k) @@ -213,35 +211,33 @@ static int policydb_init(struct policydb *p) for (i = 0; i < SYM_NUM; i++) { rc = symtab_init(&p->symtab[i], symtab_sizes[i]); if (rc) - goto out_free_symtab; + goto out; } rc = avtab_init(&p->te_avtab); if (rc) - goto out_free_symtab; + goto out; rc = roles_init(p); if (rc) - goto out_free_symtab; + goto out; rc = cond_policydb_init(p); if (rc) - goto out_free_symtab; + goto out; p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); if (!p->range_tr) - goto out_free_symtab; + goto out; ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); + return 0; out: - return rc; - -out_free_symtab: for (i = 0; i < SYM_NUM; i++) hashtab_destroy(p->symtab[i].table); - goto out; + return rc; } /* @@ -258,12 +254,17 @@ static int common_index(void *key, void *datum, void *datap) { struct policydb *p; struct common_datum *comdatum; + struct flex_array *fa; comdatum = datum; p = datap; if (!comdatum->value || comdatum->value > p->p_commons.nprim) return -EINVAL; - p->p_common_val_to_name[comdatum->value - 1] = key; + + fa = p->sym_val_to_name[SYM_COMMONS]; + if (flex_array_put_ptr(fa, comdatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); return 0; } @@ -271,12 +272,16 @@ static int class_index(void *key, void *datum, void *datap) { struct policydb *p; struct class_datum *cladatum; + struct flex_array *fa; cladatum = datum; p = datap; if (!cladatum->value || cladatum->value > p->p_classes.nprim) return -EINVAL; - p->p_class_val_to_name[cladatum->value - 1] = key; + fa = p->sym_val_to_name[SYM_CLASSES]; + if (flex_array_put_ptr(fa, cladatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); p->class_val_to_struct[cladatum->value - 1] = cladatum; return 0; } @@ -285,6 +290,7 @@ static int role_index(void *key, void *datum, void *datap) { struct policydb *p; struct role_datum *role; + struct flex_array *fa; role = datum; p = datap; @@ -292,7 +298,11 @@ static int role_index(void *key, void *datum, void *datap) || role->value > p->p_roles.nprim || role->bounds > p->p_roles.nprim) return -EINVAL; - p->p_role_val_to_name[role->value - 1] = key; + + fa = p->sym_val_to_name[SYM_ROLES]; + if (flex_array_put_ptr(fa, role->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); p->role_val_to_struct[role->value - 1] = role; return 0; } @@ -301,6 +311,7 @@ static int type_index(void *key, void *datum, void *datap) { struct policydb *p; struct type_datum *typdatum; + struct flex_array *fa; typdatum = datum; p = datap; @@ -310,8 +321,15 @@ static int type_index(void *key, void *datum, void *datap) || typdatum->value > p->p_types.nprim || typdatum->bounds > p->p_types.nprim) return -EINVAL; - p->p_type_val_to_name[typdatum->value - 1] = key; - p->type_val_to_struct[typdatum->value - 1] = typdatum; + fa = p->sym_val_to_name[SYM_TYPES]; + if (flex_array_put_ptr(fa, typdatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); + + fa = p->type_val_to_struct_array; + if (flex_array_put_ptr(fa, typdatum->value - 1, typdatum, + GFP_KERNEL | __GFP_ZERO)) + BUG(); } return 0; @@ -321,6 +339,7 @@ static int user_index(void *key, void *datum, void *datap) { struct policydb *p; struct user_datum *usrdatum; + struct flex_array *fa; usrdatum = datum; p = datap; @@ -328,7 +347,11 @@ static int user_index(void *key, void *datum, void *datap) || usrdatum->value > p->p_users.nprim || usrdatum->bounds > p->p_users.nprim) return -EINVAL; - p->p_user_val_to_name[usrdatum->value - 1] = key; + + fa = p->sym_val_to_name[SYM_USERS]; + if (flex_array_put_ptr(fa, usrdatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); p->user_val_to_struct[usrdatum->value - 1] = usrdatum; return 0; } @@ -337,6 +360,7 @@ static int sens_index(void *key, void *datum, void *datap) { struct policydb *p; struct level_datum *levdatum; + struct flex_array *fa; levdatum = datum; p = datap; @@ -345,7 +369,10 @@ static int sens_index(void *key, void *datum, void *datap) if (!levdatum->level->sens || levdatum->level->sens > p->p_levels.nprim) return -EINVAL; - p->p_sens_val_to_name[levdatum->level->sens - 1] = key; + fa = p->sym_val_to_name[SYM_LEVELS]; + if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); } return 0; @@ -355,6 +382,7 @@ static int cat_index(void *key, void *datum, void *datap) { struct policydb *p; struct cat_datum *catdatum; + struct flex_array *fa; catdatum = datum; p = datap; @@ -362,7 +390,10 @@ static int cat_index(void *key, void *datum, void *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; + fa = p->sym_val_to_name[SYM_CATS]; + if (flex_array_put_ptr(fa, catdatum->value - 1, key, + GFP_KERNEL | __GFP_ZERO)) + BUG(); } return 0; @@ -380,47 +411,6 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = cat_index, }; -/* - * Define the common val_to_name array and the class - * val_to_name and val_to_struct arrays in a policy - * database structure. - * - * Caller must clean up upon failure. - */ -static int policydb_index_classes(struct policydb *p) -{ - int rc; - - p->p_common_val_to_name = - kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL); - if (!p->p_common_val_to_name) { - rc = -ENOMEM; - goto out; - } - - rc = hashtab_map(p->p_commons.table, common_index, p); - if (rc) - goto out; - - p->class_val_to_struct = - kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL); - if (!p->class_val_to_struct) { - rc = -ENOMEM; - goto out; - } - - p->p_class_val_to_name = - kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL); - if (!p->p_class_val_to_name) { - rc = -ENOMEM; - goto out; - } - - rc = hashtab_map(p->p_classes.table, class_index, p); -out: - return rc; -} - #ifdef DEBUG_HASHES static void symtab_hash_eval(struct symtab *s) { @@ -458,9 +448,9 @@ static inline void rangetr_hash_eval(struct hashtab *h) * * Caller must clean up on failure. */ -static int policydb_index_others(struct policydb *p) +static int policydb_index(struct policydb *p) { - int i, rc = 0; + int i, rc; 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); @@ -477,47 +467,63 @@ static int policydb_index_others(struct policydb *p) symtab_hash_eval(p->symtab); #endif + rc = -ENOMEM; + p->class_val_to_struct = + kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), + GFP_KERNEL); + if (!p->class_val_to_struct) + goto out; + + rc = -ENOMEM; p->role_val_to_struct = kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), GFP_KERNEL); - if (!p->role_val_to_struct) { - rc = -ENOMEM; + if (!p->role_val_to_struct) goto out; - } + rc = -ENOMEM; p->user_val_to_struct = kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), GFP_KERNEL); - if (!p->user_val_to_struct) { - rc = -ENOMEM; + if (!p->user_val_to_struct) goto out; - } - p->type_val_to_struct = - kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)), - GFP_KERNEL); - if (!p->type_val_to_struct) { - rc = -ENOMEM; + /* Yes, I want the sizeof the pointer, not the structure */ + rc = -ENOMEM; + p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *), + p->p_types.nprim, + GFP_KERNEL | __GFP_ZERO); + if (!p->type_val_to_struct_array) goto out; - } - if (cond_init_bool_indexes(p)) { - rc = -ENOMEM; + rc = flex_array_prealloc(p->type_val_to_struct_array, 0, + p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO); + if (rc) goto out; - } - for (i = SYM_ROLES; i < SYM_NUM; i++) { - p->sym_val_to_name[i] = - kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL); - if (!p->sym_val_to_name[i]) { - rc = -ENOMEM; + rc = -ENOMEM; + if (cond_init_bool_indexes(p)) + goto out; + + for (i = 0; i < SYM_NUM; i++) { + rc = -ENOMEM; + p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *), + p->symtab[i].nprim, + GFP_KERNEL | __GFP_ZERO); + if (!p->sym_val_to_name[i]) goto out; - } + + rc = flex_array_prealloc(p->sym_val_to_name[i], + 0, p->symtab[i].nprim - 1, + GFP_KERNEL | __GFP_ZERO); + if (rc) + goto out; + rc = hashtab_map(p->symtab[i].table, index_f[i], p); if (rc) goto out; } - + rc = 0; out: return rc; } @@ -540,9 +546,11 @@ static int common_destroy(void *key, void *datum, void *p) struct common_datum *comdatum; kfree(key); - comdatum = datum; - hashtab_map(comdatum->permissions.table, perm_destroy, NULL); - hashtab_destroy(comdatum->permissions.table); + if (datum) { + comdatum = datum; + hashtab_map(comdatum->permissions.table, perm_destroy, NULL); + hashtab_destroy(comdatum->permissions.table); + } kfree(datum); return 0; } @@ -554,38 +562,40 @@ static int cls_destroy(void *key, void *datum, void *p) struct constraint_expr *e, *etmp; kfree(key); - cladatum = datum; - hashtab_map(cladatum->permissions.table, perm_destroy, NULL); - hashtab_destroy(cladatum->permissions.table); - constraint = cladatum->constraints; - while (constraint) { - e = constraint->expr; - while (e) { - ebitmap_destroy(&e->names); - etmp = e; - e = e->next; - kfree(etmp); + if (datum) { + cladatum = datum; + hashtab_map(cladatum->permissions.table, perm_destroy, NULL); + hashtab_destroy(cladatum->permissions.table); + constraint = cladatum->constraints; + 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); } - ctemp = constraint; - 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); + + 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); } - ctemp = constraint; - constraint = constraint->next; - kfree(ctemp); - } - kfree(cladatum->comkey); + kfree(cladatum->comkey); + } kfree(datum); return 0; } @@ -595,9 +605,11 @@ static int role_destroy(void *key, void *datum, void *p) struct role_datum *role; kfree(key); - role = datum; - ebitmap_destroy(&role->dominates); - ebitmap_destroy(&role->types); + if (datum) { + role = datum; + ebitmap_destroy(&role->dominates); + ebitmap_destroy(&role->types); + } kfree(datum); return 0; } @@ -614,11 +626,13 @@ static int user_destroy(void *key, void *datum, void *p) struct user_datum *usrdatum; kfree(key); - usrdatum = datum; - ebitmap_destroy(&usrdatum->roles); - ebitmap_destroy(&usrdatum->range.level[0].cat); - ebitmap_destroy(&usrdatum->range.level[1].cat); - ebitmap_destroy(&usrdatum->dfltlevel.cat); + if (datum) { + usrdatum = datum; + ebitmap_destroy(&usrdatum->roles); + ebitmap_destroy(&usrdatum->range.level[0].cat); + ebitmap_destroy(&usrdatum->range.level[1].cat); + ebitmap_destroy(&usrdatum->dfltlevel.cat); + } kfree(datum); return 0; } @@ -628,9 +642,11 @@ 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); + if (datum) { + levdatum = datum; + ebitmap_destroy(&levdatum->level->cat); + kfree(levdatum->level); + } kfree(datum); return 0; } @@ -695,13 +711,16 @@ void policydb_destroy(struct policydb *p) hashtab_destroy(p->symtab[i].table); } - for (i = 0; i < SYM_NUM; i++) - kfree(p->sym_val_to_name[i]); + for (i = 0; i < SYM_NUM; i++) { + if (p->sym_val_to_name[i]) + flex_array_free(p->sym_val_to_name[i]); + } kfree(p->class_val_to_struct); kfree(p->role_val_to_struct); kfree(p->user_val_to_struct); - kfree(p->type_val_to_struct); + if (p->type_val_to_struct_array) + flex_array_free(p->type_val_to_struct_array); avtab_destroy(&p->te_avtab); @@ -785,19 +804,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { + rc = -EINVAL; if (!c->context[0].user) { - printk(KERN_ERR "SELinux: SID %s was never " - "defined.\n", c->u.name); - rc = -EINVAL; + printk(KERN_ERR "SELinux: SID %s was never defined.\n", + c->u.name); goto out; } - if (sidtab_insert(s, c->sid[0], &c->context[0])) { - printk(KERN_ERR "SELinux: unable to load initial " - "SID %s.\n", c->u.name); - rc = -EINVAL; + + rc = sidtab_insert(s, c->sid[0], &c->context[0]); + if (rc) { + printk(KERN_ERR "SELinux: unable to load initial SID %s.\n", + c->u.name); goto out; } } + rc = 0; out: return rc; } @@ -846,8 +867,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c) * Role must be authorized for the type. */ role = p->role_val_to_struct[c->role - 1]; - if (!ebitmap_get_bit(&role->types, - c->type - 1)) + if (!ebitmap_get_bit(&role->types, c->type - 1)) /* role may not be associated with type */ return 0; @@ -858,8 +878,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c) if (!usrdatum) return 0; - if (!ebitmap_get_bit(&usrdatum->roles, - c->role - 1)) + if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1)) /* user may not be associated with role */ return 0; } @@ -881,20 +900,22 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) int rc; rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc) goto out; + rc = -EINVAL; items = le32_to_cpu(buf[0]); if (items > ARRAY_SIZE(buf)) { printk(KERN_ERR "SELinux: mls: range overflow\n"); - rc = -EINVAL; goto out; } + rc = next_entry(buf, fp, sizeof(u32) * items); - if (rc < 0) { + if (rc) { printk(KERN_ERR "SELinux: 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]); @@ -903,15 +924,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) rc = ebitmap_read(&r->level[0].cat, fp); if (rc) { - printk(KERN_ERR "SELinux: mls: error reading low " - "categories\n"); + printk(KERN_ERR "SELinux: mls: error reading low categories\n"); goto out; } if (items > 1) { rc = ebitmap_read(&r->level[1].cat, fp); if (rc) { - printk(KERN_ERR "SELinux: mls: error reading high " - "categories\n"); + printk(KERN_ERR "SELinux: mls: error reading high categories\n"); goto bad_high; } } else { @@ -922,12 +941,11 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) } } - rc = 0; -out: - return rc; + return 0; bad_high: ebitmap_destroy(&r->level[0].cat); - goto out; +out: + return rc; } /* @@ -942,7 +960,7 @@ static int context_read_and_validate(struct context *c, int rc; rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) { + if (rc) { printk(KERN_ERR "SELinux: context truncated\n"); goto out; } @@ -950,19 +968,20 @@ static int context_read_and_validate(struct context *c, c->role = le32_to_cpu(buf[1]); c->type = le32_to_cpu(buf[2]); if (p->policyvers >= POLICYDB_VERSION_MLS) { - if (mls_read_range_helper(&c->range, fp)) { - printk(KERN_ERR "SELinux: error reading MLS range of " - "context\n"); - rc = -EINVAL; + rc = mls_read_range_helper(&c->range, fp); + if (rc) { + printk(KERN_ERR "SELinux: error reading MLS range of context\n"); goto out; } } + rc = -EINVAL; if (!policydb_context_isvalid(p, c)) { printk(KERN_ERR "SELinux: invalid security context\n"); context_destroy(c); - rc = -EINVAL; + goto out; } + rc = 0; out: return rc; } @@ -981,37 +1000,36 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[2]; u32 len; + rc = -ENOMEM; perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL); - if (!perdatum) { - rc = -ENOMEM; - goto out; - } + if (!perdatum) + goto bad; rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); perdatum->value = le32_to_cpu(buf[1]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } + rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; rc = hashtab_insert(h, key, perdatum); if (rc) goto bad; -out: - return rc; + + return 0; bad: perm_destroy(key, perdatum, NULL); - goto out; + return rc; } static int common_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1022,14 +1040,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) u32 len, nel; int i, rc; + rc = -ENOMEM; comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL); - if (!comdatum) { - rc = -ENOMEM; - goto out; - } + if (!comdatum) + goto bad; rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); @@ -1041,13 +1058,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) comdatum->permissions.nprim = le32_to_cpu(buf[2]); nel = le32_to_cpu(buf[3]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } + rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; @@ -1060,11 +1077,10 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) rc = hashtab_insert(h, key, comdatum); if (rc) goto bad; -out: - return rc; + return 0; bad: common_destroy(key, comdatum, NULL); - goto out; + return rc; } static int read_cons_helper(struct constraint_node **nodep, int ncons, @@ -1088,7 +1104,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, *nodep = c; rc = next_entry(buf, fp, (sizeof(u32) * 2)); - if (rc < 0) + if (rc) return rc; c->permissions = le32_to_cpu(buf[0]); nexpr = le32_to_cpu(buf[1]); @@ -1105,7 +1121,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, c->expr = e; rc = next_entry(buf, fp, (sizeof(u32) * 3)); - if (rc < 0) + if (rc) return rc; e->expr_type = le32_to_cpu(buf[0]); e->attr = le32_to_cpu(buf[1]); @@ -1133,8 +1149,9 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, if (depth == (CEXPR_MAXDEPTH - 1)) return -EINVAL; depth++; - if (ebitmap_read(&e->names, fp)) - return -EINVAL; + rc = ebitmap_read(&e->names, fp); + if (rc) + return rc; break; default: return -EINVAL; @@ -1157,14 +1174,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) u32 len, len2, ncons, nel; int i, rc; + rc = -ENOMEM; cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL); - if (!cladatum) { - rc = -ENOMEM; - goto out; - } + if (!cladatum) + goto bad; rc = next_entry(buf, fp, sizeof(u32)*6); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); @@ -1179,33 +1195,30 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ncons = le32_to_cpu(buf[5]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } + rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; if (len2) { + rc = -ENOMEM; cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); - if (!cladatum->comkey) { - rc = -ENOMEM; + if (!cladatum->comkey) goto bad; - } rc = next_entry(cladatum->comkey, fp, len2); - if (rc < 0) + if (rc) goto bad; cladatum->comkey[len2] = '\0'; - cladatum->comdatum = hashtab_search(p->p_commons.table, - cladatum->comkey); + rc = -EINVAL; + cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); if (!cladatum->comdatum) { - printk(KERN_ERR "SELinux: unknown common %s\n", - cladatum->comkey); - rc = -EINVAL; + printk(KERN_ERR "SELinux: unknown common %s\n", cladatum->comkey); goto bad; } } @@ -1222,7 +1235,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) { /* grab the validatetrans rules */ rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc) goto bad; ncons = le32_to_cpu(buf[0]); rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); @@ -1234,12 +1247,10 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) if (rc) goto bad; - rc = 0; -out: - return rc; + return 0; bad: cls_destroy(key, cladatum, NULL); - goto out; + return rc; } static int role_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1250,17 +1261,16 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; + rc = -ENOMEM; role = kzalloc(sizeof(*role), GFP_KERNEL); - if (!role) { - rc = -ENOMEM; - goto out; - } + if (!role) + goto bad; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 3; rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); @@ -1268,13 +1278,13 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) role->bounds = le32_to_cpu(buf[2]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } + rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; @@ -1287,10 +1297,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) goto bad; if (strcmp(key, OBJECT_R) == 0) { + rc = -EINVAL; if (role->value != OBJECT_R_VAL) { printk(KERN_ERR "SELinux: Role %s has wrong value %d\n", OBJECT_R, role->value); - rc = -EINVAL; goto bad; } rc = 0; @@ -1300,11 +1310,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) rc = hashtab_insert(h, key, role); if (rc) goto bad; -out: - return rc; + return 0; bad: role_destroy(key, role, NULL); - goto out; + return rc; } static int type_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1315,17 +1324,16 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[4]; u32 len; + rc = -ENOMEM; typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); - if (!typdatum) { - rc = -ENOMEM; - return rc; - } + if (!typdatum) + goto bad; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 4; rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); @@ -1343,24 +1351,22 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) typdatum->primary = le32_to_cpu(buf[2]); } + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; rc = hashtab_insert(h, key, typdatum); if (rc) goto bad; -out: - return rc; + return 0; bad: type_destroy(key, typdatum, NULL); - goto out; + return rc; } @@ -1376,22 +1382,18 @@ static int mls_read_level(struct mls_level *lp, void *fp) memset(lp, 0, sizeof(*lp)); rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) { + if (rc) { printk(KERN_ERR "SELinux: mls: truncated level\n"); - goto bad; + return rc; } lp->sens = le32_to_cpu(buf[0]); - if (ebitmap_read(&lp->cat, fp)) { - printk(KERN_ERR "SELinux: mls: error reading level " - "categories\n"); - goto bad; + rc = ebitmap_read(&lp->cat, fp); + if (rc) { + printk(KERN_ERR "SELinux: mls: error reading level categories\n"); + return rc; } - return 0; - -bad: - return -EINVAL; } static int user_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1402,17 +1404,16 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; + rc = -ENOMEM; usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); - if (!usrdatum) { - rc = -ENOMEM; - goto out; - } + if (!usrdatum) + goto bad; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 3; rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); @@ -1420,13 +1421,12 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) usrdatum->bounds = le32_to_cpu(buf[2]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; @@ -1446,11 +1446,10 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) rc = hashtab_insert(h, key, usrdatum); if (rc) goto bad; -out: - return rc; + return 0; bad: user_destroy(key, usrdatum, NULL); - goto out; + return rc; } static int sens_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1461,47 +1460,43 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[2]; u32 len; + rc = -ENOMEM; levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC); - if (!levdatum) { - rc = -ENOMEM; - goto out; - } + if (!levdatum) + goto bad; rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); levdatum->isalias = le32_to_cpu(buf[1]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_ATOMIC); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; + rc = -ENOMEM; levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); - if (!levdatum->level) { - rc = -ENOMEM; + if (!levdatum->level) goto bad; - } - if (mls_read_level(levdatum->level, fp)) { - rc = -EINVAL; + + rc = mls_read_level(levdatum->level, fp); + if (rc) goto bad; - } rc = hashtab_insert(h, key, levdatum); if (rc) goto bad; -out: - return rc; + return 0; bad: sens_destroy(key, levdatum, NULL); - goto out; + return rc; } static int cat_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1512,39 +1507,35 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; + rc = -ENOMEM; catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC); - if (!catdatum) { - rc = -ENOMEM; - goto out; - } + if (!catdatum) + goto bad; rc = next_entry(buf, fp, sizeof buf); - if (rc < 0) + if (rc) goto bad; len = le32_to_cpu(buf[0]); catdatum->value = le32_to_cpu(buf[1]); catdatum->isalias = le32_to_cpu(buf[2]); + rc = -ENOMEM; key = kmalloc(len + 1, GFP_ATOMIC); - if (!key) { - rc = -ENOMEM; + if (!key) goto bad; - } rc = next_entry(key, fp, len); - if (rc < 0) + if (rc) goto bad; key[len] = '\0'; rc = hashtab_insert(h, key, catdatum); if (rc) goto bad; -out: - return rc; - + return 0; bad: cat_destroy(key, catdatum, NULL); - goto out; + return rc; } static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) = @@ -1585,9 +1576,9 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap) printk(KERN_ERR "SELinux: boundary violated policy: " "user=%s role=%s bounds=%s\n", - p->p_user_val_to_name[user->value - 1], - p->p_role_val_to_name[bit], - p->p_user_val_to_name[upper->value - 1]); + sym_name(p, SYM_USERS, user->value - 1), + sym_name(p, SYM_ROLES, bit), + sym_name(p, SYM_USERS, upper->value - 1)); return -EINVAL; } @@ -1622,9 +1613,9 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap) printk(KERN_ERR "SELinux: boundary violated policy: " "role=%s type=%s bounds=%s\n", - p->p_role_val_to_name[role->value - 1], - p->p_type_val_to_name[bit], - p->p_role_val_to_name[upper->value - 1]); + sym_name(p, SYM_ROLES, role->value - 1), + sym_name(p, SYM_TYPES, bit), + sym_name(p, SYM_ROLES, upper->value - 1)); return -EINVAL; } @@ -1648,12 +1639,15 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap) return -EINVAL; } - upper = p->type_val_to_struct[upper->bounds - 1]; + upper = flex_array_get_ptr(p->type_val_to_struct_array, + upper->bounds - 1); + BUG_ON(!upper); + if (upper->attribute) { printk(KERN_ERR "SELinux: type %s: " "bounded by attribute %s", (char *) key, - p->p_type_val_to_name[upper->value - 1]); + sym_name(p, SYM_TYPES, upper->value - 1)); return -EINVAL; } } @@ -2066,13 +2060,14 @@ int policydb_read(struct policydb *p, void *fp) rc = policydb_init(p); if (rc) - goto out; + return rc; /* Read the magic number and string length. */ rc = next_entry(buf, fp, sizeof(u32) * 2); - if (rc < 0) + if (rc) goto bad; + rc = -EINVAL; if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) { printk(KERN_ERR "SELinux: policydb magic number 0x%x does " "not match expected magic number 0x%x\n", @@ -2080,6 +2075,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; } + rc = -EINVAL; len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_STRING)) { printk(KERN_ERR "SELinux: policydb string length %d does not " @@ -2087,19 +2083,23 @@ int policydb_read(struct policydb *p, void *fp) len, strlen(POLICYDB_STRING)); goto bad; } + + rc = -ENOMEM; policydb_str = kmalloc(len + 1, GFP_KERNEL); if (!policydb_str) { printk(KERN_ERR "SELinux: unable to allocate memory for policydb " "string of length %d\n", len); - rc = -ENOMEM; goto bad; } + rc = next_entry(policydb_str, fp, len); - if (rc < 0) { + if (rc) { printk(KERN_ERR "SELinux: truncated policydb string identifier\n"); kfree(policydb_str); goto bad; } + + rc = -EINVAL; policydb_str[len] = '\0'; if (strcmp(policydb_str, POLICYDB_STRING)) { printk(KERN_ERR "SELinux: policydb string %s does not match " @@ -2113,9 +2113,10 @@ int policydb_read(struct policydb *p, void *fp) /* Read the version and table sizes. */ rc = next_entry(buf, fp, sizeof(u32)*4); - if (rc < 0) + if (rc) goto bad; + rc = -EINVAL; p->policyvers = le32_to_cpu(buf[0]); if (p->policyvers < POLICYDB_VERSION_MIN || p->policyvers > POLICYDB_VERSION_MAX) { @@ -2128,6 +2129,7 @@ int policydb_read(struct policydb *p, void *fp) if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { p->mls_enabled = 1; + rc = -EINVAL; if (p->policyvers < POLICYDB_VERSION_MLS) { printk(KERN_ERR "SELinux: security policydb version %d " "(MLS) not backwards compatible\n", @@ -2138,14 +2140,19 @@ int policydb_read(struct policydb *p, void *fp) p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); - if (p->policyvers >= POLICYDB_VERSION_POLCAP && - ebitmap_read(&p->policycaps, fp) != 0) - goto bad; + if (p->policyvers >= POLICYDB_VERSION_POLCAP) { + rc = ebitmap_read(&p->policycaps, fp); + if (rc) + goto bad; + } - if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && - ebitmap_read(&p->permissive_map, fp) != 0) - goto bad; + if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) { + rc = ebitmap_read(&p->permissive_map, fp); + if (rc) + goto bad; + } + rc = -EINVAL; info = policydb_lookup_compat(p->policyvers); if (!info) { printk(KERN_ERR "SELinux: unable to find policy compat info " @@ -2153,6 +2160,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; } + rc = -EINVAL; if (le32_to_cpu(buf[2]) != info->sym_num || le32_to_cpu(buf[3]) != info->ocon_num) { printk(KERN_ERR "SELinux: policydb table sizes (%d,%d) do " @@ -2164,7 +2172,7 @@ int policydb_read(struct policydb *p, void *fp) for (i = 0; i < info->sym_num; i++) { rc = next_entry(buf, fp, sizeof(u32)*2); - if (rc < 0) + if (rc) goto bad; nprim = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[1]); @@ -2188,78 +2196,73 @@ int policydb_read(struct policydb *p, void *fp) } rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc) goto bad; nel = le32_to_cpu(buf[0]); ltr = NULL; for (i = 0; i < nel; i++) { + rc = -ENOMEM; tr = kzalloc(sizeof(*tr), GFP_KERNEL); - if (!tr) { - rc = -ENOMEM; + if (!tr) goto bad; - } if (ltr) ltr->next = tr; else p->role_tr = tr; rc = next_entry(buf, fp, sizeof(u32)*3); - if (rc < 0) + if (rc) goto bad; + + rc = -EINVAL; tr->role = le32_to_cpu(buf[0]); tr->type = le32_to_cpu(buf[1]); tr->new_role = le32_to_cpu(buf[2]); if (!policydb_role_isvalid(p, tr->role) || !policydb_type_isvalid(p, tr->type) || - !policydb_role_isvalid(p, tr->new_role)) { - rc = -EINVAL; + !policydb_role_isvalid(p, tr->new_role)) goto bad; - } ltr = tr; } rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc) goto bad; nel = le32_to_cpu(buf[0]); lra = NULL; for (i = 0; i < nel; i++) { + rc = -ENOMEM; ra = kzalloc(sizeof(*ra), GFP_KERNEL); - if (!ra) { - rc = -ENOMEM; + if (!ra) goto bad; - } if (lra) lra->next = ra; else p->role_allow = ra; rc = next_entry(buf, fp, sizeof(u32)*2); - if (rc < 0) + if (rc) goto bad; + + rc = -EINVAL; ra->role = le32_to_cpu(buf[0]); ra->new_role = le32_to_cpu(buf[1]); if (!policydb_role_isvalid(p, ra->role) || - !policydb_role_isvalid(p, ra->new_role)) { - rc = -EINVAL; + !policydb_role_isvalid(p, ra->new_role)) goto bad; - } lra = ra; } - rc = policydb_index_classes(p); - if (rc) - goto bad; - - rc = policydb_index_others(p); + rc = policydb_index(p); if (rc) goto bad; + rc = -EINVAL; p->process_class = string_to_security_class(p, "process"); if (!p->process_class) goto bad; - p->process_trans_perms = string_to_av_perm(p, p->process_class, - "transition"); - p->process_trans_perms |= string_to_av_perm(p, p->process_class, - "dyntransition"); + + rc = -EINVAL; + p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); + p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); if (!p->process_trans_perms) goto bad; @@ -2312,8 +2315,6 @@ int policydb_read(struct policydb *p, void *fp) out: return rc; bad: - if (!rc) - rc = -EINVAL; policydb_destroy(p); goto out; } @@ -3076,7 +3077,7 @@ int policydb_write(struct policydb *p, void *fp) if (!info) { printk(KERN_ERR "SELinux: compatibility lookup failed for policy " "version %d", p->policyvers); - return rc; + return -EINVAL; } buf[0] = cpu_to_le32(p->policyvers); diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 95d3d7de361e..4e3ab9d0b315 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -203,21 +203,13 @@ struct policydb { #define p_cats symtab[SYM_CATS] /* symbol names indexed by (value - 1) */ - char **sym_val_to_name[SYM_NUM]; -#define p_common_val_to_name sym_val_to_name[SYM_COMMONS] -#define p_class_val_to_name sym_val_to_name[SYM_CLASSES] -#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] + struct flex_array *sym_val_to_name[SYM_NUM]; /* class, role, and user attributes indexed by (value - 1) */ struct class_datum **class_val_to_struct; struct role_datum **role_val_to_struct; struct user_datum **user_val_to_struct; - struct type_datum **type_val_to_struct; + struct flex_array *type_val_to_struct_array; /* type enforcement access vectors and transitions */ struct avtab te_avtab; @@ -321,6 +313,13 @@ static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file return 0; } +static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr) +{ + struct flex_array *fa = p->sym_val_to_name[sym_num]; + + return flex_array_get_ptr(fa, element_nr); +} + extern u16 string_to_security_class(struct policydb *p, const char *name); extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 223c1ff6ef23..a03cfaf0ee07 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -464,7 +464,7 @@ static void security_dump_masked_av(struct context *scontext, if (!permissions) return; - tclass_name = policydb.p_class_val_to_name[tclass - 1]; + tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1); tclass_dat = policydb.class_val_to_struct[tclass - 1]; common_dat = tclass_dat->comdatum; @@ -530,12 +530,18 @@ static void type_attribute_bounds_av(struct context *scontext, 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]; + struct type_datum *source; + struct type_datum *target; u32 masked = 0; + source = flex_array_get_ptr(policydb.type_val_to_struct_array, + scontext->type - 1); + BUG_ON(!source); + + target = flex_array_get_ptr(policydb.type_val_to_struct_array, + tcontext->type - 1); + BUG_ON(!target); + if (source->bounds) { memset(&lo_avd, 0, sizeof(lo_avd)); @@ -701,16 +707,16 @@ static int security_validtrans_handle_fail(struct context *ocontext, char *o = NULL, *n = NULL, *t = NULL; u32 olen, nlen, tlen; - if (context_struct_to_string(ocontext, &o, &olen) < 0) + if (context_struct_to_string(ocontext, &o, &olen)) goto out; - if (context_struct_to_string(ncontext, &n, &nlen) < 0) + if (context_struct_to_string(ncontext, &n, &nlen)) goto out; - if (context_struct_to_string(tcontext, &t, &tlen) < 0) + if (context_struct_to_string(tcontext, &t, &tlen)) goto out; audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, "security_validate_transition: denied for" " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", - o, n, t, policydb.p_class_val_to_name[tclass-1]); + o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); out: kfree(o); kfree(n); @@ -801,10 +807,11 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) struct context *old_context, *new_context; struct type_datum *type; int index; - int rc = -EINVAL; + int rc; read_lock(&policy_rwlock); + rc = -EINVAL; old_context = sidtab_search(&sidtab, old_sid); if (!old_context) { printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", @@ -812,6 +819,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) goto out; } + rc = -EINVAL; new_context = sidtab_search(&sidtab, new_sid); if (!new_context) { printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", @@ -819,28 +827,27 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) goto out; } + rc = 0; /* type/domain unchanged */ - if (old_context->type == new_context->type) { - rc = 0; + if (old_context->type == new_context->type) goto out; - } index = new_context->type; while (true) { - type = policydb.type_val_to_struct[index - 1]; + type = flex_array_get_ptr(policydb.type_val_to_struct_array, + index - 1); BUG_ON(!type); /* not bounded anymore */ - if (!type->bounds) { - rc = -EPERM; + rc = -EPERM; + if (!type->bounds) break; - } /* @newsid is bounded by @oldsid */ - if (type->bounds == old_context->type) { - rc = 0; + rc = 0; + if (type->bounds == old_context->type) break; - } + index = type->bounds; } @@ -1005,9 +1012,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 } /* Compute the size of the context. */ - *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; - *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; - *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; + *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; + *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; + *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1; *scontext_len += mls_compute_context_len(context); if (!scontext) @@ -1023,12 +1030,12 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 * Copy the user name, role name and type name into the context. */ 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]); + sym_name(&policydb, SYM_USERS, context->user - 1), + sym_name(&policydb, SYM_ROLES, context->role - 1), + sym_name(&policydb, SYM_TYPES, context->type - 1)); + scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + + 1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + + 1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)); mls_sid_to_context(context, &scontextp); @@ -1187,16 +1194,13 @@ static int string_to_context_struct(struct policydb *pol, if (rc) goto out; - if ((p - scontext) < scontext_len) { - rc = -EINVAL; + rc = -EINVAL; + if ((p - scontext) < scontext_len) goto out; - } /* Check the validity of the new context. */ - if (!policydb_context_isvalid(pol, ctx)) { - rc = -EINVAL; + if (!policydb_context_isvalid(pol, ctx)) goto out; - } rc = 0; out: if (rc) @@ -1235,27 +1239,26 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, if (force) { /* Save another copy for storing in uninterpreted form */ + rc = -ENOMEM; str = kstrdup(scontext2, gfp_flags); - if (!str) { - kfree(scontext2); - return -ENOMEM; - } + if (!str) + goto out; } read_lock(&policy_rwlock); - rc = string_to_context_struct(&policydb, &sidtab, - scontext2, scontext_len, - &context, def_sid); + rc = string_to_context_struct(&policydb, &sidtab, scontext2, + scontext_len, &context, def_sid); if (rc == -EINVAL && force) { context.str = str; context.len = scontext_len; str = NULL; } else if (rc) - goto out; + goto out_unlock; rc = sidtab_context_to_sid(&sidtab, &context, sid); context_destroy(&context); -out: +out_unlock: read_unlock(&policy_rwlock); +out: kfree(scontext2); kfree(str); return rc; @@ -1319,18 +1322,18 @@ static int compute_sid_handle_invalid_context( char *s = NULL, *t = NULL, *n = NULL; u32 slen, tlen, nlen; - if (context_struct_to_string(scontext, &s, &slen) < 0) + if (context_struct_to_string(scontext, &s, &slen)) goto out; - if (context_struct_to_string(tcontext, &t, &tlen) < 0) + if (context_struct_to_string(tcontext, &t, &tlen)) goto out; - if (context_struct_to_string(newcontext, &n, &nlen) < 0) + if (context_struct_to_string(newcontext, &n, &nlen)) goto out; audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, "security_compute_sid: invalid context %s" " for scontext=%s" " tcontext=%s" " tclass=%s", - n, s, t, policydb.p_class_val_to_name[tclass-1]); + n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); out: kfree(s); kfree(t); @@ -1569,22 +1572,17 @@ static int clone_sid(u32 sid, static inline int convert_context_handle_invalid_context(struct context *context) { - int rc = 0; + char *s; + u32 len; - if (selinux_enforcing) { - rc = -EINVAL; - } else { - char *s; - u32 len; - - if (!context_struct_to_string(context, &s, &len)) { - printk(KERN_WARNING - "SELinux: Context %s would be invalid if enforcing\n", - s); - kfree(s); - } + if (selinux_enforcing) + return -EINVAL; + + if (!context_struct_to_string(context, &s, &len)) { + printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s); + kfree(s); } - return rc; + return 0; } struct convert_context_args { @@ -1621,17 +1619,17 @@ static int convert_context(u32 key, if (c->str) { struct context ctx; + + rc = -ENOMEM; s = kstrdup(c->str, GFP_KERNEL); - if (!s) { - rc = -ENOMEM; + if (!s) goto out; - } + rc = string_to_context_struct(args->newp, NULL, s, c->len, &ctx, SECSID_NULL); kfree(s); if (!rc) { - printk(KERN_INFO - "SELinux: Context %s became valid (mapped).\n", + printk(KERN_INFO "SELinux: Context %s became valid (mapped).\n", c->str); /* Replace string with mapped representation. */ kfree(c->str); @@ -1643,8 +1641,7 @@ static int convert_context(u32 key, goto out; } else { /* Other error condition, e.g. ENOMEM. */ - printk(KERN_ERR - "SELinux: Unable to map context %s, rc = %d.\n", + printk(KERN_ERR "SELinux: Unable to map context %s, rc = %d.\n", c->str, -rc); goto out; } @@ -1654,25 +1651,26 @@ static int convert_context(u32 key, if (rc) goto out; - rc = -EINVAL; - /* Convert the user. */ + rc = -EINVAL; usrdatum = hashtab_search(args->newp->p_users.table, - args->oldp->p_user_val_to_name[c->user - 1]); + sym_name(args->oldp, SYM_USERS, c->user - 1)); if (!usrdatum) goto bad; c->user = usrdatum->value; /* Convert the role. */ + rc = -EINVAL; role = hashtab_search(args->newp->p_roles.table, - args->oldp->p_role_val_to_name[c->role - 1]); + sym_name(args->oldp, SYM_ROLES, c->role - 1)); if (!role) goto bad; c->role = role->value; /* Convert the type. */ + rc = -EINVAL; typdatum = hashtab_search(args->newp->p_types.table, - args->oldp->p_type_val_to_name[c->type - 1]); + sym_name(args->oldp, SYM_TYPES, c->type - 1)); if (!typdatum) goto bad; c->type = typdatum->value; @@ -1700,6 +1698,7 @@ static int convert_context(u32 key, oc = args->newp->ocontexts[OCON_ISID]; while (oc && oc->sid[0] != SECINITSID_UNLABELED) oc = oc->next; + rc = -EINVAL; if (!oc) { printk(KERN_ERR "SELinux: unable to look up" " the initial SIDs list\n"); @@ -1719,19 +1718,20 @@ static int convert_context(u32 key, } context_destroy(&oldc); + rc = 0; out: return rc; bad: /* Map old representation to string and save it. */ - if (context_struct_to_string(&oldc, &s, &len)) - return -ENOMEM; + rc = context_struct_to_string(&oldc, &s, &len); + if (rc) + return rc; context_destroy(&oldc); context_destroy(c); c->str = s; c->len = len; - printk(KERN_INFO - "SELinux: Context %s became invalid (unmapped).\n", + printk(KERN_INFO "SELinux: Context %s became invalid (unmapped).\n", c->str); rc = 0; goto out; @@ -2012,7 +2012,7 @@ int security_node_sid(u16 domain, u32 addrlen, u32 *out_sid) { - int rc = 0; + int rc; struct ocontext *c; read_lock(&policy_rwlock); @@ -2021,10 +2021,9 @@ int security_node_sid(u16 domain, case AF_INET: { u32 addr; - if (addrlen != sizeof(u32)) { - rc = -EINVAL; + rc = -EINVAL; + if (addrlen != sizeof(u32)) goto out; - } addr = *((u32 *)addrp); @@ -2038,10 +2037,9 @@ int security_node_sid(u16 domain, } case AF_INET6: - if (addrlen != sizeof(u64) * 2) { - rc = -EINVAL; + rc = -EINVAL; + if (addrlen != sizeof(u64) * 2) goto out; - } c = policydb.ocontexts[OCON_NODE6]; while (c) { if (match_ipv6_addrmask(addrp, c->u.node6.addr, @@ -2052,6 +2050,7 @@ int security_node_sid(u16 domain, break; default: + rc = 0; *out_sid = SECINITSID_NODE; goto out; } @@ -2069,6 +2068,7 @@ int security_node_sid(u16 domain, *out_sid = SECINITSID_NODE; } + rc = 0; out: read_unlock(&policy_rwlock); return rc; @@ -2113,24 +2113,22 @@ int security_get_user_sids(u32 fromsid, context_init(&usercon); + rc = -EINVAL; fromcon = sidtab_search(&sidtab, fromsid); - if (!fromcon) { - rc = -EINVAL; + if (!fromcon) goto out_unlock; - } + rc = -EINVAL; user = hashtab_search(policydb.p_users.table, username); - if (!user) { - rc = -EINVAL; + if (!user) goto out_unlock; - } + usercon.user = user->value; + rc = -ENOMEM; mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); - if (!mysids) { - rc = -ENOMEM; + if (!mysids) goto out_unlock; - } ebitmap_for_each_positive_bit(&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; @@ -2147,12 +2145,11 @@ int security_get_user_sids(u32 fromsid, if (mynel < maxnel) { mysids[mynel++] = sid; } else { + rc = -ENOMEM; maxnel += SIDS_NEL; mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); - if (!mysids2) { - rc = -ENOMEM; + if (!mysids2) goto out_unlock; - } memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); kfree(mysids); mysids = mysids2; @@ -2160,7 +2157,7 @@ int security_get_user_sids(u32 fromsid, } } } - + rc = 0; out_unlock: read_unlock(&policy_rwlock); if (rc || !mynel) { @@ -2168,9 +2165,9 @@ out_unlock: goto out; } + rc = -ENOMEM; mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); if (!mysids2) { - rc = -ENOMEM; kfree(mysids); goto out; } @@ -2211,7 +2208,7 @@ int security_genfs_sid(const char *fstype, u16 sclass; struct genfs *genfs; struct ocontext *c; - int rc = 0, cmp = 0; + int rc, cmp = 0; while (path[0] == '/' && path[1] == '/') path++; @@ -2219,6 +2216,7 @@ int security_genfs_sid(const char *fstype, read_lock(&policy_rwlock); sclass = unmap_class(orig_sclass); + *sid = SECINITSID_UNLABELED; for (genfs = policydb.genfs; genfs; genfs = genfs->next) { cmp = strcmp(fstype, genfs->fstype); @@ -2226,11 +2224,9 @@ int security_genfs_sid(const char *fstype, break; } - if (!genfs || cmp) { - *sid = SECINITSID_UNLABELED; - rc = -ENOENT; + rc = -ENOENT; + if (!genfs || cmp) goto out; - } for (c = genfs->head; c; c = c->next) { len = strlen(c->u.name); @@ -2239,21 +2235,18 @@ int security_genfs_sid(const char *fstype, break; } - if (!c) { - *sid = SECINITSID_UNLABELED; - rc = -ENOENT; + rc = -ENOENT; + if (!c) goto out; - } if (!c->sid[0]) { - rc = sidtab_context_to_sid(&sidtab, - &c->context[0], - &c->sid[0]); + rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } *sid = c->sid[0]; + rc = 0; out: read_unlock(&policy_rwlock); return rc; @@ -2285,8 +2278,7 @@ int security_fs_use( if (c) { *behavior = c->v.behavior; if (!c->sid[0]) { - rc = sidtab_context_to_sid(&sidtab, - &c->context[0], + rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; @@ -2309,34 +2301,39 @@ out: int security_get_bools(int *len, char ***names, int **values) { - int i, rc = -ENOMEM; + int i, rc; read_lock(&policy_rwlock); *names = NULL; *values = NULL; + rc = 0; *len = policydb.p_bools.nprim; - if (!*len) { - rc = 0; + if (!*len) goto out; - } - *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); + rc = -ENOMEM; + *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); if (!*names) goto err; - *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); + rc = -ENOMEM; + *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); if (!*values) goto err; for (i = 0; i < *len; i++) { size_t name_len; + (*values)[i] = policydb.bool_val_to_struct[i]->state; - name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; - (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); + name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1; + + rc = -ENOMEM; + (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); if (!(*names)[i]) goto err; - strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); + + strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len); (*names)[i][name_len - 1] = 0; } rc = 0; @@ -2355,24 +2352,23 @@ err: int security_set_bools(int len, int *values) { - int i, rc = 0; + int i, rc; int lenp, seqno = 0; struct cond_node *cur; write_lock_irq(&policy_rwlock); + rc = -EFAULT; lenp = policydb.p_bools.nprim; - if (len != lenp) { - rc = -EFAULT; + if (len != lenp) goto out; - } for (i = 0; i < len; i++) { if (!!values[i] != policydb.bool_val_to_struct[i]->state) { audit_log(current->audit_context, GFP_ATOMIC, AUDIT_MAC_CONFIG_CHANGE, "bool=%s val=%d old_val=%d auid=%u ses=%u", - policydb.p_bool_val_to_name[i], + sym_name(&policydb, SYM_BOOLS, i), !!values[i], policydb.bool_val_to_struct[i]->state, audit_get_loginuid(current), @@ -2391,7 +2387,7 @@ int security_set_bools(int len, int *values) } seqno = ++latest_granting; - + rc = 0; out: write_unlock_irq(&policy_rwlock); if (!rc) { @@ -2405,16 +2401,15 @@ out: int security_get_bool_value(int bool) { - int rc = 0; + int rc; int len; read_lock(&policy_rwlock); + rc = -EFAULT; len = policydb.p_bools.nprim; - if (bool >= len) { - rc = -EFAULT; + if (bool >= len) goto out; - } rc = policydb.bool_val_to_struct[bool]->state; out: @@ -2464,8 +2459,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) struct context newcon; char *s; u32 len; - int rc = 0; + int rc; + rc = 0; if (!ss_initialized || !policydb.mls_enabled) { *new_sid = sid; goto out; @@ -2474,19 +2470,20 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) context_init(&newcon); read_lock(&policy_rwlock); + + rc = -EINVAL; context1 = sidtab_search(&sidtab, sid); if (!context1) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", __func__, sid); - rc = -EINVAL; goto out_unlock; } + rc = -EINVAL; context2 = sidtab_search(&sidtab, mls_sid); if (!context2) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", __func__, mls_sid); - rc = -EINVAL; goto out_unlock; } @@ -2500,20 +2497,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) /* Check the validity of the new context. */ if (!policydb_context_isvalid(&policydb, &newcon)) { rc = convert_context_handle_invalid_context(&newcon); - if (rc) - goto bad; + if (rc) { + if (!context_struct_to_string(&newcon, &s, &len)) { + audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, + "security_sid_mls_copy: invalid context %s", s); + kfree(s); + } + goto out_unlock; + } } rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); - goto out_unlock; - -bad: - if (!context_struct_to_string(&newcon, &s, &len)) { - audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "security_sid_mls_copy: invalid context %s", s); - kfree(s); - } - out_unlock: read_unlock(&policy_rwlock); context_destroy(&newcon); @@ -2549,6 +2543,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, struct context *nlbl_ctx; struct context *xfrm_ctx; + *peer_sid = SECSID_NULL; + /* handle the common (which also happens to be the set of easy) cases * right away, these two if statements catch everything involving a * single or absent peer SID/label */ @@ -2567,40 +2563,37 @@ 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 (!policydb.mls_enabled) { - *peer_sid = SECSID_NULL; + if (!policydb.mls_enabled) return 0; - } read_lock(&policy_rwlock); + rc = -EINVAL; nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); if (!nlbl_ctx) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", __func__, nlbl_sid); - rc = -EINVAL; - goto out_slowpath; + goto out; } + rc = -EINVAL; xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); if (!xfrm_ctx) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", __func__, xfrm_sid); - rc = -EINVAL; - goto out_slowpath; + goto out; } rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); + if (rc) + goto out; -out_slowpath: + /* at present NetLabel SIDs/labels really only carry MLS + * information so if the MLS portion of the NetLabel SID + * matches the MLS portion of the labeled XFRM SID/label + * then pass along the XFRM SID as it is the most + * expressive */ + *peer_sid = xfrm_sid; +out: read_unlock(&policy_rwlock); - if (rc == 0) - /* at present NetLabel SIDs/labels really only carry MLS - * information so if the MLS portion of the NetLabel SID - * matches the MLS portion of the labeled XFRM SID/label - * then pass along the XFRM SID as it is the most - * expressive */ - *peer_sid = xfrm_sid; - else - *peer_sid = SECSID_NULL; return rc; } @@ -2619,10 +2612,11 @@ static int get_classes_callback(void *k, void *d, void *args) int security_get_classes(char ***classes, int *nclasses) { - int rc = -ENOMEM; + int rc; read_lock(&policy_rwlock); + rc = -ENOMEM; *nclasses = policydb.p_classes.nprim; *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); if (!*classes) @@ -2630,7 +2624,7 @@ int security_get_classes(char ***classes, int *nclasses) rc = hashtab_map(policydb.p_classes.table, get_classes_callback, *classes); - if (rc < 0) { + if (rc) { int i; for (i = 0; i < *nclasses; i++) kfree((*classes)[i]); @@ -2657,19 +2651,20 @@ static int get_permissions_callback(void *k, void *d, void *args) int security_get_permissions(char *class, char ***perms, int *nperms) { - int rc = -ENOMEM, i; + int rc, i; struct class_datum *match; read_lock(&policy_rwlock); + rc = -EINVAL; match = hashtab_search(policydb.p_classes.table, class); if (!match) { printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", __func__, class); - rc = -EINVAL; goto out; } + rc = -ENOMEM; *nperms = match->permissions.nprim; *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); if (!*perms) @@ -2678,13 +2673,13 @@ int security_get_permissions(char *class, char ***perms, int *nperms) if (match->comdatum) { rc = hashtab_map(match->comdatum->permissions.table, get_permissions_callback, *perms); - if (rc < 0) + if (rc) goto err; } rc = hashtab_map(match->permissions.table, get_permissions_callback, *perms); - if (rc < 0) + if (rc) goto err; out: @@ -2796,36 +2791,39 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) switch (field) { case AUDIT_SUBJ_USER: case AUDIT_OBJ_USER: + rc = -EINVAL; userdatum = hashtab_search(policydb.p_users.table, rulestr); if (!userdatum) - rc = -EINVAL; - else - tmprule->au_ctxt.user = userdatum->value; + goto out; + tmprule->au_ctxt.user = userdatum->value; break; case AUDIT_SUBJ_ROLE: case AUDIT_OBJ_ROLE: + rc = -EINVAL; roledatum = hashtab_search(policydb.p_roles.table, rulestr); if (!roledatum) - rc = -EINVAL; - else - tmprule->au_ctxt.role = roledatum->value; + goto out; + tmprule->au_ctxt.role = roledatum->value; break; case AUDIT_SUBJ_TYPE: case AUDIT_OBJ_TYPE: + rc = -EINVAL; typedatum = hashtab_search(policydb.p_types.table, rulestr); if (!typedatum) - rc = -EINVAL; - else - tmprule->au_ctxt.type = typedatum->value; + goto out; + tmprule->au_ctxt.type = typedatum->value; break; case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); + if (rc) + goto out; break; } - + rc = 0; +out: read_unlock(&policy_rwlock); if (rc) { @@ -3050,7 +3048,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, u32 *sid) { - int rc = -EIDRM; + int rc; struct context *ctx; struct context ctx_new; @@ -3061,16 +3059,15 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, read_lock(&policy_rwlock); - if (secattr->flags & NETLBL_SECATTR_CACHE) { + if (secattr->flags & NETLBL_SECATTR_CACHE) *sid = *(u32 *)secattr->cache->data; - rc = 0; - } else if (secattr->flags & NETLBL_SECATTR_SECID) { + else if (secattr->flags & NETLBL_SECATTR_SECID) *sid = secattr->attr.secid; - rc = 0; - } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { + else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { + rc = -EIDRM; ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); if (ctx == NULL) - goto netlbl_secattr_to_sid_return; + goto out; context_init(&ctx_new); ctx_new.user = ctx->user; @@ -3078,34 +3075,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, ctx_new.type = ctx->type; mls_import_netlbl_lvl(&ctx_new, secattr); if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { - if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, - secattr->attr.mls.cat) != 0) - goto netlbl_secattr_to_sid_return; + rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat, + secattr->attr.mls.cat); + if (rc) + goto out; memcpy(&ctx_new.range.level[1].cat, &ctx_new.range.level[0].cat, sizeof(ctx_new.range.level[0].cat)); } - if (mls_context_isvalid(&policydb, &ctx_new) != 1) - goto netlbl_secattr_to_sid_return_cleanup; + rc = -EIDRM; + if (!mls_context_isvalid(&policydb, &ctx_new)) + goto out_free; rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); - if (rc != 0) - goto netlbl_secattr_to_sid_return_cleanup; + if (rc) + goto out_free; security_netlbl_cache_add(secattr, *sid); ebitmap_destroy(&ctx_new.range.level[0].cat); - } else { + } else *sid = SECSID_NULL; - rc = 0; - } -netlbl_secattr_to_sid_return: read_unlock(&policy_rwlock); - return rc; -netlbl_secattr_to_sid_return_cleanup: + return 0; +out_free: ebitmap_destroy(&ctx_new.range.level[0].cat); - goto netlbl_secattr_to_sid_return; +out: + read_unlock(&policy_rwlock); + return rc; } /** @@ -3127,28 +3125,23 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) return 0; read_lock(&policy_rwlock); + + rc = -ENOENT; ctx = sidtab_search(&sidtab, sid); - if (ctx == NULL) { - rc = -ENOENT; - goto netlbl_sid_to_secattr_failure; - } - secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], + if (ctx == NULL) + goto out; + + rc = -ENOMEM; + secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1), GFP_ATOMIC); - if (secattr->domain == NULL) { - rc = -ENOMEM; - goto netlbl_sid_to_secattr_failure; - } + if (secattr->domain == NULL) + goto out; + secattr->attr.secid = sid; secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; mls_export_netlbl_lvl(ctx, secattr); rc = mls_export_netlbl_cat(ctx, secattr); - if (rc != 0) - goto netlbl_sid_to_secattr_failure; - read_unlock(&policy_rwlock); - - return 0; - -netlbl_sid_to_secattr_failure: +out: read_unlock(&policy_rwlock); return rc; } diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index e817989764cd..5840a35155fc 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -147,6 +147,17 @@ out: return rc; } +static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc) +{ + BUG_ON(loc >= SIDTAB_CACHE_LEN); + + while (loc > 0) { + s->cache[loc] = s->cache[loc - 1]; + loc--; + } + s->cache[0] = n; +} + static inline u32 sidtab_search_context(struct sidtab *s, struct context *context) { @@ -156,14 +167,33 @@ static inline u32 sidtab_search_context(struct sidtab *s, for (i = 0; i < SIDTAB_SIZE; i++) { cur = s->htable[i]; while (cur) { - if (context_cmp(&cur->context, context)) + if (context_cmp(&cur->context, context)) { + sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1); return cur->sid; + } cur = cur->next; } } return 0; } +static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context) +{ + int i; + struct sidtab_node *node; + + for (i = 0; i < SIDTAB_CACHE_LEN; i++) { + node = s->cache[i]; + if (unlikely(!node)) + return 0; + if (context_cmp(&node->context, context)) { + sidtab_update_cache(s, node, i); + return node->sid; + } + } + return 0; +} + int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *out_sid) @@ -174,7 +204,9 @@ int sidtab_context_to_sid(struct sidtab *s, *out_sid = SECSID_NULL; - sid = sidtab_search_context(s, context); + sid = sidtab_search_cache(s, context); + if (!sid) + sid = sidtab_search_context(s, context); if (!sid) { spin_lock_irqsave(&s->lock, flags); /* Rescan now that we hold the lock. */ @@ -259,12 +291,15 @@ void sidtab_destroy(struct sidtab *s) void sidtab_set(struct sidtab *dst, struct sidtab *src) { unsigned long flags; + int i; spin_lock_irqsave(&src->lock, flags); dst->htable = src->htable; dst->nel = src->nel; dst->next_sid = src->next_sid; dst->shutdown = 0; + for (i = 0; i < SIDTAB_CACHE_LEN; i++) + dst->cache[i] = NULL; spin_unlock_irqrestore(&src->lock, flags); } diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 64ea5b1cdea4..84dc154d9389 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -26,6 +26,8 @@ struct sidtab { unsigned int nel; /* number of elements */ unsigned int next_sid; /* next SID to allocate */ unsigned char shutdown; +#define SIDTAB_CACHE_LEN 3 + struct sidtab_node *cache[SIDTAB_CACHE_LEN]; spinlock_t lock; }; |