]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - security/selinux/ss/policydb.c
Merge branch 'master' into tk71
[mv-sheeva.git] / security / selinux / ss / policydb.c
index 3a29704be8ce10f4409dd0a3d4f0bea8bb0d1086..57363562f0f886a455e900fdf59a56417b379127 100644 (file)
@@ -37,6 +37,7 @@
 #include "policydb.h"
 #include "conditional.h"
 #include "mls.h"
+#include "services.h"
 
 #define _DEBUG_HASHES
 
@@ -147,32 +148,30 @@ static int roles_init(struct policydb *p)
        int rc;
        struct role_datum *role;
 
+       rc = -ENOMEM;
        role = kzalloc(sizeof(*role), GFP_KERNEL);
-       if (!role) {
-               rc = -ENOMEM;
+       if (!role)
                goto out;
-       }
+
+       rc = -EINVAL;
        role->value = ++p->p_roles.nprim;
-       if (role->value != OBJECT_R_VAL) {
-               rc = -EINVAL;
-               goto out_free_role;
-       }
+       if (role->value != OBJECT_R_VAL)
+               goto out;
+
+       rc = -ENOMEM;
        key = kstrdup(OBJECT_R, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
-               goto out_free_role;
-       }
+       if (!key)
+               goto out;
+
        rc = hashtab_insert(p->p_roles.table, key, role);
        if (rc)
-               goto out_free_key;
-out:
-       return rc;
+               goto out;
 
-out_free_key:
+       return 0;
+out:
        kfree(key);
-out_free_role:
        kfree(role);
-       goto out;
+       return rc;
 }
 
 static u32 rangetr_hash(struct hashtab *h, const void *k)
@@ -185,9 +184,19 @@ static u32 rangetr_hash(struct hashtab *h, const void *k)
 static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
 {
        const struct range_trans *key1 = k1, *key2 = k2;
-       return (key1->source_type != key2->source_type ||
-               key1->target_type != key2->target_type ||
-               key1->target_class != key2->target_class);
+       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;
 }
 
 /*
@@ -202,35 +211,33 @@ static int policydb_init(struct policydb *p)
        for (i = 0; i < SYM_NUM; i++) {
                rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
                if (rc)
-                       goto out_free_symtab;
+                       goto out;
        }
 
        rc = avtab_init(&p->te_avtab);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        rc = roles_init(p);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        rc = cond_policydb_init(p);
        if (rc)
-               goto out_free_symtab;
+               goto out;
 
        p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
        if (!p->range_tr)
-               goto out_free_symtab;
+               goto out;
 
        ebitmap_init(&p->policycaps);
        ebitmap_init(&p->permissive_map);
 
+       return 0;
 out:
-       return rc;
-
-out_free_symtab:
        for (i = 0; i < SYM_NUM; i++)
                hashtab_destroy(p->symtab[i].table);
-       goto out;
+       return rc;
 }
 
 /*
@@ -247,12 +254,17 @@ static int common_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct common_datum *comdatum;
+       struct flex_array *fa;
 
        comdatum = datum;
        p = datap;
        if (!comdatum->value || comdatum->value > p->p_commons.nprim)
                return -EINVAL;
-       p->p_common_val_to_name[comdatum->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_COMMONS];
+       if (flex_array_put_ptr(fa, comdatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        return 0;
 }
 
@@ -260,12 +272,16 @@ static int class_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct class_datum *cladatum;
+       struct flex_array *fa;
 
        cladatum = datum;
        p = datap;
        if (!cladatum->value || cladatum->value > p->p_classes.nprim)
                return -EINVAL;
-       p->p_class_val_to_name[cladatum->value - 1] = key;
+       fa = p->sym_val_to_name[SYM_CLASSES];
+       if (flex_array_put_ptr(fa, cladatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->class_val_to_struct[cladatum->value - 1] = cladatum;
        return 0;
 }
@@ -274,6 +290,7 @@ static int role_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct role_datum *role;
+       struct flex_array *fa;
 
        role = datum;
        p = datap;
@@ -281,7 +298,11 @@ static int role_index(void *key, void *datum, void *datap)
            || role->value > p->p_roles.nprim
            || role->bounds > p->p_roles.nprim)
                return -EINVAL;
-       p->p_role_val_to_name[role->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_ROLES];
+       if (flex_array_put_ptr(fa, role->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->role_val_to_struct[role->value - 1] = role;
        return 0;
 }
@@ -290,6 +311,7 @@ static int type_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct type_datum *typdatum;
+       struct flex_array *fa;
 
        typdatum = datum;
        p = datap;
@@ -299,8 +321,15 @@ static int type_index(void *key, void *datum, void *datap)
                    || typdatum->value > p->p_types.nprim
                    || typdatum->bounds > p->p_types.nprim)
                        return -EINVAL;
-               p->p_type_val_to_name[typdatum->value - 1] = key;
-               p->type_val_to_struct[typdatum->value - 1] = typdatum;
+               fa = p->sym_val_to_name[SYM_TYPES];
+               if (flex_array_put_ptr(fa, typdatum->value - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
+
+               fa = p->type_val_to_struct_array;
+               if (flex_array_put_ptr(fa, typdatum->value - 1, typdatum,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -310,6 +339,7 @@ static int user_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct user_datum *usrdatum;
+       struct flex_array *fa;
 
        usrdatum = datum;
        p = datap;
@@ -317,7 +347,11 @@ static int user_index(void *key, void *datum, void *datap)
            || usrdatum->value > p->p_users.nprim
            || usrdatum->bounds > p->p_users.nprim)
                return -EINVAL;
-       p->p_user_val_to_name[usrdatum->value - 1] = key;
+
+       fa = p->sym_val_to_name[SYM_USERS];
+       if (flex_array_put_ptr(fa, usrdatum->value - 1, key,
+                              GFP_KERNEL | __GFP_ZERO))
+               BUG();
        p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
        return 0;
 }
@@ -326,6 +360,7 @@ static int sens_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct level_datum *levdatum;
+       struct flex_array *fa;
 
        levdatum = datum;
        p = datap;
@@ -334,7 +369,10 @@ static int sens_index(void *key, void *datum, void *datap)
                if (!levdatum->level->sens ||
                    levdatum->level->sens > p->p_levels.nprim)
                        return -EINVAL;
-               p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+               fa = p->sym_val_to_name[SYM_LEVELS];
+               if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -344,6 +382,7 @@ static int cat_index(void *key, void *datum, void *datap)
 {
        struct policydb *p;
        struct cat_datum *catdatum;
+       struct flex_array *fa;
 
        catdatum = datum;
        p = datap;
@@ -351,7 +390,10 @@ static int cat_index(void *key, void *datum, void *datap)
        if (!catdatum->isalias) {
                if (!catdatum->value || catdatum->value > p->p_cats.nprim)
                        return -EINVAL;
-               p->p_cat_val_to_name[catdatum->value - 1] = key;
+               fa = p->sym_val_to_name[SYM_CATS];
+               if (flex_array_put_ptr(fa, catdatum->value - 1, key,
+                                      GFP_KERNEL | __GFP_ZERO))
+                       BUG();
        }
 
        return 0;
@@ -369,47 +411,6 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
        cat_index,
 };
 
-/*
- * Define the common val_to_name array and the class
- * val_to_name and val_to_struct arrays in a policy
- * database structure.
- *
- * Caller must clean up upon failure.
- */
-static int policydb_index_classes(struct policydb *p)
-{
-       int rc;
-
-       p->p_common_val_to_name =
-               kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL);
-       if (!p->p_common_val_to_name) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = hashtab_map(p->p_commons.table, common_index, p);
-       if (rc)
-               goto out;
-
-       p->class_val_to_struct =
-               kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL);
-       if (!p->class_val_to_struct) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       p->p_class_val_to_name =
-               kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL);
-       if (!p->p_class_val_to_name) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = hashtab_map(p->p_classes.table, class_index, p);
-out:
-       return rc;
-}
-
 #ifdef DEBUG_HASHES
 static void symtab_hash_eval(struct symtab *s)
 {
@@ -447,9 +448,9 @@ static inline void rangetr_hash_eval(struct hashtab *h)
  *
  * Caller must clean up on failure.
  */
-static int policydb_index_others(struct policydb *p)
+static int policydb_index(struct policydb *p)
 {
-       int i, rc = 0;
+       int i, rc;
 
        printk(KERN_DEBUG "SELinux:  %d users, %d roles, %d types, %d bools",
               p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
@@ -466,47 +467,63 @@ static int policydb_index_others(struct policydb *p)
        symtab_hash_eval(p->symtab);
 #endif
 
+       rc = -ENOMEM;
+       p->class_val_to_struct =
+               kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)),
+                       GFP_KERNEL);
+       if (!p->class_val_to_struct)
+               goto out;
+
+       rc = -ENOMEM;
        p->role_val_to_struct =
                kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)),
                        GFP_KERNEL);
