From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/security/selinux/ss/policydb.c | 1617 +++++++++++++++++++++++++++++++++-------------------------- 1 files changed, 891 insertions(+), 726 deletions(-) diff --git a/kernel/security/selinux/ss/policydb.c b/kernel/security/selinux/ss/policydb.c index 3e68f93..ef30a84 100644 --- a/kernel/security/selinux/ss/policydb.c +++ b/kernel/security/selinux/ss/policydb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of the policy database. * @@ -25,9 +26,6 @@ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * 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 - * the Free Software Foundation, version 2. */ #include <linux/kernel.h> @@ -36,7 +34,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/audit.h> -#include <linux/flex_array.h> #include "security.h" #include "policydb.h" @@ -58,17 +55,6 @@ "categories", }; #endif - -static unsigned int symtab_sizes[SYM_NUM] = { - 2, - 32, - 16, - 512, - 128, - 16, - 16, - 16, -}; struct policydb_compat_info { int version; @@ -163,6 +149,16 @@ .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_GLBLUB, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_COMP_FTRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static struct policydb_compat_info *policydb_lookup_compat(int version) @@ -177,437 +173,6 @@ } } return info; -} - -/* - * Initialize the role table. - */ -static int roles_init(struct policydb *p) -{ - char *key = NULL; - int rc; - struct role_datum *role; - - role = kzalloc(sizeof(*role), GFP_KERNEL); - if (!role) - return -ENOMEM; - - rc = -EINVAL; - role->value = ++p->p_roles.nprim; - if (role->value != OBJECT_R_VAL) - goto out; - - rc = -ENOMEM; - key = kstrdup(OBJECT_R, GFP_KERNEL); - if (!key) - goto out; - - rc = hashtab_insert(p->p_roles.table, key, role); - if (rc) - goto out; - - return 0; -out: - kfree(key); - kfree(role); - return rc; -} - -static u32 filenametr_hash(struct hashtab *h, const void *k) -{ - const struct filename_trans *ft = k; - unsigned long hash; - unsigned int byte_num; - unsigned char focus; - - hash = ft->stype ^ ft->ttype ^ ft->tclass; - - byte_num = 0; - while ((focus = ft->name[byte_num++])) - hash = partial_name_hash(focus, hash); - return hash & (h->size - 1); -} - -static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) -{ - const struct filename_trans *ft1 = k1; - const struct filename_trans *ft2 = k2; - int v; - - v = ft1->stype - ft2->stype; - if (v) - return v; - - v = ft1->ttype - ft2->ttype; - if (v) - return v; - - v = ft1->tclass - ft2->tclass; - if (v) - return v; - - return strcmp(ft1->name, ft2->name); - -} - -static u32 rangetr_hash(struct hashtab *h, const void *k) -{ - const struct range_trans *key = k; - return (key->source_type + (key->target_type << 3) + - (key->target_class << 5)) & (h->size - 1); -} - -static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) -{ - const struct range_trans *key1 = k1, *key2 = k2; - int v; - - v = key1->source_type - key2->source_type; - if (v) - return v; - - v = key1->target_type - key2->target_type; - if (v) - return v; - - v = key1->target_class - key2->target_class; - - return v; -} - -static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap); - -/* - * Initialize a policy database structure. - */ -static int policydb_init(struct policydb *p) -{ - int i, rc; - - memset(p, 0, sizeof(*p)); - - for (i = 0; i < SYM_NUM; i++) { - rc = symtab_init(&p->symtab[i], symtab_sizes[i]); - if (rc) - goto out; - } - - rc = avtab_init(&p->te_avtab); - if (rc) - goto out; - - rc = roles_init(p); - if (rc) - goto out; - - rc = cond_policydb_init(p); - if (rc) - goto out; - - p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); - if (!p->filename_trans) { - rc = -ENOMEM; - goto out; - } - - p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); - if (!p->range_tr) { - rc = -ENOMEM; - goto out; - } - - ebitmap_init(&p->filename_trans_ttypes); - ebitmap_init(&p->policycaps); - ebitmap_init(&p->permissive_map); - - return 0; -out: - hashtab_destroy(p->filename_trans); - hashtab_destroy(p->range_tr); - for (i = 0; i < SYM_NUM; i++) { - hashtab_map(p->symtab[i].table, destroy_f[i], NULL); - hashtab_destroy(p->symtab[i].table); - } - return rc; -} - -/* - * The following *_index functions are used to - * define the val_to_name and val_to_struct arrays - * in a policy database structure. The val_to_name - * arrays are used when converting security context - * structures into string representations. The - * val_to_struct arrays are used when the attributes - * of a class, role, or user are needed. - */ - -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; - - 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; -} - -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; - 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; -} - -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; - if (!role->value - || role->value > p->p_roles.nprim - || role->bounds > p->p_roles.nprim) - return -EINVAL; - - 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; -} - -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; - - if (typdatum->primary) { - if (!typdatum->value - || typdatum->value > p->p_types.nprim - || typdatum->bounds > p->p_types.nprim) - return -EINVAL; - 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; -} - -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; - if (!usrdatum->value - || usrdatum->value > p->p_users.nprim - || usrdatum->bounds > p->p_users.nprim) - return -EINVAL; - - 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; -} - -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; - - if (!levdatum->isalias) { - if (!levdatum->level->sens || - levdatum->level->sens > p->p_levels.nprim) - return -EINVAL; - 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; -} - -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; - - if (!catdatum->isalias) { - if (!catdatum->value || catdatum->value > p->p_cats.nprim) - return -EINVAL; - 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; -} - -static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = -{ - common_index, - class_index, - role_index, - type_index, - user_index, - cond_index_bool, - sens_index, - cat_index, -}; - -#ifdef DEBUG_HASHES -static void hash_eval(struct hashtab *h, const char *hash_name) -{ - struct hashtab_info info; - - hashtab_stat(h, &info); - pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " - "longest chain length %d\n", hash_name, h->nel, - info.slots_used, h->size, info.max_chain_len); -} - -static void symtab_hash_eval(struct symtab *s) -{ - int i; - - for (i = 0; i < SYM_NUM; i++) - hash_eval(s[i].table, symtab_name[i]); -} - -#else -static inline void hash_eval(struct hashtab *h, char *hash_name) -{ -} -#endif - -/* - * Define the other val_to_name and val_to_struct arrays - * in a policy database structure. - * - * Caller must clean up on failure. - */ -static int policydb_index(struct policydb *p) -{ - int i, rc; - - if (p->mls_enabled) - pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", - p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, - p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); - else - pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n", - p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, - p->p_bools.nprim); - - pr_debug("SELinux: %d classes, %d rules\n", - p->p_classes.nprim, p->te_avtab.nel); - -#ifdef DEBUG_HASHES - avtab_hash_eval(&p->te_avtab, "rules"); - symtab_hash_eval(p->symtab); -#endif - - p->class_val_to_struct = kcalloc(p->p_classes.nprim, - sizeof(*p->class_val_to_struct), - GFP_KERNEL); - if (!p->class_val_to_struct) - return -ENOMEM; - - p->role_val_to_struct = kcalloc(p->p_roles.nprim, - sizeof(*p->role_val_to_struct), - GFP_KERNEL); - if (!p->role_val_to_struct) - return -ENOMEM; - - p->user_val_to_struct = kcalloc(p->p_users.nprim, - sizeof(*p->user_val_to_struct), - GFP_KERNEL); - if (!p->user_val_to_struct) - return -ENOMEM; - - /* Yes, I want the sizeof the pointer, not the structure */ - 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) - return -ENOMEM; - - rc = flex_array_prealloc(p->type_val_to_struct_array, 0, - p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); - if (rc) - goto out; - - rc = cond_init_bool_indexes(p); - if (rc) - goto out; - - for (i = 0; i < SYM_NUM; i++) { - 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]) - return -ENOMEM; - - rc = flex_array_prealloc(p->sym_val_to_name[i], - 0, p->symtab[i].nprim, - 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; } /* @@ -630,8 +195,8 @@ kfree(key); if (datum) { comdatum = datum; - hashtab_map(comdatum->permissions.table, perm_destroy, NULL); - hashtab_destroy(comdatum->permissions.table); + hashtab_map(&comdatum->permissions.table, perm_destroy, NULL); + hashtab_destroy(&comdatum->permissions.table); } kfree(datum); return 0; @@ -659,8 +224,8 @@ kfree(key); if (datum) { cladatum = datum; - hashtab_map(cladatum->permissions.table, perm_destroy, NULL); - hashtab_destroy(cladatum->permissions.table); + hashtab_map(&cladatum->permissions.table, perm_destroy, NULL); + hashtab_destroy(&cladatum->permissions.table); constraint = cladatum->constraints; while (constraint) { e = constraint->expr; @@ -765,10 +330,17 @@ static int filenametr_destroy(void *key, void *datum, void *p) { - struct filename_trans *ft = key; + struct filename_trans_key *ft = key; + struct filename_trans_datum *next, *d = datum; + kfree(ft->name); kfree(key); - kfree(datum); + do { + ebitmap_destroy(&d->stypes); + next = d->next; + kfree(d); + d = next; + } while (unlikely(d)); cond_resched(); return 0; } @@ -776,11 +348,19 @@ static int range_tr_destroy(void *key, void *datum, void *p) { struct mls_range *rt = datum; + kfree(key); ebitmap_destroy(&rt->level[0].cat); ebitmap_destroy(&rt->level[1].cat); kfree(datum); cond_resched(); + return 0; +} + +static int role_tr_destroy(void *key, void *datum, void *p) +{ + kfree(key); + kfree(datum); return 0; } @@ -798,6 +378,409 @@ } /* + * Initialize the role table. + */ +static int roles_init(struct policydb *p) +{ + char *key = NULL; + int rc; + struct role_datum *role; + + role = kzalloc(sizeof(*role), GFP_KERNEL); + if (!role) + return -ENOMEM; + + rc = -EINVAL; + role->value = ++p->p_roles.nprim; + if (role->value != OBJECT_R_VAL) + goto out; + + rc = -ENOMEM; + key = kstrdup(OBJECT_R, GFP_KERNEL); + if (!key) + goto out; + + rc = symtab_insert(&p->p_roles, key, role); + if (rc) + goto out; + + return 0; +out: + kfree(key); + kfree(role); + return rc; +} + +static u32 filenametr_hash(const void *k) +{ + const struct filename_trans_key *ft = k; + unsigned long hash; + unsigned int byte_num; + unsigned char focus; + + hash = ft->ttype ^ ft->tclass; + + byte_num = 0; + while ((focus = ft->name[byte_num++])) + hash = partial_name_hash(focus, hash); + return hash; +} + +static int filenametr_cmp(const void *k1, const void *k2) +{ + const struct filename_trans_key *ft1 = k1; + const struct filename_trans_key *ft2 = k2; + int v; + + v = ft1->ttype - ft2->ttype; + if (v) + return v; + + v = ft1->tclass - ft2->tclass; + if (v) + return v; + + return strcmp(ft1->name, ft2->name); + +} + +static const struct hashtab_key_params filenametr_key_params = { + .hash = filenametr_hash, + .cmp = filenametr_cmp, +}; + +struct filename_trans_datum *policydb_filenametr_search( + struct policydb *p, struct filename_trans_key *key) +{ + return hashtab_search(&p->filename_trans, key, filenametr_key_params); +} + +static u32 rangetr_hash(const void *k) +{ + const struct range_trans *key = k; + + return key->source_type + (key->target_type << 3) + + (key->target_class << 5); +} + +static int rangetr_cmp(const void *k1, const void *k2) +{ + const struct range_trans *key1 = k1, *key2 = k2; + int v; + + v = key1->source_type - key2->source_type; + if (v) + return v; + + v = key1->target_type - key2->target_type; + if (v) + return v; + + v = key1->target_class - key2->target_class; + + return v; +} + +static const struct hashtab_key_params rangetr_key_params = { + .hash = rangetr_hash, + .cmp = rangetr_cmp, +}; + +struct mls_range *policydb_rangetr_search(struct policydb *p, + struct range_trans *key) +{ + return hashtab_search(&p->range_tr, key, rangetr_key_params); +} + +static u32 role_trans_hash(const void *k) +{ + const struct role_trans_key *key = k; + + return key->role + (key->type << 3) + (key->tclass << 5); +} + +static int role_trans_cmp(const void *k1, const void *k2) +{ + const struct role_trans_key *key1 = k1, *key2 = k2; + int v; + + v = key1->role - key2->role; + if (v) + return v; + + v = key1->type - key2->type; + if (v) + return v; + + return key1->tclass - key2->tclass; +} + +static const struct hashtab_key_params roletr_key_params = { + .hash = role_trans_hash, + .cmp = role_trans_cmp, +}; + +struct role_trans_datum *policydb_roletr_search(struct policydb *p, + struct role_trans_key *key) +{ + return hashtab_search(&p->role_tr, key, roletr_key_params); +} + +/* + * Initialize a policy database structure. + */ +static void policydb_init(struct policydb *p) +{ + memset(p, 0, sizeof(*p)); + + avtab_init(&p->te_avtab); + cond_policydb_init(p); + + ebitmap_init(&p->filename_trans_ttypes); + ebitmap_init(&p->policycaps); + ebitmap_init(&p->permissive_map); +} + +/* + * The following *_index functions are used to + * define the val_to_name and val_to_struct arrays + * in a policy database structure. The val_to_name + * arrays are used when converting security context + * structures into string representations. The + * val_to_struct arrays are used when the attributes + * of a class, role, or user are needed. + */ + +static int common_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct common_datum *comdatum; + + comdatum = datum; + p = datap; + if (!comdatum->value || comdatum->value > p->p_commons.nprim) + return -EINVAL; + + p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key; + + return 0; +} + +static int class_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct class_datum *cladatum; + + cladatum = datum; + p = datap; + if (!cladatum->value || cladatum->value > p->p_classes.nprim) + return -EINVAL; + + p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key; + p->class_val_to_struct[cladatum->value - 1] = cladatum; + return 0; +} + +static int role_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct role_datum *role; + + role = datum; + p = datap; + if (!role->value + || role->value > p->p_roles.nprim + || role->bounds > p->p_roles.nprim) + return -EINVAL; + + p->sym_val_to_name[SYM_ROLES][role->value - 1] = key; + p->role_val_to_struct[role->value - 1] = role; + return 0; +} + +static int type_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct type_datum *typdatum; + + typdatum = datum; + p = datap; + + if (typdatum->primary) { + if (!typdatum->value + || typdatum->value > p->p_types.nprim + || typdatum->bounds > p->p_types.nprim) + return -EINVAL; + p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key; + p->type_val_to_struct[typdatum->value - 1] = typdatum; + } + + return 0; +} + +static int user_index(void *key, void *datum, void *datap) +{ + struct policydb *p; + struct user_datum *usrdatum; + + usrdatum = datum; + p = datap; + if (!usrdatum->value + || usrdatum->value > p->p_users.nprim + || usrdatum->bounds > p->p_users.nprim) + return -EINVAL; + + p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key; + p->user_val_to_struct[usrdatum->value - 1] = usrdatum; + 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->sym_val_to_name[SYM_LEVELS][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->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key; + } + + return 0; +} + +static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = +{ + common_index, + class_index, + role_index, + type_index, + user_index, + cond_index_bool, + sens_index, + cat_index, +}; + +#ifdef DEBUG_HASHES +static void hash_eval(struct hashtab *h, const char *hash_name) +{ + struct hashtab_info info; + + hashtab_stat(h, &info); + pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n", + hash_name, h->nel, info.slots_used, h->size, + info.max_chain_len); +} + +static void symtab_hash_eval(struct symtab *s) +{ + int i; + + for (i = 0; i < SYM_NUM; i++) + hash_eval(&s[i].table, symtab_name[i]); +} + +#else +static inline void hash_eval(struct hashtab *h, char *hash_name) +{ +} +#endif + +/* + * Define the other val_to_name and val_to_struct arrays + * in a policy database structure. + * + * Caller must clean up on failure. + */ +static int policydb_index(struct policydb *p) +{ + int i, rc; + + if (p->mls_enabled) + pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", + p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, + p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); + else + pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n", + p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, + p->p_bools.nprim); + + pr_debug("SELinux: %d classes, %d rules\n", + p->p_classes.nprim, p->te_avtab.nel); + +#ifdef DEBUG_HASHES + avtab_hash_eval(&p->te_avtab, "rules"); + symtab_hash_eval(p->symtab); +#endif + + p->class_val_to_struct = kcalloc(p->p_classes.nprim, + sizeof(*p->class_val_to_struct), + GFP_KERNEL); + if (!p->class_val_to_struct) + return -ENOMEM; + + p->role_val_to_struct = kcalloc(p->p_roles.nprim, + sizeof(*p->role_val_to_struct), + GFP_KERNEL); + if (!p->role_val_to_struct) + return -ENOMEM; + + p->user_val_to_struct = kcalloc(p->p_users.nprim, + sizeof(*p->user_val_to_struct), + GFP_KERNEL); + if (!p->user_val_to_struct) + return -ENOMEM; + + p->type_val_to_struct = kvcalloc(p->p_types.nprim, + sizeof(*p->type_val_to_struct), + GFP_KERNEL); + if (!p->type_val_to_struct) + return -ENOMEM; + + rc = cond_init_bool_indexes(p); + if (rc) + goto out; + + for (i = 0; i < SYM_NUM; i++) { + p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim, + sizeof(char *), + GFP_KERNEL); + if (!p->sym_val_to_name[i]) + return -ENOMEM; + + rc = hashtab_map(&p->symtab[i].table, index_f[i], p); + if (rc) + goto out; + } + rc = 0; +out: + return rc; +} + +/* * Free any memory allocated by a policy database structure. */ void policydb_destroy(struct policydb *p) @@ -806,24 +789,20 @@ struct genfs *g, *gtmp; int i; struct role_allow *ra, *lra = NULL; - struct role_trans *tr, *ltr = NULL; for (i = 0; i < SYM_NUM; i++) { cond_resched(); - hashtab_map(p->symtab[i].table, destroy_f[i], NULL); - hashtab_destroy(p->symtab[i].table); + 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]) - flex_array_free(p->sym_val_to_name[i]); - } + for (i = 0; i < SYM_NUM; i++) + kvfree(p->sym_val_to_name[i]); kfree(p->class_val_to_struct); kfree(p->role_val_to_struct); kfree(p->user_val_to_struct); - if (p->type_val_to_struct_array) - flex_array_free(p->type_val_to_struct_array); + kvfree(p->type_val_to_struct); avtab_destroy(&p->te_avtab); @@ -856,12 +835,8 @@ cond_policydb_destroy(p); - for (tr = p->role_tr; tr; tr = tr->next) { - cond_resched(); - kfree(ltr); - ltr = tr; - } - kfree(ltr); + hashtab_map(&p->role_tr, role_tr_destroy, NULL); + hashtab_destroy(&p->role_tr); for (ra = p->role_allow; ra; ra = ra->next) { cond_resched(); @@ -870,22 +845,16 @@ } kfree(lra); - hashtab_map(p->filename_trans, filenametr_destroy, NULL); - hashtab_destroy(p->filename_trans); + hashtab_map(&p->filename_trans, filenametr_destroy, NULL); + hashtab_destroy(&p->filename_trans); - hashtab_map(p->range_tr, range_tr_destroy, NULL); - hashtab_destroy(p->range_tr); + hashtab_map(&p->range_tr, range_tr_destroy, NULL); + hashtab_destroy(&p->range_tr); if (p->type_attr_map_array) { - for (i = 0; i < p->p_types.nprim; i++) { - struct ebitmap *e; - - e = flex_array_get(p->type_attr_map_array, i); - if (!e) - continue; - ebitmap_destroy(e); - } - flex_array_free(p->type_attr_map_array); + for (i = 0; i < p->p_types.nprim; i++) + ebitmap_destroy(&p->type_attr_map_array[i]); + kvfree(p->type_attr_map_array); } ebitmap_destroy(&p->filename_trans_ttypes); @@ -905,41 +874,33 @@ rc = sidtab_init(s); if (rc) { pr_err("SELinux: out of memory on SID table init\n"); - goto out; + return rc; } head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { - rc = -EINVAL; - if (!c->context[0].user) { - pr_err("SELinux: SID %s was never defined.\n", - c->u.name); + u32 sid = c->sid[0]; + const char *name = security_get_initial_sid_context(sid); + + if (sid == SECSID_NULL) { + pr_err("SELinux: SID 0 was assigned a context.\n"); sidtab_destroy(s); - goto out; - } - if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) { - pr_err("SELinux: Initial SID %s out of range.\n", - c->u.name); - sidtab_destroy(s); - goto out; - } - rc = context_add_hash(p, &c->context[0]); - if (rc) { - sidtab_destroy(s); - goto out; + return -EINVAL; } - rc = sidtab_set_initial(s, c->sid[0], &c->context[0]); + /* Ignore initial SIDs unused by this kernel. */ + if (!name) + continue; + + rc = sidtab_set_initial(s, sid, &c->context[0]); if (rc) { pr_err("SELinux: unable to load initial SID %s.\n", - c->u.name); + name); sidtab_destroy(s); - goto out; + return rc; } } - rc = 0; -out: - return rc; + return 0; } int policydb_class_isvalid(struct policydb *p, unsigned int class) @@ -1123,18 +1084,18 @@ if (!str) return -ENOMEM; - /* it's expected the caller should free the str */ - *strp = str; - rc = next_entry(str, fp, len); - if (rc) + if (rc) { + kfree(str); return rc; + } str[len] = '\0'; + *strp = str; return 0; } -static int perm_read(struct policydb *p, struct hashtab *h, void *fp) +static int perm_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct perm_datum *perdatum; @@ -1157,7 +1118,7 @@ if (rc) goto bad; - rc = hashtab_insert(h, key, perdatum); + rc = symtab_insert(s, key, perdatum); if (rc) goto bad; @@ -1167,7 +1128,7 @@ return rc; } -static int common_read(struct policydb *p, struct hashtab *h, void *fp) +static int common_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct common_datum *comdatum; @@ -1185,24 +1146,24 @@ len = le32_to_cpu(buf[0]); comdatum->value = le32_to_cpu(buf[1]); + nel = le32_to_cpu(buf[3]); - rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE); + rc = symtab_init(&comdatum->permissions, nel); if (rc) goto bad; comdatum->permissions.nprim = le32_to_cpu(buf[2]); - nel = le32_to_cpu(buf[3]); rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; for (i = 0; i < nel; i++) { - rc = perm_read(p, comdatum->permissions.table, fp); + rc = perm_read(p, &comdatum->permissions, fp); if (rc) goto bad; } - rc = hashtab_insert(h, key, comdatum); + rc = symtab_insert(s, key, comdatum); if (rc) goto bad; return 0; @@ -1307,10 +1268,9 @@ if (rc) return rc; if (p->policyvers >= - POLICYDB_VERSION_CONSTRAINT_NAMES) { - e->type_names = kzalloc(sizeof - (*e->type_names), - GFP_KERNEL); + POLICYDB_VERSION_CONSTRAINT_NAMES) { + e->type_names = kzalloc(sizeof + (*e->type_names), GFP_KERNEL); if (!e->type_names) return -ENOMEM; type_set_init(e->type_names); @@ -1332,7 +1292,7 @@ return 0; } -static int class_read(struct policydb *p, struct hashtab *h, void *fp) +static int class_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct class_datum *cladatum; @@ -1351,12 +1311,12 @@ len = le32_to_cpu(buf[0]); len2 = le32_to_cpu(buf[1]); cladatum->value = le32_to_cpu(buf[2]); + nel = le32_to_cpu(buf[4]); - rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE); + rc = symtab_init(&cladatum->permissions, nel); if (rc) goto bad; cladatum->permissions.nprim = le32_to_cpu(buf[3]); - nel = le32_to_cpu(buf[4]); ncons = le32_to_cpu(buf[5]); @@ -1370,7 +1330,8 @@ goto bad; rc = -EINVAL; - cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); + cladatum->comdatum = symtab_search(&p->p_commons, + cladatum->comkey); if (!cladatum->comdatum) { pr_err("SELinux: unknown common %s\n", cladatum->comkey); @@ -1378,7 +1339,7 @@ } } for (i = 0; i < nel; i++) { - rc = perm_read(p, cladatum->permissions.table, fp); + rc = perm_read(p, &cladatum->permissions, fp); if (rc) goto bad; } @@ -1416,7 +1377,7 @@ cladatum->default_type = le32_to_cpu(buf[0]); } - rc = hashtab_insert(h, key, cladatum); + rc = symtab_insert(s, key, cladatum); if (rc) goto bad; @@ -1426,7 +1387,7 @@ return rc; } -static int role_read(struct policydb *p, struct hashtab *h, void *fp) +static int role_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct role_datum *role; @@ -1473,7 +1434,7 @@ goto bad; } - rc = hashtab_insert(h, key, role); + rc = symtab_insert(s, key, role); if (rc) goto bad; return 0; @@ -1482,7 +1443,7 @@ return rc; } -static int type_read(struct policydb *p, struct hashtab *h, void *fp) +static int type_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct type_datum *typdatum; @@ -1520,7 +1481,7 @@ if (rc) goto bad; - rc = hashtab_insert(h, key, typdatum); + rc = symtab_insert(s, key, typdatum); if (rc) goto bad; return 0; @@ -1556,7 +1517,7 @@ return 0; } -static int user_read(struct policydb *p, struct hashtab *h, void *fp) +static int user_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct user_datum *usrdatum; @@ -1597,7 +1558,7 @@ goto bad; } - rc = hashtab_insert(h, key, usrdatum); + rc = symtab_insert(s, key, usrdatum); if (rc) goto bad; return 0; @@ -1606,7 +1567,7 @@ return rc; } -static int sens_read(struct policydb *p, struct hashtab *h, void *fp) +static int sens_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct level_datum *levdatum; @@ -1638,7 +1599,7 @@ if (rc) goto bad; - rc = hashtab_insert(h, key, levdatum); + rc = symtab_insert(s, key, levdatum); if (rc) goto bad; return 0; @@ -1647,7 +1608,7 @@ return rc; } -static int cat_read(struct policydb *p, struct hashtab *h, void *fp) +static int cat_read(struct policydb *p, struct symtab *s, void *fp) { char *key = NULL; struct cat_datum *catdatum; @@ -1671,7 +1632,7 @@ if (rc) goto bad; - rc = hashtab_insert(h, key, catdatum); + rc = symtab_insert(s, key, catdatum); if (rc) goto bad; return 0; @@ -1680,7 +1641,7 @@ return rc; } -static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) = +static int (*read_f[SYM_NUM]) (struct policydb *p, struct symtab *s, void *fp) = { common_read, class_read, @@ -1779,8 +1740,7 @@ return -EINVAL; } - upper = flex_array_get_ptr(p->type_val_to_struct_array, - upper->bounds - 1); + upper = p->type_val_to_struct[upper->bounds - 1]; BUG_ON(!upper); if (upper->attribute) { @@ -1802,18 +1762,15 @@ if (p->policyvers < POLICYDB_VERSION_BOUNDARY) return 0; - rc = hashtab_map(p->p_users.table, - user_bounds_sanity_check, p); + rc = hashtab_map(&p->p_users.table, user_bounds_sanity_check, p); if (rc) return rc; - rc = hashtab_map(p->p_roles.table, - role_bounds_sanity_check, p); + rc = hashtab_map(&p->p_roles.table, role_bounds_sanity_check, p); if (rc) return rc; - rc = hashtab_map(p->p_types.table, - type_bounds_sanity_check, p); + rc = hashtab_map(&p->p_types.table, type_bounds_sanity_check, p); if (rc) return rc; @@ -1824,7 +1781,7 @@ { struct class_datum *cladatum; - cladatum = hashtab_search(p->p_classes.table, name); + cladatum = symtab_search(&p->p_classes, name); if (!cladatum) return 0; @@ -1843,11 +1800,9 @@ cladatum = p->class_val_to_struct[tclass-1]; comdatum = cladatum->comdatum; if (comdatum) - perdatum = hashtab_search(comdatum->permissions.table, - name); + perdatum = symtab_search(&comdatum->permissions, name); if (!perdatum) - perdatum = hashtab_search(cladatum->permissions.table, - name); + perdatum = symtab_search(&cladatum->permissions, name); if (!perdatum) return 0; @@ -1870,6 +1825,11 @@ return rc; nel = le32_to_cpu(buf[0]); + + rc = hashtab_init(&p->range_tr, nel); + if (rc) + return rc; + for (i = 0; i < nel; i++) { rc = -ENOMEM; rt = kzalloc(sizeof(*rt), GFP_KERNEL); @@ -1911,14 +1871,14 @@ goto out; } - rc = hashtab_insert(p->range_tr, rt, r); + rc = hashtab_insert(&p->range_tr, rt, r, rangetr_key_params); if (rc) goto out; rt = NULL; r = NULL; } - hash_eval(p->range_tr, "rangetr"); + hash_eval(&p->range_tr, "rangetr"); rc = 0; out: kfree(rt); @@ -1926,13 +1886,183 @@ return rc; } +static int filename_trans_read_helper_compat(struct policydb *p, void *fp) +{ + struct filename_trans_key key, *ft = NULL; + struct filename_trans_datum *last, *datum = NULL; + char *name = NULL; + u32 len, stype, otype; + __le32 buf[4]; + int rc; + + /* length of the path component string */ + rc = next_entry(buf, fp, sizeof(u32)); + if (rc) + return rc; + len = le32_to_cpu(buf[0]); + + /* path component string */ + rc = str_read(&name, GFP_KERNEL, fp, len); + if (rc) + return rc; + + rc = next_entry(buf, fp, sizeof(u32) * 4); + if (rc) + goto out; + + stype = le32_to_cpu(buf[0]); + key.ttype = le32_to_cpu(buf[1]); + key.tclass = le32_to_cpu(buf[2]); + key.name = name; + + otype = le32_to_cpu(buf[3]); + + last = NULL; + datum = policydb_filenametr_search(p, &key); + while (datum) { + if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) { + /* conflicting/duplicate rules are ignored */ + datum = NULL; + goto out; + } + if (likely(datum->otype == otype)) + break; + last = datum; + datum = datum->next; + } + if (!datum) { + rc = -ENOMEM; + datum = kmalloc(sizeof(*datum), GFP_KERNEL); + if (!datum) + goto out; + + ebitmap_init(&datum->stypes); + datum->otype = otype; + datum->next = NULL; + + if (unlikely(last)) { + last->next = datum; + } else { + rc = -ENOMEM; + ft = kmemdup(&key, sizeof(key), GFP_KERNEL); + if (!ft) + goto out; + + rc = hashtab_insert(&p->filename_trans, ft, datum, + filenametr_key_params); + if (rc) + goto out; + name = NULL; + + rc = ebitmap_set_bit(&p->filename_trans_ttypes, + key.ttype, 1); + if (rc) + return rc; + } + } + kfree(name); + return ebitmap_set_bit(&datum->stypes, stype - 1, 1); + +out: + kfree(ft); + kfree(name); + kfree(datum); + return rc; +} + +static int filename_trans_read_helper(struct policydb *p, void *fp) +{ + struct filename_trans_key *ft = NULL; + struct filename_trans_datum **dst, *datum, *first = NULL; + char *name = NULL; + u32 len, ttype, tclass, ndatum, i; + __le32 buf[3]; + int rc; + + /* length of the path component string */ + rc = next_entry(buf, fp, sizeof(u32)); + if (rc) + return rc; + len = le32_to_cpu(buf[0]); + + /* path component string */ + rc = str_read(&name, GFP_KERNEL, fp, len); + if (rc) + return rc; + + rc = next_entry(buf, fp, sizeof(u32) * 3); + if (rc) + goto out; + + ttype = le32_to_cpu(buf[0]); + tclass = le32_to_cpu(buf[1]); + + ndatum = le32_to_cpu(buf[2]); + if (ndatum == 0) { + pr_err("SELinux: Filename transition key with no datum\n"); + rc = -ENOENT; + goto out; + } + + dst = &first; + for (i = 0; i < ndatum; i++) { + rc = -ENOMEM; + datum = kmalloc(sizeof(*datum), GFP_KERNEL); + if (!datum) + goto out; + + *dst = datum; + + /* ebitmap_read() will at least init the bitmap */ + rc = ebitmap_read(&datum->stypes, fp); + if (rc) + goto out; + + rc = next_entry(buf, fp, sizeof(u32)); + if (rc) + goto out; + + datum->otype = le32_to_cpu(buf[0]); + datum->next = NULL; + + dst = &datum->next; + } + + rc = -ENOMEM; + ft = kmalloc(sizeof(*ft), GFP_KERNEL); + if (!ft) + goto out; + + ft->ttype = ttype; + ft->tclass = tclass; + ft->name = name; + + rc = hashtab_insert(&p->filename_trans, ft, first, + filenametr_key_params); + if (rc == -EEXIST) + pr_err("SELinux: Duplicate filename transition key\n"); + if (rc) + goto out; + + return ebitmap_set_bit(&p->filename_trans_ttypes, ttype, 1); + +out: + kfree(ft); + kfree(name); + while (first) { + datum = first; + first = first->next; + + ebitmap_destroy(&datum->stypes); + kfree(datum); + } + return rc; +} + static int filename_trans_read(struct policydb *p, void *fp) { - struct filename_trans *ft; - struct filename_trans_datum *otype; - char *name; - u32 nel, len; - __le32 buf[4]; + u32 nel; + __le32 buf[1]; int rc, i; if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) @@ -1943,69 +2073,31 @@ return rc; nel = le32_to_cpu(buf[0]); - for (i = 0; i < nel; i++) { - otype = NULL; - name = NULL; + if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { + p->compat_filename_trans_count = nel; - rc = -ENOMEM; - ft = kzalloc(sizeof(*ft), GFP_KERNEL); - if (!ft) - goto out; - - rc = -ENOMEM; - otype = kmalloc(sizeof(*otype), GFP_KERNEL); - if (!otype) - goto out; - - /* length of the path component string */ - rc = next_entry(buf, fp, sizeof(u32)); + rc = hashtab_init(&p->filename_trans, (1 << 11)); if (rc) - goto out; - len = le32_to_cpu(buf[0]); + return rc; - /* path component string */ - rc = str_read(&name, GFP_KERNEL, fp, len); + for (i = 0; i < nel; i++) { + rc = filename_trans_read_helper_compat(p, fp); + if (rc) + return rc; + } + } else { + rc = hashtab_init(&p->filename_trans, nel); if (rc) - goto out; + return rc; - ft->name = name; - - rc = next_entry(buf, fp, sizeof(u32) * 4); - if (rc) - goto out; - - ft->stype = le32_to_cpu(buf[0]); - ft->ttype = le32_to_cpu(buf[1]); - ft->tclass = le32_to_cpu(buf[2]); - - otype->otype = le32_to_cpu(buf[3]); - - rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); - if (rc) - goto out; - - rc = hashtab_insert(p->filename_trans, ft, otype); - if (rc) { - /* - * Do not return -EEXIST to the caller, or the system - * will not boot. - */ - if (rc != -EEXIST) - goto out; - /* But free memory to avoid memory leak. */ - kfree(ft); - kfree(name); - kfree(otype); + for (i = 0; i < nel; i++) { + rc = filename_trans_read_helper(p, fp); + if (rc) + return rc; } } - hash_eval(p->filename_trans, "filenametr"); + hash_eval(&p->filename_trans, "filenametr"); return 0; -out: - kfree(ft); - kfree(name); - kfree(otype); - - return rc; } static int genfs_read(struct policydb *p, void *fp) @@ -2310,17 +2402,16 @@ int policydb_read(struct policydb *p, void *fp) { struct role_allow *ra, *lra; - struct role_trans *tr, *ltr; + struct role_trans_key *rtk = NULL; + struct role_trans_datum *rtd = NULL; int i, j, rc; __le32 buf[4]; - u32 len, nprim, nel; + u32 len, nprim, nel, perm; char *policydb_str; struct policydb_compat_info *info; - rc = policydb_init(p); - if (rc) - return rc; + policydb_init(p); /* Read the magic number and string length. */ rc = next_entry(buf, fp, sizeof(u32) * 2); @@ -2444,8 +2535,19 @@ goto bad; nprim = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[1]); + + rc = symtab_init(&p->symtab[i], nel); + if (rc) + goto out; + + if (i == SYM_ROLES) { + rc = roles_init(p); + if (rc) + goto out; + } + for (j = 0; j < nel; j++) { - rc = read_f[i](p, p->symtab[i].table, fp); + rc = read_f[i](p, &p->symtab[i], fp); if (rc) goto bad; } @@ -2455,8 +2557,10 @@ rc = -EINVAL; p->process_class = string_to_security_class(p, "process"); - if (!p->process_class) + if (!p->process_class) { + pr_err("SELinux: process class is required, not defined in policy\n"); goto bad; + } rc = avtab_read(&p->te_avtab, fp, p); if (rc) @@ -2472,39 +2576,50 @@ if (rc) goto bad; nel = le32_to_cpu(buf[0]); - ltr = NULL; + + rc = hashtab_init(&p->role_tr, nel); + if (rc) + goto bad; for (i = 0; i < nel; i++) { rc = -ENOMEM; - tr = kzalloc(sizeof(*tr), GFP_KERNEL); - if (!tr) + rtk = kmalloc(sizeof(*rtk), GFP_KERNEL); + if (!rtk) goto bad; - if (ltr) - ltr->next = tr; - else - p->role_tr = tr; + + rc = -ENOMEM; + rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); + if (!rtd) + goto bad; + rc = next_entry(buf, fp, sizeof(u32)*3); 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]); + rtk->role = le32_to_cpu(buf[0]); + rtk->type = le32_to_cpu(buf[1]); + rtd->new_role = le32_to_cpu(buf[2]); if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { rc = next_entry(buf, fp, sizeof(u32)); if (rc) goto bad; - tr->tclass = le32_to_cpu(buf[0]); + rtk->tclass = le32_to_cpu(buf[0]); } else - tr->tclass = p->process_class; + rtk->tclass = p->process_class; rc = -EINVAL; - if (!policydb_role_isvalid(p, tr->role) || - !policydb_type_isvalid(p, tr->type) || - !policydb_class_isvalid(p, tr->tclass) || - !policydb_role_isvalid(p, tr->new_role)) + if (!policydb_role_isvalid(p, rtk->role) || + !policydb_type_isvalid(p, rtk->type) || + !policydb_class_isvalid(p, rtk->tclass) || + !policydb_role_isvalid(p, rtd->new_role)) goto bad; - ltr = tr; + + rc = hashtab_insert(&p->role_tr, rtk, rtd, roletr_key_params); + if (rc) + goto bad; + + rtk = NULL; + rtd = NULL; } rc = next_entry(buf, fp, sizeof(u32)); @@ -2543,10 +2658,18 @@ goto bad; 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) + perm = string_to_av_perm(p, p->process_class, "transition"); + if (!perm) { + pr_err("SELinux: process transition permission is required, not defined in policy\n"); goto bad; + } + p->process_trans_perms = perm; + perm = string_to_av_perm(p, p->process_class, "dyntransition"); + if (!perm) { + pr_err("SELinux: process dyntransition permission is required, not defined in policy\n"); + goto bad; + } + p->process_trans_perms |= perm; rc = ocontext_read(p, info, fp); if (rc) @@ -2561,23 +2684,19 @@ goto bad; rc = -ENOMEM; - p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap), - p->p_types.nprim, - GFP_KERNEL | __GFP_ZERO); + p->type_attr_map_array = kvcalloc(p->p_types.nprim, + sizeof(*p->type_attr_map_array), + GFP_KERNEL); if (!p->type_attr_map_array) goto bad; - /* preallocate so we don't have to worry about the put ever failing */ - rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim, - GFP_KERNEL | __GFP_ZERO); - if (rc) - goto bad; + /* just in case ebitmap_init() becomes more than just a memset(0): */ + for (i = 0; i < p->p_types.nprim; i++) + ebitmap_init(&p->type_attr_map_array[i]); for (i = 0; i < p->p_types.nprim; i++) { - struct ebitmap *e = flex_array_get(p->type_attr_map_array, i); + struct ebitmap *e = &p->type_attr_map_array[i]; - BUG_ON(!e); - ebitmap_init(e); if (p->policyvers >= POLICYDB_VERSION_AVTAB) { rc = ebitmap_read(e, fp); if (rc) @@ -2597,6 +2716,8 @@ out: return rc; bad: + kfree(rtk); + kfree(rtd); policydb_destroy(p); goto out; } @@ -2714,43 +2835,49 @@ return 0; } -static int role_trans_write(struct policydb *p, void *fp) +static int role_trans_write_one(void *key, void *datum, void *ptr) { - struct role_trans *r = p->role_tr; - struct role_trans *tr; - u32 buf[3]; - size_t nel; + struct role_trans_key *rtk = key; + struct role_trans_datum *rtd = datum; + struct policy_data *pd = ptr; + void *fp = pd->fp; + struct policydb *p = pd->p; + __le32 buf[3]; int rc; - nel = 0; - for (tr = r; tr; tr = tr->next) - nel++; - buf[0] = cpu_to_le32(nel); + buf[0] = cpu_to_le32(rtk->role); + buf[1] = cpu_to_le32(rtk->type); + buf[2] = cpu_to_le32(rtd->new_role); + rc = put_entry(buf, sizeof(u32), 3, fp); + if (rc) + return rc; + if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { + buf[0] = cpu_to_le32(rtk->tclass); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; + } + return 0; +} + +static int role_trans_write(struct policydb *p, void *fp) +{ + struct policy_data pd = { .p = p, .fp = fp }; + __le32 buf[1]; + int rc; + + buf[0] = cpu_to_le32(p->role_tr.nel); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; - for (tr = r; tr; tr = tr->next) { - buf[0] = cpu_to_le32(tr->role); - buf[1] = cpu_to_le32(tr->type); - buf[2] = cpu_to_le32(tr->new_role); - rc = put_entry(buf, sizeof(u32), 3, fp); - if (rc) - return rc; - if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { - buf[0] = cpu_to_le32(tr->tclass); - rc = put_entry(buf, sizeof(u32), 1, fp); - if (rc) - return rc; - } - } - return 0; + return hashtab_map(&p->role_tr, role_trans_write_one, &pd); } static int role_allow_write(struct role_allow *r, void *fp) { struct role_allow *ra; - u32 buf[2]; + __le32 buf[2]; size_t nel; int rc; @@ -2838,7 +2965,7 @@ buf[0] = cpu_to_le32(len); buf[1] = cpu_to_le32(comdatum->value); buf[2] = cpu_to_le32(comdatum->permissions.nprim); - buf[3] = cpu_to_le32(comdatum->permissions.table->nel); + buf[3] = cpu_to_le32(comdatum->permissions.table.nel); rc = put_entry(buf, sizeof(u32), 4, fp); if (rc) return rc; @@ -2847,7 +2974,7 @@ if (rc) return rc; - rc = hashtab_map(comdatum->permissions.table, perm_write, fp); + rc = hashtab_map(&comdatum->permissions.table, perm_write, fp); if (rc) return rc; @@ -2946,10 +3073,7 @@ buf[1] = cpu_to_le32(len2); buf[2] = cpu_to_le32(cladatum->value); buf[3] = cpu_to_le32(cladatum->permissions.nprim); - if (cladatum->permissions.table) - buf[4] = cpu_to_le32(cladatum->permissions.table->nel); - else - buf[4] = 0; + buf[4] = cpu_to_le32(cladatum->permissions.table.nel); buf[5] = cpu_to_le32(ncons); rc = put_entry(buf, sizeof(u32), 6, fp); if (rc) @@ -2965,7 +3089,7 @@ return rc; } - rc = hashtab_map(cladatum->permissions.table, perm_write, fp); + rc = hashtab_map(&cladatum->permissions.table, perm_write, fp); if (rc) return rc; @@ -3323,14 +3447,6 @@ return 0; } -static int hashtab_cnt(void *key, void *data, void *ptr) -{ - int *cnt = ptr; - *cnt = *cnt + 1; - - return 0; -} - static int range_write_helper(void *key, void *data, void *ptr) { __le32 buf[2]; @@ -3362,41 +3478,71 @@ static int range_write(struct policydb *p, void *fp) { __le32 buf[1]; - int rc, nel; + int rc; struct policy_data pd; pd.p = p; pd.fp = fp; - /* count the number of entries in the hashtab */ - nel = 0; - rc = hashtab_map(p->range_tr, hashtab_cnt, &nel); - if (rc) - return rc; - - buf[0] = cpu_to_le32(nel); + buf[0] = cpu_to_le32(p->range_tr.nel); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; /* actually write all of the entries */ - rc = hashtab_map(p->range_tr, range_write_helper, &pd); + rc = hashtab_map(&p->range_tr, range_write_helper, &pd); if (rc) return rc; return 0; } +static int filename_write_helper_compat(void *key, void *data, void *ptr) +{ + struct filename_trans_key *ft = key; + struct filename_trans_datum *datum = data; + struct ebitmap_node *node; + void *fp = ptr; + __le32 buf[4]; + int rc; + u32 bit, len = strlen(ft->name); + + do { + ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { + buf[0] = cpu_to_le32(len); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; + + rc = put_entry(ft->name, sizeof(char), len, fp); + if (rc) + return rc; + + buf[0] = cpu_to_le32(bit + 1); + buf[1] = cpu_to_le32(ft->ttype); + buf[2] = cpu_to_le32(ft->tclass); + buf[3] = cpu_to_le32(datum->otype); + + rc = put_entry(buf, sizeof(u32), 4, fp); + if (rc) + return rc; + } + + datum = datum->next; + } while (unlikely(datum)); + + return 0; +} + static int filename_write_helper(void *key, void *data, void *ptr) { - __le32 buf[4]; - struct filename_trans *ft = key; - struct filename_trans_datum *otype = data; + struct filename_trans_key *ft = key; + struct filename_trans_datum *datum; void *fp = ptr; + __le32 buf[3]; int rc; - u32 len; + u32 ndatum, len = strlen(ft->name); - len = strlen(ft->name); buf[0] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) @@ -3406,42 +3552,62 @@ if (rc) return rc; - buf[0] = cpu_to_le32(ft->stype); - buf[1] = cpu_to_le32(ft->ttype); - buf[2] = cpu_to_le32(ft->tclass); - buf[3] = cpu_to_le32(otype->otype); + ndatum = 0; + datum = data; + do { + ndatum++; + datum = datum->next; + } while (unlikely(datum)); - rc = put_entry(buf, sizeof(u32), 4, fp); + buf[0] = cpu_to_le32(ft->ttype); + buf[1] = cpu_to_le32(ft->tclass); + buf[2] = cpu_to_le32(ndatum); + rc = put_entry(buf, sizeof(u32), 3, fp); if (rc) return rc; + + datum = data; + do { + rc = ebitmap_write(&datum->stypes, fp); + if (rc) + return rc; + + buf[0] = cpu_to_le32(datum->otype); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; + + datum = datum->next; + } while (unlikely(datum)); return 0; } static int filename_trans_write(struct policydb *p, void *fp) { - u32 nel; __le32 buf[1]; int rc; if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) return 0; - nel = 0; - rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel); - if (rc) - return rc; + if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { + buf[0] = cpu_to_le32(p->compat_filename_trans_count); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; - buf[0] = cpu_to_le32(nel); - rc = put_entry(buf, sizeof(u32), 1, fp); - if (rc) - return rc; + rc = hashtab_map(&p->filename_trans, + filename_write_helper_compat, fp); + } else { + buf[0] = cpu_to_le32(p->filename_trans.nel); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; - rc = hashtab_map(p->filename_trans, filename_write_helper, fp); - if (rc) - return rc; - - return 0; + rc = hashtab_map(&p->filename_trans, filename_write_helper, fp); + } + return rc; } /* @@ -3528,12 +3694,12 @@ pd.p = p; buf[0] = cpu_to_le32(p->symtab[i].nprim); - buf[1] = cpu_to_le32(p->symtab[i].table->nel); + buf[1] = cpu_to_le32(p->symtab[i].table.nel); rc = put_entry(buf, sizeof(u32), 2, fp); if (rc) return rc; - rc = hashtab_map(p->symtab[i].table, write_f[i], &pd); + rc = hashtab_map(&p->symtab[i].table, write_f[i], &pd); if (rc) return rc; } @@ -3542,7 +3708,7 @@ if (rc) return rc; - rc = cond_write_list(p, p->cond_list, fp); + rc = cond_write_list(p, fp); if (rc) return rc; @@ -3571,9 +3737,8 @@ return rc; for (i = 0; i < p->p_types.nprim; i++) { - struct ebitmap *e = flex_array_get(p->type_attr_map_array, i); + struct ebitmap *e = &p->type_attr_map_array[i]; - BUG_ON(!e); rc = ebitmap_write(e, fp); if (rc) return rc; -- Gitblit v1.6.2