selinux: convert part of the sym_val_to_name array to use flex_array

The sym_val_to_name type array can be quite large as it grows linearly with
the number of types.  With known policies having over 5k types these
allocations are growing large enough that they are likely to fail.  Convert
those to flex_array so no allocation is larger than PAGE_SIZE

Signed-off-by: Eric Paris <eparis@redhat.com>
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index af41fdf..5adca67 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -254,12 +254,17 @@
 {
 	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;
 }
 
@@ -267,12 +272,16 @@
 {
 	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;
 }
@@ -281,6 +290,7 @@
 {
 	struct policydb *p;
 	struct role_datum *role;
+	struct flex_array *fa;
 
 	role = datum;
 	p = datap;
@@ -288,7 +298,11 @@
 	    || 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;
 }
@@ -297,6 +311,7 @@
 {
 	struct policydb *p;
 	struct type_datum *typdatum;
+	struct flex_array *fa;
 
 	typdatum = datum;
 	p = datap;
@@ -306,10 +321,13 @@
 		    || typdatum->value > p->p_types.nprim
 		    || typdatum->bounds > p->p_types.nprim)
 			return -EINVAL;
-		p->p_type_val_to_name[typdatum->value - 1] = key;
-		/* this flex array was all preallocated, this cannot fail */
-		if (flex_array_put_ptr(p->type_val_to_struct_array,
-				       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();
 	}
@@ -321,6 +339,7 @@
 {
 	struct policydb *p;
 	struct user_datum *usrdatum;
+	struct flex_array *fa;
 
 	usrdatum = datum;
 	p = datap;
@@ -328,7 +347,11 @@
 	    || usrdatum->value > p->p_users.nprim
 	    || usrdatum->bounds > p->p_users.nprim)
 		return -EINVAL;
-	p->p_user_val_to_name[usrdatum->value - 1] = key;
+
+	fa = p->sym_val_to_name[SYM_USERS];
+	if (flex_array_put_ptr(fa, usrdatum->value - 1, key,
+			       GFP_KERNEL | __GFP_ZERO))
+		BUG();
 	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
 	return 0;
 }
@@ -337,6 +360,7 @@
 {
 	struct policydb *p;
 	struct level_datum *levdatum;
+	struct flex_array *fa;
 
 	levdatum = datum;
 	p = datap;
@@ -345,7 +369,10 @@
 		if (!levdatum->level->sens ||
 		    levdatum->level->sens > p->p_levels.nprim)
 			return -EINVAL;
-		p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+		fa = p->sym_val_to_name[SYM_LEVELS];
+		if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key,
+				       GFP_KERNEL | __GFP_ZERO))
+			BUG();
 	}
 
 	return 0;
@@ -355,6 +382,7 @@
 {
 	struct policydb *p;
 	struct cat_datum *catdatum;
+	struct flex_array *fa;
 
 	catdatum = datum;
 	p = datap;
@@ -362,7 +390,10 @@
 	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;
@@ -392,9 +423,16 @@
 	int rc;
 
 	rc = -ENOMEM;
-	p->p_common_val_to_name =
-		kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL);
-	if (!p->p_common_val_to_name)
+	p->sym_val_to_name[SYM_COMMONS] = flex_array_alloc(sizeof(char *),
+							   p->p_commons.nprim,
+							   GFP_KERNEL | __GFP_ZERO);
+	if (!p->sym_val_to_name[SYM_COMMONS])
+		goto out;
+
+	rc = flex_array_prealloc(p->sym_val_to_name[SYM_COMMONS],
+				 0, p->p_commons.nprim - 1,
+				 GFP_KERNEL | __GFP_ZERO);
+	if (rc)
 		goto out;
 
 	rc = hashtab_map(p->p_commons.table, common_index, p);
@@ -408,9 +446,16 @@
 		goto out;
 
 	rc = -ENOMEM;
-	p->p_class_val_to_name =
-		kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL);
-	if (!p->p_class_val_to_name)
+	p->sym_val_to_name[SYM_CLASSES] = flex_array_alloc(sizeof(char *),
+							   p->p_classes.nprim,
+							   GFP_KERNEL | __GFP_ZERO);
+	if (!p->sym_val_to_name[SYM_CLASSES])
+		goto out;
+
+	rc = flex_array_prealloc(p->sym_val_to_name[SYM_CLASSES],
+				 0, p->p_classes.nprim - 1,
+				 GFP_KERNEL | __GFP_ZERO);
+	if (rc)
 		goto out;
 
 	rc = hashtab_map(p->p_classes.table, class_index, p);
@@ -507,10 +552,18 @@
 
 	for (i = SYM_ROLES; i < SYM_NUM; i++) {
 		rc = -ENOMEM;
-		p->sym_val_to_name[i] =
-			kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
+		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;
@@ -703,8 +756,10 @@
 		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);
@@ -1566,9 +1621,9 @@
 			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;
 		}
@@ -1603,9 +1658,9 @@
 			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;
 		}
@@ -1637,7 +1692,7 @@
 			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;
 		}
 	}