-       if (!p->role_val_to_struct) {
-               rc = -ENOMEM;
+       if (!p->role_val_to_struct)
                goto out;
-       }
 
+       rc = -ENOMEM;
        p->user_val_to_struct =
                kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)),
                        GFP_KERNEL);
-       if (!p->user_val_to_struct) {
-               rc = -ENOMEM;
+       if (!p->user_val_to_struct)
                goto out;
-       }
 
-       p->type_val_to_struct =
-               kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
-                       GFP_KERNEL);
-       if (!p->type_val_to_struct) {
-               rc = -ENOMEM;
+       /* Yes, I want the sizeof the pointer, not the structure */
+       rc = -ENOMEM;
+       p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *),
+                                                      p->p_types.nprim,
+                                                      GFP_KERNEL | __GFP_ZERO);
+       if (!p->type_val_to_struct_array)
                goto out;
-       }
 
-       if (cond_init_bool_indexes(p)) {
-               rc = -ENOMEM;
+       rc = flex_array_prealloc(p->type_val_to_struct_array, 0,
+                                p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO);
+       if (rc)
                goto out;
-       }
 
-       for (i = SYM_ROLES; i < SYM_NUM; i++) {
-               p->sym_val_to_name[i] =
-                       kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
-               if (!p->sym_val_to_name[i]) {
-                       rc = -ENOMEM;
+       rc = 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 - 1,
+                                        GFP_KERNEL | __GFP_ZERO);
+               if (rc)
+                       goto out;
+
                rc = hashtab_map(p->symtab[i].table, index_f[i], p);
                if (rc)
                        goto out;
        }
-
+       rc = 0;
 out:
        return rc;
 }
@@ -529,9 +546,11 @@ static int common_destroy(void *key, void *datum, void *p)
        struct common_datum *comdatum;
 
        kfree(key);
-       comdatum = datum;
-       hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
-       hashtab_destroy(comdatum->permissions.table);
+       if (datum) {
+               comdatum = datum;
+               hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
+               hashtab_destroy(comdatum->permissions.table);
+       }
        kfree(datum);
        return 0;
 }
@@ -543,38 +562,40 @@ static int cls_destroy(void *key, void *datum, void *p)
        struct constraint_expr *e, *etmp;
 
        kfree(key);
-       cladatum = datum;
-       hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
-       hashtab_destroy(cladatum->permissions.table);
-       constraint = cladatum->constraints;
-       while (constraint) {
-               e = constraint->expr;
-               while (e) {
-                       ebitmap_destroy(&e->names);
-                       etmp = e;
-                       e = e->next;
-                       kfree(etmp);
+       if (datum) {
+               cladatum = datum;
+               hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+               hashtab_destroy(cladatum->permissions.table);
+               constraint = cladatum->constraints;
+               while (constraint) {
+                       e = constraint->expr;
+                       while (e) {
+                               ebitmap_destroy(&e->names);
+                               etmp = e;
+                               e = e->next;
+                               kfree(etmp);
+                       }
+                       ctemp = constraint;
+                       constraint = constraint->next;
+                       kfree(ctemp);
                }
-               ctemp = constraint;
-               constraint = constraint->next;
-               kfree(ctemp);
-       }
-
-       constraint = cladatum->validatetrans;
-       while (constraint) {
-               e = constraint->expr;
-               while (e) {
-                       ebitmap_destroy(&e->names);
-                       etmp = e;
-                       e = e->next;
-                       kfree(etmp);
+
+               constraint = cladatum->validatetrans;
+               while (constraint) {
+                       e = constraint->expr;
+                       while (e) {
+                               ebitmap_destroy(&e->names);
+                               etmp = e;
+                               e = e->next;
+                               kfree(etmp);
+                       }
+                       ctemp = constraint;
+                       constraint = constraint->next;
+                       kfree(ctemp);
                }
-               ctemp = constraint;
-               constraint = constraint->next;
-               kfree(ctemp);
-       }
 
-       kfree(cladatum->comkey);
+               kfree(cladatum->comkey);
+       }
        kfree(datum);
        return 0;
 }
@@ -584,9 +605,11 @@ static int role_destroy(void *key, void *datum, void *p)
        struct role_datum *role;
 
        kfree(key);
-       role = datum;
-       ebitmap_destroy(&role->dominates);
-       ebitmap_destroy(&role->types);
+       if (datum) {
+               role = datum;
+               ebitmap_destroy(&role->dominates);
+               ebitmap_destroy(&role->types);
+       }
        kfree(datum);
        return 0;
 }
