X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=security%2Fselinux%2Fss%2Fpolicydb.c;h=0111990ba8378e6ac8222817f92b188aa50ea299;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=e10ed0e1e9a9e435a7d92aa87a1db00a742dadc9;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index e10ed0e1e..0111990ba 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -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,12 +39,13 @@ static char *symtab_name[SYM_NUM] = { "roles", "types", "users", - mls_symtab_names - "bools" + "bools", + "levels", + "categories", }; #endif -int policydb_loaded_version; +int selinux_mls_enabled = 0; static unsigned int symtab_sizes[SYM_NUM] = { 2, @@ -46,8 +53,9 @@ static unsigned int symtab_sizes[SYM_NUM] = { 16, 512, 128, - mls_symtab_sizes - 16 + 16, + 16, + 16, }; struct policydb_compat_info { @@ -60,21 +68,31 @@ 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, + }, + { + .version = POLICYDB_VERSION_AVTAB, .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, @@ -85,7 +103,7 @@ static struct policydb_compat_info *policydb_lookup_compat(int version) int i; struct policydb_compat_info *info = NULL; - for (i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++) { + for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) { if (policydb_compat[i].version == version) { info = &policydb_compat[i]; break; @@ -97,18 +115,17 @@ static struct policydb_compat_info *policydb_lookup_compat(int version) /* * Initialize the role table. */ -int roles_init(struct policydb *p) +static int roles_init(struct policydb *p) { char *key = NULL; int rc; struct role_datum *role; - role = kmalloc(sizeof(*role), GFP_KERNEL); + role = kzalloc(sizeof(*role), GFP_KERNEL); if (!role) { rc = -ENOMEM; goto out; } - memset(role, 0, sizeof(*role)); role->value = ++p->p_roles.nprim; if (role->value != OBJECT_R_VAL) { rc = -EINVAL; @@ -136,7 +153,7 @@ out_free_role: /* * Initialize a policy database structure. */ -int policydb_init(struct policydb *p) +static int policydb_init(struct policydb *p) { int i, rc; @@ -254,6 +271,41 @@ static int user_index(void *key, void *datum, void *datap) 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, @@ -261,8 +313,9 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = role_index, type_index, user_index, - mls_index_f - cond_index_bool + cond_index_bool, + sens_index, + cat_index, }; /* @@ -272,7 +325,7 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = * * Caller must clean up upon failure. */ -int policydb_index_classes(struct policydb *p) +static int policydb_index_classes(struct policydb *p) { int rc; @@ -329,13 +382,15 @@ static void symtab_hash_eval(struct symtab *s) * * Caller must clean up on failure. */ -int policydb_index_others(struct policydb *p) +static int policydb_index_others(struct policydb *p) { int i, rc = 0; 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", @@ -431,6 +486,21 @@ static int class_destroy(void *key, void *datum, void *p) 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; @@ -462,7 +532,28 @@ static int user_destroy(void *key, void *datum, void *p) 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; } @@ -474,11 +565,12 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = 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) +static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); context_destroy(&c->context[1]); @@ -496,23 +588,21 @@ void policydb_destroy(struct policydb *p) struct ocontext *c, *ctmp; struct genfs *g, *gtmp; int i; + struct role_allow *ra, *lra = NULL; + struct role_trans *tr, *ltr = NULL; + struct range_trans *rt, *lrt = NULL; for (i = 0; i < SYM_NUM; i++) { hashtab_map(p->symtab[i].table, destroy_f[i], NULL); hashtab_destroy(p->symtab[i].table); } - for (i = 0; i < SYM_NUM; i++) { - if (p->sym_val_to_name[i]) - kfree(p->sym_val_to_name[i]); - } + for (i = 0; i < SYM_NUM; i++) + kfree(p->sym_val_to_name[i]); - if (p->class_val_to_struct) - kfree(p->class_val_to_struct); - if (p->role_val_to_struct) - kfree(p->role_val_to_struct); - if (p->user_val_to_struct) - kfree(p->user_val_to_struct); + kfree(p->class_val_to_struct); + kfree(p->role_val_to_struct); + kfree(p->user_val_to_struct); avtab_destroy(&p->te_avtab); @@ -541,6 +631,30 @@ void policydb_destroy(struct policydb *p) cond_policydb_destroy(p); + for (tr = p->role_tr; tr; tr = tr->next) { + kfree(ltr); + ltr = tr; + } + kfree(ltr); + + for (ra = p->role_allow; ra; ra = ra -> next) { + kfree(lra); + lra = ra; + } + kfree(lra); + + for (rt = p->range_tr; rt; rt = rt -> next) { + kfree(lrt); + lrt = rt; + } + kfree(lrt); + + if (p->type_attr_map) { + for (i = 0; i < p->p_types.nprim; i++) + ebitmap_destroy(&p->type_attr_map[i]); + } + kfree(p->type_attr_map); + return; } @@ -625,6 +739,66 @@ int policydb_context_isvalid(struct policydb *p, struct context *c) return 1; } +/* + * Read a MLS range structure from a policydb binary + * representation file. + */ +static int mls_read_range_helper(struct mls_range *r, void *fp) +{ + __le32 buf[2]; + u32 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. @@ -633,23 +807,24 @@ static int context_read_and_validate(struct context *c, struct policydb *p, void *fp) { - u32 *buf; - int rc = 0; + __le32 buf[3]; + int rc; - buf = next_entry(fp, sizeof(u32)*3); - if (!buf) { + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) { printk(KERN_ERR "security: context truncated\n"); - rc = -EINVAL; goto out; } 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)) { @@ -672,38 +847,30 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) char *key = NULL; struct perm_datum *perdatum; int rc; - u32 *buf, len; + __le32 buf[2]; + u32 len; - perdatum = kmalloc(sizeof(*perdatum), GFP_KERNEL); + perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL); if (!perdatum) { rc = -ENOMEM; goto out; } - memset(perdatum, 0, sizeof(*perdatum)); - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); perdatum->value = le32_to_cpu(buf[1]); - rc = mls_read_perm(perdatum, fp); - if (rc) - goto bad; - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; rc = hashtab_insert(h, key, perdatum); @@ -720,21 +887,19 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) { char *key = NULL; struct common_datum *comdatum; - u32 *buf, len, nel; + __le32 buf[4]; + u32 len, nel; int i, rc; - comdatum = kmalloc(sizeof(*comdatum), GFP_KERNEL); + comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL); if (!comdatum) { rc = -ENOMEM; goto out; } - memset(comdatum, 0, sizeof(*comdatum)); - buf = next_entry(fp, sizeof(u32)*4); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); comdatum->value = le32_to_cpu(buf[1]); @@ -745,17 +910,14 @@ 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]); - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; for (i = 0; i < nel; i++) { @@ -774,27 +936,107 @@ 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; + __le32 buf[3]; + u32 nexpr; + int rc, i, j, depth; + + lc = NULL; + for (i = 0; i < ncons; i++) { + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + 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 = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return -ENOMEM; + + 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, len, len2, ncons, nexpr, nel; - int i, j, depth, rc; + __le32 buf[6]; + u32 len, len2, ncons, nel; + int i, rc; - cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL); + cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL); if (!cladatum) { rc = -ENOMEM; - goto bad; + goto out; } - memset(cladatum, 0, sizeof(*cladatum)); - buf = next_entry(fp, sizeof(u32)*6); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)*6); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); len2 = le32_to_cpu(buf[1]); @@ -808,17 +1050,14 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ncons = le32_to_cpu(buf[5]); - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; if (len2) { @@ -827,12 +1066,9 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) rc = -ENOMEM; goto bad; } - buf = next_entry(fp, len2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(cladatum->comkey, fp, len2); + if (rc < 0) goto bad; - } - memcpy(cladatum->comkey, buf, len2); cladatum->comkey[len2] = 0; cladatum->comdatum = hashtab_search(p->p_commons.table, @@ -850,90 +1086,26 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) goto bad; } - lc = NULL; - rc = -EINVAL; - 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; - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) + 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; - } - - buf = next_entry(fp, sizeof(u32)*3); - if (!buf) - goto bad; - 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) - 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; + + rc = 0; out: return rc; bad: @@ -946,35 +1118,30 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) char *key = NULL; struct role_datum *role; int rc; - u32 *buf, len; + __le32 buf[2]; + u32 len; - role = kmalloc(sizeof(*role), GFP_KERNEL); + role = kzalloc(sizeof(*role), GFP_KERNEL); if (!role) { rc = -ENOMEM; goto out; } - memset(role, 0, sizeof(*role)); - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); role->value = le32_to_cpu(buf[1]); - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; rc = ebitmap_read(&role->dominates, fp); @@ -1011,36 +1178,31 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) char *key = NULL; struct type_datum *typdatum; int rc; - u32 *buf, len; + __le32 buf[3]; + u32 len; - typdatum = kmalloc(sizeof(*typdatum),GFP_KERNEL); + typdatum = kzalloc(sizeof(*typdatum),GFP_KERNEL); if (!typdatum) { rc = -ENOMEM; return rc; } - memset(typdatum, 0, sizeof(*typdatum)); - buf = next_entry(fp, sizeof(u32)*3); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); typdatum->value = le32_to_cpu(buf[1]); typdatum->primary = le32_to_cpu(buf[2]); - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; rc = hashtab_insert(h, key, typdatum); @@ -1053,50 +1215,79 @@ 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) +{ + __le32 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; struct user_datum *usrdatum; int rc; - u32 *buf, len; - + __le32 buf[2]; + u32 len; - usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL); + usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); if (!usrdatum) { rc = -ENOMEM; goto out; } - memset(usrdatum, 0, sizeof(*usrdatum)); - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof buf); + if (rc < 0) goto bad; - } len = le32_to_cpu(buf[0]); usrdatum->value = le32_to_cpu(buf[1]); - buf = next_entry(fp, len); - if (!buf) { - rc = -EINVAL; - goto bad; - } key = kmalloc(len + 1,GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; } - memcpy(key, buf, len); + rc = next_entry(key, fp, len); + if (rc < 0) + goto bad; key[len] = 0; rc = ebitmap_read(&usrdatum->roles, fp); 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) @@ -1108,6 +1299,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; + __le32 buf[2]; + u32 len; + + levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC); + if (!levdatum) { + rc = -ENOMEM; + goto out; + } + + 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; + __le32 buf[3]; + u32 len; + + catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC); + if (!catdatum) { + rc = -ENOMEM; + goto out; + } + + 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, @@ -1115,12 +1400,12 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) 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 @@ -1132,46 +1417,38 @@ int policydb_read(struct policydb *p, void *fp) struct role_trans *tr, *ltr; struct ocontext *l, *c, *newc; struct genfs *genfs_p, *genfs, *newgenfs; - int i, j, rc, r_policyvers = 0; - u32 *buf, len, len2, config, nprim, nel, nel2; + int i, j, rc; + __le32 buf[8]; + u32 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) goto out; - rc = -EINVAL; /* Read the magic number and string length. */ - buf = next_entry(fp, sizeof(u32)* 2); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)* 2); + if (rc < 0) goto bad; - for (i = 0; i < 2; i++) - buf[i] = le32_to_cpu(buf[i]); - - if (buf[0] != POLICYDB_MAGIC) { + if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) { printk(KERN_ERR "security: policydb magic number 0x%x does " "not match expected magic number 0x%x\n", - buf[0], POLICYDB_MAGIC); + le32_to_cpu(buf[0]), POLICYDB_MAGIC); goto bad; } - len = buf[1]; + len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_STRING)) { printk(KERN_ERR "security: policydb string length %d does not " "match expected length %Zu\n", len, strlen(POLICYDB_STRING)); goto bad; } - buf = next_entry(fp, len); - if (!buf) { - printk(KERN_ERR "security: truncated policydb string identifier\n"); - goto bad; - } policydb_str = kmalloc(len + 1,GFP_KERNEL); if (!policydb_str) { printk(KERN_ERR "security: unable to allocate memory for policydb " @@ -1179,7 +1456,12 @@ int policydb_read(struct policydb *p, void *fp) rc = -ENOMEM; goto bad; } - memcpy(policydb_str, buf, len); + rc = next_entry(policydb_str, fp, len); + if (rc < 0) { + printk(KERN_ERR "security: truncated policydb string identifier\n"); + kfree(policydb_str); + goto bad; + } policydb_str[len] = 0; if (strcmp(policydb_str, POLICYDB_STRING)) { printk(KERN_ERR "security: policydb string %s does not match " @@ -1192,54 +1474,61 @@ int policydb_read(struct policydb *p, void *fp) policydb_str = NULL; /* Read the version, config, and table sizes. */ - buf = next_entry(fp, sizeof(u32)*4); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)*4); + if (rc < 0) goto bad; - for (i = 0; i < 4; i++) - buf[i] = le32_to_cpu(buf[i]); - r_policyvers = buf[0]; - if (r_policyvers < POLICYDB_VERSION_MIN || - r_policyvers > POLICYDB_VERSION_MAX) { + p->policyvers = le32_to_cpu(buf[0]); + if (p->policyvers < POLICYDB_VERSION_MIN || + p->policyvers > POLICYDB_VERSION_MAX) { printk(KERN_ERR "security: policydb version %d does not match " "my version range %d-%d\n", - buf[0], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); + le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); 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 ((le32_to_cpu(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(r_policyvers); + info = policydb_lookup_compat(p->policyvers); if (!info) { printk(KERN_ERR "security: unable to find policy compat info " - "for version %d\n", r_policyvers); + "for version %d\n", p->policyvers); goto bad; } - if (buf[2] != info->sym_num || buf[3] != info->ocon_num) { + if (le32_to_cpu(buf[2]) != info->sym_num || + le32_to_cpu(buf[3]) != info->ocon_num) { printk(KERN_ERR "security: policydb table sizes (%d,%d) do " - "not match mine (%d,%d)\n", buf[2], buf[3], + "not match mine (%d,%d)\n", le32_to_cpu(buf[2]), + le32_to_cpu(buf[3]), info->sym_num, info->ocon_num); goto bad; } - rc = mls_read_nlevels(p, fp); - if (rc) - goto bad; - for (i = 0; i < info->sym_num; i++) { - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)*2); + if (rc < 0) goto bad; - } nprim = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[1]); for (j = 0; j < nel; j++) { @@ -1251,70 +1540,60 @@ int policydb_read(struct policydb *p, void *fp) p->symtab[i].nprim = nprim; } - rc = avtab_read(&p->te_avtab, fp, config); + rc = avtab_read(&p->te_avtab, fp, p->policyvers); if (rc) goto bad; - if (r_policyvers >= POLICYDB_VERSION_BOOL) { + if (p->policyvers >= POLICYDB_VERSION_BOOL) { rc = cond_read_list(p, fp); if (rc) goto bad; } - buf = next_entry(fp, sizeof(u32)); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; - } nel = le32_to_cpu(buf[0]); ltr = NULL; for (i = 0; i < nel; i++) { - tr = kmalloc(sizeof(*tr), GFP_KERNEL); + tr = kzalloc(sizeof(*tr), GFP_KERNEL); if (!tr) { rc = -ENOMEM; goto bad; } - memset(tr, 0, sizeof(*tr)); if (ltr) { ltr->next = tr; } else { p->role_tr = tr; } - buf = next_entry(fp, sizeof(u32)*3); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)*3); + if (rc < 0) goto bad; - } tr->role = le32_to_cpu(buf[0]); tr->type = le32_to_cpu(buf[1]); tr->new_role = le32_to_cpu(buf[2]); ltr = tr; } - buf = next_entry(fp, sizeof(u32)); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; - } nel = le32_to_cpu(buf[0]); lra = NULL; for (i = 0; i < nel; i++) { - ra = kmalloc(sizeof(*ra), GFP_KERNEL); + ra = kzalloc(sizeof(*ra), GFP_KERNEL); if (!ra) { rc = -ENOMEM; goto bad; } - memset(ra, 0, sizeof(*ra)); if (lra) { lra->next = ra; } else { p->role_allow = ra; } - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)*2); + if (rc < 0) goto bad; - } ra->role = le32_to_cpu(buf[0]); ra->new_role = le32_to_cpu(buf[1]); lra = ra; @@ -1329,20 +1608,17 @@ int policydb_read(struct policydb *p, void *fp) goto bad; for (i = 0; i < info->ocon_num; i++) { - buf = next_entry(fp, sizeof(u32)); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; - } nel = le32_to_cpu(buf[0]); l = NULL; for (j = 0; j < nel; j++) { - c = kmalloc(sizeof(*c), GFP_KERNEL); + c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) { rc = -ENOMEM; goto bad; } - memset(c, 0, sizeof(*c)); if (l) { l->next = c; } else { @@ -1352,8 +1628,8 @@ int policydb_read(struct policydb *p, void *fp) rc = -EINVAL; switch (i) { case OCON_ISID: - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; c->sid[0] = le32_to_cpu(buf[0]); rc = context_read_and_validate(&c->context[0], p, fp); @@ -1362,19 +1638,18 @@ int policydb_read(struct policydb *p, void *fp) break; case OCON_FS: case OCON_NETIF: - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); - buf = next_entry(fp, len); - if (!buf) - goto bad; c->u.name = kmalloc(len + 1,GFP_KERNEL); if (!c->u.name) { rc = -ENOMEM; goto bad; } - memcpy(c->u.name, buf, len); + rc = next_entry(c->u.name, fp, len); + if (rc < 0) + goto bad; c->u.name[len] = 0; rc = context_read_and_validate(&c->context[0], p, fp); if (rc) @@ -1384,8 +1659,8 @@ int policydb_read(struct policydb *p, void *fp) goto bad; break; case OCON_PORT: - buf = next_entry(fp, sizeof(u32)*3); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)*3); + if (rc < 0) goto bad; c->u.port.protocol = le32_to_cpu(buf[0]); c->u.port.low_port = le32_to_cpu(buf[1]); @@ -1395,8 +1670,8 @@ int policydb_read(struct policydb *p, void *fp) goto bad; break; case OCON_NODE: - buf = next_entry(fp, sizeof(u32)* 2); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)* 2); + if (rc < 0) goto bad; c->u.node.addr = le32_to_cpu(buf[0]); c->u.node.mask = le32_to_cpu(buf[1]); @@ -1405,22 +1680,21 @@ int policydb_read(struct policydb *p, void *fp) goto bad; break; case OCON_FSUSE: - buf = next_entry(fp, sizeof(u32)*2); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)*2); + if (rc < 0) goto bad; c->v.behavior = le32_to_cpu(buf[0]); if (c->v.behavior > SECURITY_FS_USE_NONE) goto bad; len = le32_to_cpu(buf[1]); - buf = next_entry(fp, len); - if (!buf) - goto bad; c->u.name = kmalloc(len + 1,GFP_KERNEL); if (!c->u.name) { rc = -ENOMEM; goto bad; } - memcpy(c->u.name, buf, len); + rc = next_entry(c->u.name, fp, len); + if (rc < 0) + goto bad; c->u.name[len] = 0; rc = context_read_and_validate(&c->context[0], p, fp); if (rc) @@ -1429,8 +1703,8 @@ int policydb_read(struct policydb *p, void *fp) case OCON_NODE6: { int k; - buf = next_entry(fp, sizeof(u32) * 8); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32) * 8); + if (rc < 0) goto bad; for (k = 0; k < 4; k++) c->u.node6.addr[k] = le32_to_cpu(buf[k]); @@ -1444,28 +1718,22 @@ int policydb_read(struct policydb *p, void *fp) } } - buf = next_entry(fp, sizeof(u32)); - if (!buf) { - rc = -EINVAL; + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; - } nel = le32_to_cpu(buf[0]); genfs_p = NULL; rc = -EINVAL; for (i = 0; i < nel; i++) { - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); - buf = next_entry(fp, len); - if (!buf) - goto bad; - newgenfs = kmalloc(sizeof(*newgenfs), GFP_KERNEL); + newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL); if (!newgenfs) { rc = -ENOMEM; goto bad; } - memset(newgenfs, 0, sizeof(*newgenfs)); newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL); if (!newgenfs->fstype) { @@ -1473,7 +1741,12 @@ int policydb_read(struct policydb *p, void *fp) kfree(newgenfs); goto bad; } - memcpy(newgenfs->fstype, buf, len); + rc = next_entry(newgenfs->fstype, fp, len); + if (rc < 0) { + kfree(newgenfs->fstype); + kfree(newgenfs); + goto bad; + } newgenfs->fstype[len] = 0; for (genfs_p = NULL, genfs = p->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { @@ -1492,35 +1765,33 @@ int policydb_read(struct policydb *p, void *fp) genfs_p->next = newgenfs; else p->genfs = newgenfs; - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; nel2 = le32_to_cpu(buf[0]); for (j = 0; j < nel2; j++) { - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); - buf = next_entry(fp, len); - if (!buf) - goto bad; - newc = kmalloc(sizeof(*newc), GFP_KERNEL); + newc = kzalloc(sizeof(*newc), GFP_KERNEL); if (!newc) { rc = -ENOMEM; goto bad; } - memset(newc, 0, sizeof(*newc)); newc->u.name = kmalloc(len + 1,GFP_KERNEL); if (!newc->u.name) { rc = -ENOMEM; goto bad_newc; } - memcpy(newc->u.name, buf, len); + rc = next_entry(newc->u.name, fp, len); + if (rc < 0) + goto bad_newc; newc->u.name[len] = 0; - buf = next_entry(fp, sizeof(u32)); - if (!buf) + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) goto bad_newc; newc->v.sclass = le32_to_cpu(buf[0]); if (context_read_and_validate(&newc->context[0], p, fp)) @@ -1549,15 +1820,57 @@ int policydb_read(struct policydb *p, void *fp) } } - rc = mls_read_trusted(p, fp); - if (rc) + 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 = kzalloc(sizeof(*rt), GFP_KERNEL); + if (!rt) { + rc = -ENOMEM; + goto bad; + } + if (lrt) + lrt->next = rt; + else + p->range_tr = rt; + rc = next_entry(buf, fp, (sizeof(u32) * 2)); + if (rc < 0) + 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; + } + } + + p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); + if (!p->type_attr_map) goto bad; + + for (i = 0; i < p->p_types.nprim; i++) { + ebitmap_init(&p->type_attr_map[i]); + if (p->policyvers >= POLICYDB_VERSION_AVTAB) { + if (ebitmap_read(&p->type_attr_map[i], fp)) + goto bad; + } + /* add the type itself as the degenerate case */ + if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) + goto bad; + } + + rc = 0; out: - policydb_loaded_version = r_policyvers; return rc; bad_newc: ocontext_destroy(newc,OCON_FSUSE); bad: + if (!rc) + rc = -EINVAL; policydb_destroy(p); goto out; }