Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

apparmor: mitigate parser generating large xtables

Some versions of the parser are generating an xtable transition per
state in the state machine, even when the state machine isn't using
the transition table.

The parser bug is triggered by
commit 2e12c5f06017 ("apparmor: add additional flags to extended permission.")

In addition to fixing this in userspace, mitigate this in the kernel
as part of the policy verification checks by detecting this situation
and adjusting to what is actually used, or if not used at all freeing
it, so we are not wasting unneeded memory on policy.

Fixes: 2e12c5f06017 ("apparmor: add additional flags to extended permission.")
Signed-off-by: John Johansen <john.johansen@canonical.com>

+45 -6
+1
security/apparmor/include/lib.h
··· 125 125 }; 126 126 127 127 void aa_free_str_table(struct aa_str_table *table); 128 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp); 128 129 129 130 struct counted_str { 130 131 struct kref count;
+23
security/apparmor/lib.c
··· 116 116 aa_g_debug); 117 117 } 118 118 119 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp) 120 + { 121 + char **n; 122 + int i; 123 + 124 + if (t->size == newsize) 125 + return true; 126 + n = kcalloc(newsize, sizeof(*n), gfp); 127 + if (!n) 128 + return false; 129 + for (i = 0; i < min(t->size, newsize); i++) 130 + n[i] = t->table[i]; 131 + for (; i < t->size; i++) 132 + kfree_sensitive(t->table[i]); 133 + if (newsize > t->size) 134 + memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n)); 135 + kfree_sensitive(t->table); 136 + t->table = n; 137 + t->size = newsize; 138 + 139 + return true; 140 + } 141 + 119 142 /** 120 143 * aa_free_str_table - free entries str table 121 144 * @t: the string table to free (MAYBE NULL)
+21 -6
security/apparmor/policy_unpack.c
··· 802 802 if (!pdb->dfa && pdb->trans.table) 803 803 aa_free_str_table(&pdb->trans); 804 804 805 - /* TODO: move compat mapping here, requires dfa merging first */ 806 - /* TODO: move verify here, it has to be done after compat mappings */ 805 + /* TODO: 806 + * - move compat mapping here, requires dfa merging first 807 + * - move verify here, it has to be done after compat mappings 808 + * - move free of unneeded trans table here, has to be done 809 + * after perm mapping. 810 + */ 807 811 out: 808 812 *policy = pdb; 809 813 return 0; ··· 1246 1242 static bool verify_perms(struct aa_policydb *pdb) 1247 1243 { 1248 1244 int i; 1245 + int xidx, xmax = -1; 1249 1246 1250 1247 for (i = 0; i < pdb->size; i++) { 1251 1248 if (!verify_perm(&pdb->perms[i])) 1252 1249 return false; 1253 1250 /* verify indexes into str table */ 1254 - if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE && 1255 - (pdb->perms[i].xindex & AA_X_INDEX_MASK) >= pdb->trans.size) 1256 - return false; 1251 + if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE) { 1252 + xidx = pdb->perms[i].xindex & AA_X_INDEX_MASK; 1253 + if (xidx >= pdb->trans.size) 1254 + return false; 1255 + if (xmax < xidx) 1256 + xmax = xidx; 1257 + } 1257 1258 if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size) 1258 1259 return false; 1259 1260 if (pdb->perms[i].label && 1260 1261 pdb->perms[i].label >= pdb->trans.size) 1261 1262 return false; 1262 1263 } 1263 - 1264 + /* deal with incorrectly constructed string tables */ 1265 + if (xmax == -1) { 1266 + aa_free_str_table(&pdb->trans); 1267 + } else if (pdb->trans.size > xmax + 1) { 1268 + if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL)) 1269 + return false; 1270 + } 1264 1271 return true; 1265 1272 } 1266 1273