@@ -603,11 +626,13 @@ static int user_destroy(void *key, void *datum, void *p)
        struct user_datum *usrdatum;
 
        kfree(key);
-       usrdatum = datum;
-       ebitmap_destroy(&usrdatum->roles);
-       ebitmap_destroy(&usrdatum->range.level[0].cat);
-       ebitmap_destroy(&usrdatum->range.level[1].cat);
-       ebitmap_destroy(&usrdatum->dfltlevel.cat);
+       if (datum) {
+               usrdatum = datum;
+               ebitmap_destroy(&usrdatum->roles);
+               ebitmap_destroy(&usrdatum->range.level[0].cat);
+               ebitmap_destroy(&usrdatum->range.level[1].cat);
+               ebitmap_destroy(&usrdatum->dfltlevel.cat);
+       }
        kfree(datum);
        return 0;
 }
@@ -617,9 +642,11 @@ static int sens_destroy(void *key, void *datum, void *p)
        struct level_datum *levdatum;
 
        kfree(key);
-       levdatum = datum;
-       ebitmap_destroy(&levdatum->level->cat);
-       kfree(levdatum->level);
+       if (datum) {
+               levdatum = datum;
+               ebitmap_destroy(&levdatum->level->cat);
+               kfree(levdatum->level);
+       }
        kfree(datum);
        return 0;
 }
@@ -684,13 +711,16 @@ void policydb_destroy(struct policydb *p)
                hashtab_destroy(p->symtab[i].table);
        }
 
-       for (i = 0; i < SYM_NUM; i++)
-               kfree(p->sym_val_to_name[i]);
+       for (i = 0; i < SYM_NUM; i++) {
+               if (p->sym_val_to_name[i])
+                       flex_array_free(p->sym_val_to_name[i]);
+       }
 
        kfree(p->class_val_to_struct);
        kfree(p->role_val_to_struct);
        kfree(p->user_val_to_struct);
-       kfree(p->type_val_to_struct);
+       if (p->type_val_to_struct_array)
+               flex_array_free(p->type_val_to_struct_array);
 
        avtab_destroy(&p->te_avtab);
 
@@ -774,19 +804,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
 
        head = p->ocontexts[OCON_ISID];
        for (c = head; c; c = c->next) {
+               rc = -EINVAL;
                if (!c->context[0].user) {
-                       printk(KERN_ERR "SELinux:  SID %s was never "
-                              "defined.\n", c->u.name);
-                       rc = -EINVAL;
+                       printk(KERN_ERR "SELinux:  SID %s was never defined.\n",
+                               c->u.name);
                        goto out;
                }
-               if (sidtab_insert(s, c->sid[0], &c->context[0])) {
-                       printk(KERN_ERR "SELinux:  unable to load initial "
-                              "SID %s.\n", c->u.name);
-                       rc = -EINVAL;
+
+               rc = sidtab_insert(s, c->sid[0], &c->context[0]);
+               if (rc) {
+                       printk(KERN_ERR "SELinux:  unable to load initial SID %s.\n",
+                               c->u.name);
                        goto out;
                }
        }
+       rc = 0;
 out:
        return rc;
 }
@@ -835,8 +867,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
                 * Role must be authorized for the type.
                 */
                role = p->role_val_to_struct[c->role - 1];
-               if (!ebitmap_get_bit(&role->types,
-                                    c->type - 1))
+               if (!ebitmap_get_bit(&role->types, c->type - 1))
                        /* role may not be associated with type */
                        return 0;
 
@@ -847,8 +878,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
                if (!usrdatum)
                        return 0;
 
-               if (!ebitmap_get_bit(&usrdatum->roles,
-                                    c->role - 1))
+               if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))
                        /* user may not be associated with role */
                        return 0;
        }
@@ -870,20 +900,22 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
        int rc;
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto out;
 
+       rc = -EINVAL;
        items = le32_to_cpu(buf[0]);
        if (items > ARRAY_SIZE(buf)) {
                printk(KERN_ERR "SELinux: mls:  range overflow\n");
-               rc = -EINVAL;
                goto out;
        }
+
        rc = next_entry(buf, fp, sizeof(u32) * items);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: mls:  truncated range\n");
                goto out;
        }
+
        r->level[0].sens = le32_to_cpu(buf[0]);
        if (items > 1)
                r->level[1].sens = le32_to_cpu(buf[1]);
@@ -892,15 +924,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
 
        rc = ebitmap_read(&r->level[0].cat, fp);
        if (rc) {
-               printk(KERN_ERR "SELinux: mls:  error reading low "
-                      "categories\n");
+               printk(KERN_ERR "SELinux: mls:  error reading low categories\n");
                goto out;
        }
        if (items > 1) {
                rc = ebitmap_read(&r->level[1].cat, fp);
                if (rc) {
-                       printk(KERN_ERR "SELinux: mls:  error reading high "
-                              "categories\n");
+                       printk(KERN_ERR "SELinux: mls:  error reading high categories\n");
                        goto bad_high;
                }
        } else {
@@ -911,12 +941,11 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
                }
        }
 
-       rc = 0;
-out:
-       return rc;
+       return 0;
 bad_high:
        ebitmap_destroy(&r->level[0].cat);
