perm_read() bounds a permission value by SEL_VEC_MAX but never by the nprim of the owning class or common, which is taken verbatim from the policy image. security_get_permissions() then writes perms[value - 1] into an nprim-sized kcalloc() array, so a class declaring fewer permissions than its largest permission value drives an out-of-bounds heap write. The top-level symbol tables are validated this way; the nested per-class permission table is not. Reject a permission whose value exceeds nprim, which is already set when perm_read() runs. Well-formed policies are unaffected.
Unified · Split
| @@ -1175,6 +1175,9 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f · 1174 unmodified lines | |||
| 1175 | rc = -EINVAL; | 1175 | rc = -EINVAL; |
| 1176 | if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX) | 1176 | if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX) |
| 1177 | goto bad; | 1177 | goto bad; |
| 1178 | /* indexes an nprim-sized array in security_get_permissions() */ | ||
| 1179 | if (perdatum->value > s->nprim) | ||
| 1180 | goto bad; | ||
| 1178 | 1181 | ||
| 1179 | rc = str_read(&key, GFP_KERNEL, fp, len); | 1182 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1180 | if (rc) | 1183 | if (rc) |