aboutsummaryrefslogtreecommitdiff
path: root/security/selinux/ss/policydb.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r--security/selinux/ss/policydb.c1120
1 files changed, 738 insertions, 382 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 94f630d93a5..9c5cdc2caae 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -13,7 +13,7 @@
*
* Added conditional policy language extensions
*
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
*
* Added support for the policy capability bitmap
*
@@ -123,6 +123,31 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_DEFAULT_TYPE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -148,32 +173,67 @@ 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 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)
@@ -213,35 +273,40 @@ 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->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
+ if (!p->filename_trans)
+ 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->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
+ return 0;
out:
- return rc;
-
-out_free_symtab:
+ hashtab_destroy(p->filename_trans);
+ hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
- goto out;
+ return rc;
}
/*
@@ -258,12 +323,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 +341,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 +359,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 +367,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 +380,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 +390,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 +408,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 +416,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 +429,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 +438,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 +451,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 +459,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,74 +480,27 @@ 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)
+#ifdef DEBUG_HASHES
+static void hash_eval(struct hashtab *h, const char *hash_name)
{
- 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;
- }
+ struct hashtab_info info;
- rc = hashtab_map(p->p_classes.table, class_index, p);
-out:
- return rc;
+ hashtab_stat(h, &info);
+ printk(KERN_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);
}
-#ifdef DEBUG_HASHES
static void symtab_hash_eval(struct symtab *s)
{
int i;
- for (i = 0; i < SYM_NUM; i++) {
- struct hashtab *h = s[i].table;
- struct hashtab_info info;
-
- hashtab_stat(h, &info);
- printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
- "longest chain length %d\n", symtab_name[i], h->nel,
- info.slots_used, h->size, info.max_chain_len);
- }
+ for (i = 0; i < SYM_NUM; i++)
+ hash_eval(s[i].table, symtab_name[i]);
}
-static void rangetr_hash_eval(struct hashtab *h)
-{
- struct hashtab_info info;
-
- hashtab_stat(h, &info);
- printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, "
- "longest chain length %d\n", h->nel,
- info.slots_used, h->size, info.max_chain_len);
-}
#else
-static inline void rangetr_hash_eval(struct hashtab *h)
+static inline void hash_eval(struct hashtab *h, char *hash_name)
{
}
#endif
@@ -458,9 +511,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 +530,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, 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 = cond_init_bool_indexes(p);
+ if (rc)
+ 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,
+ 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,13 +609,28 @@ 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;
}
+static void constraint_expr_destroy(struct constraint_expr *expr)
+{
+ if (expr) {
+ ebitmap_destroy(&expr->names);
+ if (expr->type_names) {
+ ebitmap_destroy(&expr->type_names->types);
+ ebitmap_destroy(&expr->type_names->negset);
+ kfree(expr->type_names);
+ }
+ kfree(expr);
+ }
+}
+
static int cls_destroy(void *key, void *datum, void *p)
{
struct class_datum *cladatum;
@@ -554,38 +638,37 @@ 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) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(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) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(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 +678,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 +699,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 +715,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;
}
@@ -654,6 +743,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
cat_destroy,
};
+static int filenametr_destroy(void *key, void *datum, void *p)
+{
+ struct filename_trans *ft = key;
+ kfree(ft->name);
+ kfree(key);
+ kfree(datum);
+ cond_resched();
+ return 0;
+}
+
static int range_tr_destroy(void *key, void *datum, void *p)
{
struct mls_range *rt = datum;
@@ -695,13 +794,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);
@@ -748,6 +850,9 @@ void policydb_destroy(struct policydb *p)
}
kfree(lra);
+ 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);
@@ -762,6 +867,8 @@ void policydb_destroy(struct policydb *p)
}
flex_array_free(p->type_attr_map_array);
}
+
+ ebitmap_destroy(&p->filename_trans_ttypes);
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
@@ -785,19 +892,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 +955,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 +966,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 +988,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 +1012,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 +1029,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 +1048,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 +1056,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 +1088,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 +1128,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 +1146,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,15 +1165,40 @@ 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,
- int allowxtarget, void *fp)
+static void type_set_init(struct type_set *t)
+{
+ ebitmap_init(&t->types);
+ ebitmap_init(&t->negset);
+}
+
+static int type_set_read(struct type_set *t, void *fp)
+{
+ __le32 buf[1];
+ int rc;
+
+ if (ebitmap_read(&t->types, fp))
+ return -EINVAL;
+ if (ebitmap_read(&t->negset, fp))
+ return -EINVAL;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc < 0)
+ return -EINVAL;
+ t->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+
+static int read_cons_helper(struct policydb *p,
+ struct constraint_node **nodep,
+ int ncons, int allowxtarget, void *fp)
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
@@ -1088,7 +1218,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 +1235,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 +1263,21 @@ 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;
+ if (p->policyvers >=
+ 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);
+ rc = type_set_read(e->type_names, fp);
+ if (rc)
+ return rc;
+ }
break;
default:
return -EINVAL;
@@ -1157,14 +1300,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 +1321,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;
}
}
@@ -1215,31 +1354,47 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
goto bad;
}
- rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+ rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
if (rc)
goto bad;
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);
+ rc = read_cons_helper(p, &cladatum->validatetrans,
+ ncons, 1, fp);
+ if (rc)
+ goto bad;
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
+ rc = next_entry(buf, fp, sizeof(u32) * 3);
if (rc)
goto bad;
+
+ cladatum->default_user = le32_to_cpu(buf[0]);
+ cladatum->default_role = le32_to_cpu(buf[1]);
+ cladatum->default_range = le32_to_cpu(buf[2]);
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
+ rc = next_entry(buf, fp, sizeof(u32) * 1);
+ if (rc)
+ goto bad;
+ cladatum->default_type = le32_to_cpu(buf[0]);
}
rc = hashtab_insert(h, key, cladatum);
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 +1405,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 +1422,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 +1441,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 +1454,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 +1468,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 +1495,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 +1526,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 +1548,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 +1565,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 +1590,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 +1604,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 +1651,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 +1720,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 +1757,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 +1783,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;
}
}
@@ -1686,8 +1824,6 @@ static int policydb_bounds_sanity_check(struct policydb *p)
return 0;
}
-extern int ss_initialized;
-
u16 string_to_security_class(struct policydb *p, const char *name)
{
struct class_datum *cladatum;
@@ -1786,7 +1922,7 @@ static int range_read(struct policydb *p, void *fp)
rt = NULL;
r = NULL;
}
- rangetr_hash_eval(p->range_tr);
+ hash_eval(p->range_tr, "rangetr");
rc = 0;
out:
kfree(rt);
@@ -1794,6 +1930,95 @@ out:
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];
+ int rc, i;
+
+ if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+ return 0;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ return rc;
+ nel = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < nel; i++) {
+ ft = NULL;
+ otype = NULL;
+ name = NULL;
+
+ 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));
+ if (rc)
+ goto out;
+ len = le32_to_cpu(buf[0]);
+
+ rc = -ENOMEM;
+ name = kmalloc(len + 1, GFP_KERNEL);
+ if (!name)
+ goto out;
+
+ ft->name = name;
+
+ /* path component string */
+ rc = next_entry(name, fp, len);
+ if (rc)
+ goto out;
+ name[len] = 0;
+
+ 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);
+ }
+ }
+ 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)
{
int i, j, rc;
@@ -2009,7 +2234,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
rc = -EINVAL;
c->v.behavior = le32_to_cpu(buf[0]);
- if (c->v.behavior > SECURITY_FS_USE_NONE)
+ /* Determined at runtime, not in policy DB. */
+ if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
+ goto out;
+ if (c->v.behavior > SECURITY_FS_USE_MAX)
goto out;
rc = -ENOMEM;
@@ -2066,13 +2294,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 +2309,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 +2317,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 +2347,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 +2363,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 +2374,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 +2394,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 +2406,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]);
@@ -2177,6 +2419,11 @@ int policydb_read(struct policydb *p, void *fp)
p->symtab[i].nprim = nprim;
}
+ rc = -EINVAL;
+ p->process_class = string_to_security_class(p, "process");
+ if (!p->process_class)
+ goto bad;
+
rc = avtab_read(&p->te_avtab, fp, p);
if (rc)
goto bad;
@@ -2188,78 +2435,81 @@ 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 (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto bad;
+ tr->tclass = le32_to_cpu(buf[0]);
+ } else
+ tr->tclass = p->process_class;
+
if (!policydb_role_isvalid(p, tr->role) ||
!policydb_type_isvalid(p, tr->type) ||
- !policydb_role_isvalid(p, tr->new_role)) {
- rc = -EINVAL;
+ !policydb_class_isvalid(p, tr->tclass) ||
+ !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);
+ rc = filename_trans_read(p, fp);
if (rc)
goto bad;
- rc = policydb_index_others(p);
+ rc = policydb_index(p);
if (rc)
goto bad;
- 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;
@@ -2283,7 +2533,7 @@ int policydb_read(struct policydb *p, void *fp)
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 - 1,
+ rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim,
GFP_KERNEL | __GFP_ZERO);
if (rc)
goto bad;
@@ -2312,8 +2562,6 @@ int policydb_read(struct policydb *p, void *fp)
out:
return rc;
bad:
- if (!rc)
- rc = -EINVAL;
policydb_destroy(p);
goto out;
}
@@ -2431,8 +2679,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
return 0;
}
-static int role_trans_write(struct role_trans *r, void *fp)
+static int role_trans_write(struct policydb *p, void *fp)
{
+ struct role_trans *r = p->role_tr;
struct role_trans *tr;
u32 buf[3];
size_t nel;
@@ -2452,6 +2701,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
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;
@@ -2564,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)
return 0;
}
+static int type_set_write(struct type_set *t, void *fp)
+{
+ int rc;
+ __le32 buf[1];
+
+ if (ebitmap_write(&t->types, fp))
+ return -EINVAL;
+ if (ebitmap_write(&t->negset, fp))
+ return -EINVAL;
+
+ buf[0] = cpu_to_le32(t->flags);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return -EINVAL;
+
+ return 0;
+}
+
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
void *fp)
{
@@ -2595,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
rc = ebitmap_write(&e->names, fp);
if (rc)
return rc;
+ if (p->policyvers >=
+ POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ rc = type_set_write(e->type_names, fp);
+ if (rc)
+ return rc;
+ }
break;
default:
break;
@@ -2673,6 +2952,23 @@ static int class_write(void *vkey, void *datum, void *ptr)
if (rc)
return rc;
+ if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
+ buf[0] = cpu_to_le32(cladatum->default_user);
+ buf[1] = cpu_to_le32(cladatum->default_role);
+ buf[2] = cpu_to_le32(cladatum->default_range);
+
+ rc = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (rc)
+ return rc;
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
+ buf[0] = cpu_to_le32(cladatum->default_type);
+ rc = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (rc)
+ return rc;
+ }
+
return 0;
}
@@ -2959,7 +3255,7 @@ static int genfs_write(struct policydb *p, void *fp)
return 0;
}
-static int range_count(void *key, void *data, void *ptr)
+static int hashtab_cnt(void *key, void *data, void *ptr)
{
int *cnt = ptr;
*cnt = *cnt + 1;
@@ -2997,9 +3293,8 @@ static int range_write_helper(void *key, void *data, void *ptr)
static int range_write(struct policydb *p, void *fp)
{
- size_t nel;
__le32 buf[1];
- int rc;
+ int rc, nel;
struct policy_data pd;
pd.p = p;
@@ -3007,7 +3302,7 @@ static int range_write(struct policydb *p, void *fp)
/* count the number of entries in the hashtab */
nel = 0;
- rc = hashtab_map(p->range_tr, range_count, &nel);
+ rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
if (rc)
return rc;
@@ -3024,6 +3319,63 @@ static int range_write(struct policydb *p, void *fp)
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;
+ void *fp = ptr;
+ int rc;
+ u32 len;
+
+ len = strlen(ft->name);
+ 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(ft->stype);
+ buf[1] = cpu_to_le32(ft->ttype);
+ buf[2] = cpu_to_le32(ft->tclass);
+ buf[3] = cpu_to_le32(otype->otype);
+
+ rc = put_entry(buf, sizeof(u32), 4, fp);
+ if (rc)
+ return rc;
+
+ 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;
+
+ 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, fp);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
/*
* Write the configuration data in a policy database
* structure to a policy database binary representation
@@ -3076,7 +3428,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);
@@ -3126,7 +3478,7 @@ int policydb_write(struct policydb *p, void *fp)
if (rc)
return rc;
- rc = role_trans_write(p->role_tr, fp);
+ rc = role_trans_write(p, fp);
if (rc)
return rc;
@@ -3134,6 +3486,10 @@ int policydb_write(struct policydb *p, void *fp)
if (rc)
return rc;
+ rc = filename_trans_write(p, fp);
+ if (rc)
+ return rc;
+
rc = ocontext_write(p, info, fp);
if (rc)
return rc;