-       goto out;
+out:
+       return rc;
 }
 
 /*
@@ -931,7 +960,7 @@ static int context_read_and_validate(struct context *c,
        int rc;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: context truncated\n");
                goto out;
        }
@@ -939,19 +968,20 @@ static int context_read_and_validate(struct context *c,
        c->role = le32_to_cpu(buf[1]);
        c->type = le32_to_cpu(buf[2]);
        if (p->policyvers >= POLICYDB_VERSION_MLS) {
-               if (mls_read_range_helper(&c->range, fp)) {
-                       printk(KERN_ERR "SELinux: error reading MLS range of "
-                              "context\n");
-                       rc = -EINVAL;
+               rc = mls_read_range_helper(&c->range, fp);
+               if (rc) {
+                       printk(KERN_ERR "SELinux: error reading MLS range of context\n");
                        goto out;
                }
        }
 
+       rc = -EINVAL;
        if (!policydb_context_isvalid(p, c)) {
                printk(KERN_ERR "SELinux:  invalid security context\n");
                context_destroy(c);
-               rc = -EINVAL;
+               goto out;
        }
+       rc = 0;
 out:
        return rc;
 }
@@ -970,37 +1000,36 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[2];
        u32 len;
 
+       rc = -ENOMEM;
        perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
-       if (!perdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!perdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        perdatum->value = le32_to_cpu(buf[1]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, perdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+
+       return 0;
 bad:
        perm_destroy(key, perdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int common_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1011,14 +1040,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        u32 len, nel;
        int i, rc;
 
+       rc = -ENOMEM;
        comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
-       if (!comdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!comdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1030,13 +1058,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        comdatum->permissions.nprim = le32_to_cpu(buf[2]);
        nel = le32_to_cpu(buf[3]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1049,11 +1077,10 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, comdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        common_destroy(key, comdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int read_cons_helper(struct constraint_node **nodep, int ncons,
@@ -1077,7 +1104,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                        *nodep = c;
 
                rc = next_entry(buf, fp, (sizeof(u32) * 2));
-               if (rc < 0)
+               if (rc)
                        return rc;
                c->permissions = le32_to_cpu(buf[0]);
                nexpr = le32_to_cpu(buf[1]);
@@ -1094,7 +1121,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                                c->expr = e;
 
                        rc = next_entry(buf, fp, (sizeof(u32) * 3));
-                       if (rc < 0)
+                       if (rc)
                                return rc;
                        e->expr_type = le32_to_cpu(buf[0]);
                        e->attr = le32_to_cpu(buf[1]);
@@ -1122,8 +1149,9 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
                                if (depth == (CEXPR_MAXDEPTH - 1))
                                        return -EINVAL;
                                depth++;
-                               if (ebitmap_read(&e->names, fp))
-                                       return -EINVAL;
+                               rc = ebitmap_read(&e->names, fp);
+                               if (rc)
+                                       return rc;
                                break;
                        default:
                                return -EINVAL;
@@ -1146,14 +1174,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        u32 len, len2, ncons, nel;
        int i, rc;
 
+       rc = -ENOMEM;
        cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
-       if (!cladatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!cladatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof(u32)*6);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1168,33 +1195,30 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
 
        ncons = le32_to_cpu(buf[5]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        if (len2) {
+               rc = -ENOMEM;
                cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL);
-               if (!cladatum->comkey) {
-                       rc = -ENOMEM;
+               if (!cladatum->comkey)
                        goto bad;
-               }
                rc = next_entry(cladatum->comkey, fp, len2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
                cladatum->comkey[len2] = '\0';
 
-               cladatum->comdatum = hashtab_search(p->p_commons.table,
-                                                   cladatum->comkey);
+               rc = -EINVAL;
+               cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey);
                if (!cladatum->comdatum) {
-                       printk(KERN_ERR "SELinux:  unknown common %s\n",
-                              cladatum->comkey);
-                       rc = -EINVAL;
+                       printk(KERN_ERR "SELinux:  unknown common %s\n", cladatum->comkey);
                        goto bad;
                }
        }
@@ -1211,7 +1235,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
                /* grab the validatetrans rules */
                rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
+               if (rc)
                        goto bad;
                ncons = le32_to_cpu(buf[0]);
                rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
@@ -1223,12 +1247,10 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        if (rc)
                goto bad;
 
-       rc = 0;
-out:
-       return rc;
+       return 0;
 bad:
        cls_destroy(key, cladatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int role_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1239,17 +1261,16 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        role = kzalloc(sizeof(*role), GFP_KERNEL);
-       if (!role) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!role)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 3;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1257,13 +1278,13 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                role->bounds = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
+
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1276,10 +1297,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
                goto bad;
 
        if (strcmp(key, OBJECT_R) == 0) {
+               rc = -EINVAL;
                if (role->value != OBJECT_R_VAL) {
                        printk(KERN_ERR "SELinux: Role %s has wrong value %d\n",
                               OBJECT_R, role->value);
-                       rc = -EINVAL;
                        goto bad;
                }
                rc = 0;
@@ -1289,11 +1310,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, role);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        role_destroy(key, role, NULL);
-       goto out;
+       return rc;
 }
 
 static int type_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1304,17 +1324,16 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[4];
        u32 len;
 
+       rc = -ENOMEM;
        typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
-       if (!typdatum) {
-               rc = -ENOMEM;
-               return rc;
-       }
+       if (!typdatum)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 4;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1332,24 +1351,22 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
                typdatum->primary = le32_to_cpu(buf[2]);
        }
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, typdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        type_destroy(key, typdatum, NULL);
-       goto out;
+       return rc;
 }
 
 
@@ -1365,22 +1382,18 @@ static int mls_read_level(struct mls_level *lp, void *fp)
        memset(lp, 0, sizeof(*lp));
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: mls: truncated level\n");
-               goto bad;
+               return rc;
        }
        lp->sens = le32_to_cpu(buf[0]);
 
-       if (ebitmap_read(&lp->cat, fp)) {
-               printk(KERN_ERR "SELinux: mls:  error reading level "
-                      "categories\n");
-               goto bad;
+       rc = ebitmap_read(&lp->cat, fp);
+       if (rc) {
+               printk(KERN_ERR "SELinux: mls:  error reading level categories\n");
+               return rc;
        }
-
        return 0;
-
-bad:
-       return -EINVAL;
 }
 
 static int user_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1391,17 +1404,16 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
-       if (!usrdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!usrdatum)
+               goto bad;
 
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                to_read = 3;
 
        rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
@@ -1409,13 +1421,12 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
                usrdatum->bounds = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
@@ -1435,11 +1446,10 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = hashtab_insert(h, key, usrdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        user_destroy(key, usrdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1450,47 +1460,43 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[2];
        u32 len;
 
+       rc = -ENOMEM;
        levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
-       if (!levdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!levdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        levdatum->isalias = le32_to_cpu(buf[1]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
+       rc = -ENOMEM;
        levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
-       if (!levdatum->level) {
-               rc = -ENOMEM;
+       if (!levdatum->level)
                goto bad;
-       }
-       if (mls_read_level(levdatum->level, fp)) {
-               rc = -EINVAL;
+
+       rc = mls_read_level(levdatum->level, fp);
+       if (rc)
                goto bad;
-       }
 
        rc = hashtab_insert(h, key, levdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
+       return 0;
 bad:
        sens_destroy(key, levdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
@@ -1501,39 +1507,35 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
        __le32 buf[3];
        u32 len;
 
+       rc = -ENOMEM;
        catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
-       if (!catdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!catdatum)
+               goto bad;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        catdatum->value = le32_to_cpu(buf[1]);
        catdatum->isalias = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
+       if (!key)
                goto bad;
-       }
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto bad;
        key[len] = '\0';
 
        rc = hashtab_insert(h, key, catdatum);
        if (rc)
                goto bad;
-out:
-       return rc;
-
+       return 0;
 bad:
        cat_destroy(key, catdatum, NULL);
-       goto out;
+       return rc;
 }
 
 static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
@@ -1574,9 +1576,9 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap)
                        printk(KERN_ERR
                               "SELinux: boundary violated policy: "
                               "user=%s role=%s bounds=%s\n",
-                              p->p_user_val_to_name[user->value - 1],
-                              p->p_role_val_to_name[bit],
-                              p->p_user_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_USERS, user->value - 1),
+                              sym_name(p, SYM_ROLES, bit),
+                              sym_name(p, SYM_USERS, upper->value - 1));
 
                        return -EINVAL;
                }
@@ -1611,9 +1613,9 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)
                        printk(KERN_ERR
                               "SELinux: boundary violated policy: "
                               "role=%s type=%s bounds=%s\n",
-                              p->p_role_val_to_name[role->value - 1],
-                              p->p_type_val_to_name[bit],
-                              p->p_role_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_ROLES, role->value - 1),
+                              sym_name(p, SYM_TYPES, bit),
+                              sym_name(p, SYM_ROLES, upper->value - 1));
 
                        return -EINVAL;
                }
@@ -1624,11 +1626,11 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)
 
 static int type_bounds_sanity_check(void *key, void *datum, void *datap)
 {
-       struct type_datum *upper, *type;
+       struct type_datum *upper;
        struct policydb *p = datap;
        int depth = 0;
 
-       upper = type = datum;
+       upper = datum;
        while (upper->bounds) {
                if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
                        printk(KERN_ERR "SELinux: type %s: "
@@ -1637,12 +1639,15 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
                        return -EINVAL;
                }
 
-               upper = p->type_val_to_struct[upper->bounds - 1];
+               upper = flex_array_get_ptr(p->type_val_to_struct_array,
+                                          upper->bounds - 1);
+               BUG_ON(!upper);
+
                if (upper->attribute) {
                        printk(KERN_ERR "SELinux: type %s: "
                               "bounded by attribute %s",
                               (char *) key,
-                              p->p_type_val_to_name[upper->value - 1]);
+                              sym_name(p, SYM_TYPES, upper->value - 1));
                        return -EINVAL;
                }
        }
@@ -2055,13 +2060,14 @@ int policydb_read(struct policydb *p, void *fp)
 
        rc = policydb_init(p);
        if (rc)
-               goto out;
+               return rc;
 
        /* Read the magic number and string length. */
        rc = next_entry(buf, fp, sizeof(u32) * 2);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
+       rc = -EINVAL;
        if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
                printk(KERN_ERR "SELinux:  policydb magic number 0x%x does "
                       "not match expected magic number 0x%x\n",
@@ -2069,6 +2075,7 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
        }
 
+       rc = -EINVAL;
        len = le32_to_cpu(buf[1]);
        if (len != strlen(POLICYDB_STRING)) {
                printk(KERN_ERR "SELinux:  policydb string length %d does not "
@@ -2076,19 +2083,23 @@ int policydb_read(struct policydb *p, void *fp)
                       len, strlen(POLICYDB_STRING));
                goto bad;
        }
+
+       rc = -ENOMEM;
        policydb_str = kmalloc(len + 1, GFP_KERNEL);
        if (!policydb_str) {
                printk(KERN_ERR "SELinux:  unable to allocate memory for policydb "
                       "string of length %d\n", len);
-               rc = -ENOMEM;
                goto bad;
        }
+
        rc = next_entry(policydb_str, fp, len);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux:  truncated policydb string identifier\n");
                kfree(policydb_str);
                goto bad;
        }
+
+       rc = -EINVAL;
        policydb_str[len] = '\0';
        if (strcmp(policydb_str, POLICYDB_STRING)) {
                printk(KERN_ERR "SELinux:  policydb string %s does not match "
@@ -2102,9 +2113,10 @@ int policydb_read(struct policydb *p, void *fp)
 
        /* Read the version and table sizes. */
        rc = next_entry(buf, fp, sizeof(u32)*4);
-       if (rc < 0)
+       if (rc)
                goto bad;
 
+       rc = -EINVAL;
        p->policyvers = le32_to_cpu(buf[0]);
        if (p->policyvers < POLICYDB_VERSION_MIN ||
            p->policyvers > POLICYDB_VERSION_MAX) {
@@ -2117,6 +2129,7 @@ int policydb_read(struct policydb *p, void *fp)
        if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
                p->mls_enabled = 1;
 
+               rc = -EINVAL;
                if (p->policyvers < POLICYDB_VERSION_MLS) {
                        printk(KERN_ERR "SELinux: security policydb version %d "
                                "(MLS) not backwards compatible\n",
@@ -2127,14 +2140,19 @@ int policydb_read(struct policydb *p, void *fp)
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
-       if (p->policyvers >= POLICYDB_VERSION_POLCAP &&
-           ebitmap_read(&p->policycaps, fp) != 0)
-               goto bad;
+       if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
+               rc = ebitmap_read(&p->policycaps, fp);
+               if (rc)
+                       goto bad;
+       }
 
-       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
-           ebitmap_read(&p->permissive_map, fp) != 0)
-               goto bad;
+       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
+               rc = ebitmap_read(&p->permissive_map, fp);
+               if (rc)
+                       goto bad;
+       }
 
+       rc = -EINVAL;
        info = policydb_lookup_compat(p->policyvers);
        if (!info) {
                printk(KERN_ERR "SELinux:  unable to find policy compat info "
@@ -2142,6 +2160,7 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
        }
 
+       rc = -EINVAL;
        if (le32_to_cpu(buf[2]) != info->sym_num ||
                le32_to_cpu(buf[3]) != info->ocon_num) {
                printk(KERN_ERR "SELinux:  policydb table sizes (%d,%d) do "
@@ -2153,7 +2172,7 @@ int policydb_read(struct policydb *p, void *fp)
 
        for (i = 0; i < info->sym_num; i++) {
                rc = next_entry(buf, fp, sizeof(u32)*2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
                nprim = le32_to_cpu(buf[0]);
                nel = le32_to_cpu(buf[1]);
@@ -2177,78 +2196,73 @@ int policydb_read(struct policydb *p, void *fp)
        }
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto bad;
        nel = le32_to_cpu(buf[0]);
        ltr = NULL;
        for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
                tr = kzalloc(sizeof(*tr), GFP_KERNEL);
-               if (!tr) {
-                       rc = -ENOMEM;
+               if (!tr)
                        goto bad;
-               }
                if (ltr)
                        ltr->next = tr;
                else
                        p->role_tr = tr;
                rc = next_entry(buf, fp, sizeof(u32)*3);
-               if (rc < 0)
+               if (rc)
                        goto bad;
+
+               rc = -EINVAL;
                tr->role = le32_to_cpu(buf[0]);
                tr->type = le32_to_cpu(buf[1]);
                tr->new_role = le32_to_cpu(buf[2]);
                if (!policydb_role_isvalid(p, tr->role) ||
                    !policydb_type_isvalid(p, tr->type) ||
-                   !policydb_role_isvalid(p, tr->new_role)) {
-                       rc = -EINVAL;
+                   !policydb_role_isvalid(p, tr->new_role))
                        goto bad;
-               }
                ltr = tr;
        }
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       if (rc)
                goto bad;
        nel = le32_to_cpu(buf[0]);
        lra = NULL;
        for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
                ra = kzalloc(sizeof(*ra), GFP_KERNEL);
-               if (!ra) {
-                       rc = -ENOMEM;
+               if (!ra)
                        goto bad;
-               }
                if (lra)
                        lra->next = ra;
                else
                        p->role_allow = ra;
                rc = next_entry(buf, fp, sizeof(u32)*2);
-               if (rc < 0)
+               if (rc)
                        goto bad;
+
+               rc = -EINVAL;
                ra->role = le32_to_cpu(buf[0]);
                ra->new_role = le32_to_cpu(buf[1]);
                if (!policydb_role_isvalid(p, ra->role) ||
-                   !policydb_role_isvalid(p, ra->new_role)) {
-                       rc = -EINVAL;
+                   !policydb_role_isvalid(p, ra->new_role))
                        goto bad;
-               }
                lra = ra;
        }
 
-       rc = policydb_index_classes(p);
-       if (rc)
-               goto bad;
-
-       rc = policydb_index_others(p);
+       rc = policydb_index(p);
        if (rc)
                goto bad;
 
+       rc = -EINVAL;
        p->process_class = string_to_security_class(p, "process");
        if (!p->process_class)
                goto bad;
-       p->process_trans_perms = string_to_av_perm(p, p->process_class,
-                                                  "transition");
-       p->process_trans_perms |= string_to_av_perm(p, p->process_class,
-                                                   "dyntransition");
+
+       rc = -EINVAL;
+       p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
+       p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
        if (!p->process_trans_perms)
                goto bad;
 
@@ -2301,8 +2315,846 @@ int policydb_read(struct policydb *p, void *fp)
 out:
        return rc;
 bad:
-       if (!rc)
-               rc = -EINVAL;
        policydb_destroy(p);
        goto out;
 }
+
+/*
+ * Write a MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_level(struct mls_level *l, void *fp)
+{
+       __le32 buf[1];
+       int rc;
+
+       buf[0] = cpu_to_le32(l->sens);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&l->cat, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * Write a MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_range_helper(struct mls_range *r, void *fp)
+{
+       __le32 buf[3];
+       size_t items;
+       int rc, eq;
+
+       eq = mls_level_eq(&r->level[1], &r->level[0]);
+
+       if (eq)
+               items = 2;
+       else
+               items = 3;
+       buf[0] = cpu_to_le32(items-1);
+       buf[1] = cpu_to_le32(r->level[0].sens);
+       if (!eq)
+               buf[2] = cpu_to_le32(r->level[1].sens);
+
+       BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
+
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&r->level[0].cat, fp);
+       if (rc)
+               return rc;
+       if (!eq) {
+               rc = ebitmap_write(&r->level[1].cat, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int sens_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct level_datum *levdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[2];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(levdatum->isalias);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_level(levdatum->level, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int cat_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct cat_datum *catdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[3];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(catdatum->value);
+       buf[2] = cpu_to_le32(catdatum->isalias);
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int role_trans_write(struct role_trans *r, void *fp)
+{
+       struct role_trans *tr;
+       u32 buf[3];
+       size_t nel;
+       int rc;
+
+       nel = 0;
+       for (tr = r; tr; tr = tr->next)
+               nel++;
+       buf[0] = cpu_to_le32(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;
+       }
+
+       return 0;
+}
+
+static int role_allow_write(struct role_allow *r, void *fp)
+{
+       struct role_allow *ra;
+       u32 buf[2];
+       size_t nel;
+       int rc;
+
+       nel = 0;
+       for (ra = r; ra; ra = ra->next)
+               nel++;
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (ra = r; ra; ra = ra->next) {
+               buf[0] = cpu_to_le32(ra->role);
+               buf[1] = cpu_to_le32(ra->new_role);
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
+/*
+ * Write a security context structure
+ * to a policydb binary representation file.
+ */
+static int context_write(struct policydb *p, struct context *c,
+                        void *fp)
+{
+       int rc;
+       __le32 buf[3];
+
+       buf[0] = cpu_to_le32(c->user);
+       buf[1] = cpu_to_le32(c->role);
+       buf[2] = cpu_to_le32(c->type);
+
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_range_helper(&c->range, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * The following *_write functions are used to
+ * write the symbol data to a policy database
+ * binary representation file.
+ */
+
+static int perm_write(void *vkey, void *datum, void *fp)
+{
+       char *key = vkey;
+       struct perm_datum *perdatum = datum;
+       __le32 buf[2];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(perdatum->value);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int common_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct common_datum *comdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[4];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       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);
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(comdatum->permissions.table, perm_write, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int write_cons_helper(struct policydb *p, struct constraint_node *node,
+                            void *fp)
+{
+       struct constraint_node *c;
+       struct constraint_expr *e;
+       __le32 buf[3];
+       u32 nel;
+       int rc;
+
+       for (c = node; c; c = c->next) {
+               nel = 0;
+               for (e = c->expr; e; e = e->next)
+                       nel++;
+               buf[0] = cpu_to_le32(c->permissions);
+               buf[1] = cpu_to_le32(nel);
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+               for (e = c->expr; e; e = e->next) {
+                       buf[0] = cpu_to_le32(e->expr_type);
+                       buf[1] = cpu_to_le32(e->attr);
+                       buf[2] = cpu_to_le32(e->op);
+                       rc = put_entry(buf, sizeof(u32), 3, fp);
+                       if (rc)
+                               return rc;
+
+                       switch (e->expr_type) {
+                       case CEXPR_NAMES:
+                               rc = ebitmap_write(&e->names, fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int class_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct class_datum *cladatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       struct constraint_node *c;
+       __le32 buf[6];
+       u32 ncons;
+       size_t len, len2;
+       int rc;
+
+       len = strlen(key);
+       if (cladatum->comkey)
+               len2 = strlen(cladatum->comkey);
+       else
+               len2 = 0;
+
+       ncons = 0;
+       for (c = cladatum->constraints; c; c = c->next)
+               ncons++;
+
+       buf[0] = cpu_to_le32(len);
+       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[5] = cpu_to_le32(ncons);
+       rc = put_entry(buf, sizeof(u32), 6, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       if (cladatum->comkey) {
+               rc = put_entry(cladatum->comkey, 1, len2, fp);
+               if (rc)
+                       return rc;
+       }
+
+       rc = hashtab_map(cladatum->permissions.table, perm_write, fp);
+       if (rc)
+               return rc;
+
+       rc = write_cons_helper(p, cladatum->constraints, fp);
+       if (rc)
+               return rc;
+
+       /* write out the validatetrans rule */
+       ncons = 0;
+       for (c = cladatum->validatetrans; c; c = c->next)
+               ncons++;
+
+       buf[0] = cpu_to_le32(ncons);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = write_cons_helper(p, cladatum->validatetrans, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int role_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct role_datum *role = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       __le32 buf[3];
+       size_t items, len;
+       int rc;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(role->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               buf[items++] = cpu_to_le32(role->bounds);
+
+       BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
+
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&role->dominates, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&role->types, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int type_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct type_datum *typdatum = datum;
+       struct policy_data *pd = ptr;
+       struct policydb *p = pd->p;
+       void *fp = pd->fp;
+       __le32 buf[4];
+       int rc;
+       size_t items, len;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(typdatum->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+               u32 properties = 0;
+
+               if (typdatum->primary)
+                       properties |= TYPEDATUM_PROPERTY_PRIMARY;
+
+               if (typdatum->attribute)
+                       properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+
+               buf[items++] = cpu_to_le32(properties);
+               buf[items++] = cpu_to_le32(typdatum->bounds);
+       } else {
+               buf[items++] = cpu_to_le32(typdatum->primary);
+       }
+       BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int user_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct user_datum *usrdatum = datum;
+       struct policy_data *pd = ptr;
+       struct policydb *p = pd->p;
+       void *fp = pd->fp;
+       __le32 buf[3];
+       size_t items, len;
+       int rc;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(usrdatum->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               buf[items++] = cpu_to_le32(usrdatum->bounds);
+       BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&usrdatum->roles, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_range_helper(&usrdatum->range, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_level(&usrdatum->dfltlevel, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int (*write_f[SYM_NUM]) (void *key, void *datum,
+                               void *datap) =
+{
+       common_write,
+       class_write,
+       role_write,
+       type_write,
+       user_write,
+       cond_write_bool,
+       sens_write,
+       cat_write,
+};
+
+static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
+                         void *fp)
+{
+       unsigned int i, j, rc;
+       size_t nel, len;
+       __le32 buf[3];
+       u32 nodebuf[8];
+       struct ocontext *c;
+       for (i = 0; i < info->ocon_num; i++) {
+               nel = 0;
+               for (c = p->ocontexts[i]; c; c = c->next)
+                       nel++;
+               buf[0] = cpu_to_le32(nel);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               for (c = p->ocontexts[i]; c; c = c->next) {
+                       switch (i) {
+                       case OCON_ISID:
+                               buf[0] = cpu_to_le32(c->sid[0]);
+                               rc = put_entry(buf, sizeof(u32), 1, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_FS:
+                       case OCON_NETIF:
+                               len = strlen(c->u.name);
+                               buf[0] = cpu_to_le32(len);
+                               rc = put_entry(buf, sizeof(u32), 1, fp);
+                               if (rc)
+                                       return rc;
+                               rc = put_entry(c->u.name, 1, len, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[1], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_PORT:
+                               buf[0] = cpu_to_le32(c->u.port.protocol);
+                               buf[1] = cpu_to_le32(c->u.port.low_port);
+                               buf[2] = cpu_to_le32(c->u.port.high_port);
+                               rc = put_entry(buf, sizeof(u32), 3, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_NODE:
+                               nodebuf[0] = c->u.node.addr; /* network order */
+                               nodebuf[1] = c->u.node.mask; /* network order */
+                               rc = put_entry(nodebuf, sizeof(u32), 2, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_FSUSE:
+                               buf[0] = cpu_to_le32(c->v.behavior);
+                               len = strlen(c->u.name);
+                               buf[1] = cpu_to_le32(len);
+                               rc = put_entry(buf, sizeof(u32), 2, fp);
+                               if (rc)
+                                       return rc;
+                               rc = put_entry(c->u.name, 1, len, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_NODE6:
+                               for (j = 0; j < 4; j++)
+                                       nodebuf[j] = c->u.node6.addr[j]; /* network order */
+                               for (j = 0; j < 4; j++)
+                                       nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
+                               rc = put_entry(nodebuf, sizeof(u32), 8, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int genfs_write(struct policydb *p, void *fp)
+{
+       struct genfs *genfs;
+       struct ocontext *c;
+       size_t len;
+       __le32 buf[1];
+       int rc;
+
+       len = 0;
+       for (genfs = p->genfs; genfs; genfs = genfs->next)
+               len++;
+       buf[0] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (genfs = p->genfs; genfs; genfs = genfs->next) {
+               len = strlen(genfs->fstype);
+               buf[0] = cpu_to_le32(len);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               rc = put_entry(genfs->fstype, 1, len, fp);
+               if (rc)
+                       return rc;
+               len = 0;
+               for (c = genfs->head; c; c = c->next)
+                       len++;
+               buf[0] = cpu_to_le32(len);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               for (c = genfs->head; c; c = c->next) {
+                       len = strlen(c->u.name);
+                       buf[0] = cpu_to_le32(len);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+                       rc = put_entry(c->u.name, 1, len, fp);
+                       if (rc)
+                               return rc;
+                       buf[0] = cpu_to_le32(c->v.sclass);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+                       rc = context_write(p, &c->context[0], fp);
+                       if (rc)
+                               return rc;
+               }
+       }
+       return 0;
+}
+
+static int range_count(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];
+       struct range_trans *rt = key;
+       struct mls_range *r = data;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       int rc;
+
+       buf[0] = cpu_to_le32(rt->source_type);
+       buf[1] = cpu_to_le32(rt->target_type);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+       if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+               buf[0] = cpu_to_le32(rt->target_class);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+       }
+       rc = mls_write_range_helper(r, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int range_write(struct policydb *p, void *fp)
+{
+       size_t nel;
+       __le32 buf[1];
+       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, range_count, &nel);
+       if (rc)
+               return rc;
+
+       buf[0] = cpu_to_le32(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);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * Write the configuration data in a policy database
+ * structure to a policy database binary representation
+ * file.
+ */
+int policydb_write(struct policydb *p, void *fp)
+{
+       unsigned int i, num_syms;
+       int rc;
+       __le32 buf[4];
+       u32 config;
+       size_t len;
+       struct policydb_compat_info *info;
+
+       /*
+        * refuse to write policy older than compressed avtab
+        * to simplify the writer.  There are other tests dropped
+        * since we assume this throughout the writer code.  Be
+        * careful if you ever try to remove this restriction
+        */
+       if (p->policyvers < POLICYDB_VERSION_AVTAB) {
+               printk(KERN_ERR "SELinux: refusing to write policy version %d."
+                      "  Because it is less than version %d\n", p->policyvers,
+                      POLICYDB_VERSION_AVTAB);
+               return -EINVAL;
+       }
+
+       config = 0;
+       if (p->mls_enabled)
+               config |= POLICYDB_CONFIG_MLS;
+
+       if (p->reject_unknown)
+               config |= REJECT_UNKNOWN;
+       if (p->allow_unknown)
+               config |= ALLOW_UNKNOWN;
+
+       /* Write the magic number and string identifiers. */
+       buf[0] = cpu_to_le32(POLICYDB_MAGIC);
+       len = strlen(POLICYDB_STRING);
+       buf[1] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+       rc = put_entry(POLICYDB_STRING, 1, len, fp);
+       if (rc)
+               return rc;
+
+       /* Write the version, config, and table sizes. */
+       info = policydb_lookup_compat(p->policyvers);
+       if (!info) {
+               printk(KERN_ERR "SELinux: compatibility lookup failed for policy "
+                   "version %d", p->policyvers);
+               return -EINVAL;
+       }
+
+       buf[0] = cpu_to_le32(p->policyvers);
+       buf[1] = cpu_to_le32(config);
+       buf[2] = cpu_to_le32(info->sym_num);
+       buf[3] = cpu_to_le32(info->ocon_num);
+
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
+
+       if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
+               rc = ebitmap_write(&p->policycaps, fp);
+               if (rc)
+                       return rc;
+       }
+
+       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
+               rc = ebitmap_write(&p->permissive_map, fp);
+               if (rc)
+                       return rc;
+       }
+
+       num_syms = info->sym_num;
+       for (i = 0; i < num_syms; i++) {
+               struct policy_data pd;
+
+               pd.fp = fp;
+               pd.p = p;
+
+               buf[0] = cpu_to_le32(p->symtab[i].nprim);
+               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);
+               if (rc)
+                       return rc;
+       }
+
+       rc = avtab_write(p, &p->te_avtab, fp);
+       if (rc)
+               return rc;
+
+       rc = cond_write_list(p, p->cond_list, fp);
+       if (rc)
+               return rc;
+
+       rc = role_trans_write(p->role_tr, fp);
+       if (rc)
+               return rc;
+
+       rc = role_allow_write(p->role_allow, fp);
+       if (rc)
+               return rc;
+
+       rc = ocontext_write(p, info, fp);
+       if (rc)
+               return rc;
+
+       rc = genfs_write(p, fp);
+       if (rc)
+               return rc;
+
+       rc = range_write(p, fp);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < p->p_types.nprim; i++) {
+               struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+
+               BUG_ON(!e);
+               rc = ebitmap_write(e, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}