Skip to content

Commit aff426f

Browse files
committed
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 2e12c5f ("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: 2e12c5f ("apparmor: add additional flags to extended permission.") Signed-off-by: John Johansen <[email protected]>
1 parent b1f87be commit aff426f

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

security/apparmor/include/lib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct aa_str_table {
125125
};
126126

127127
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);
128129

129130
struct counted_str {
130131
struct kref count;

security/apparmor/lib.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,29 @@ int aa_print_debug_params(char *buffer)
116116
aa_g_debug);
117117
}
118118

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+
119142
/**
120143
* aa_free_str_table - free entries str table
121144
* @t: the string table to free (MAYBE NULL)

security/apparmor/policy_unpack.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,12 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
802802
if (!pdb->dfa && pdb->trans.table)
803803
aa_free_str_table(&pdb->trans);
804804

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+
*/
807811
out:
808812
*policy = pdb;
809813
return 0;
@@ -1242,21 +1246,32 @@ static bool verify_perm(struct aa_perms *perm)
12421246
static bool verify_perms(struct aa_policydb *pdb)
12431247
{
12441248
int i;
1249+
int xidx, xmax = -1;
12451250

12461251
for (i = 0; i < pdb->size; i++) {
12471252
if (!verify_perm(&pdb->perms[i]))
12481253
return false;
12491254
/* verify indexes into str table */
1250-
if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE &&
1251-
(pdb->perms[i].xindex & AA_X_INDEX_MASK) >= pdb->trans.size)
1252-
return false;
1255+
if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1256+
xidx = pdb->perms[i].xindex & AA_X_INDEX_MASK;
1257+
if (xidx >= pdb->trans.size)
1258+
return false;
1259+
if (xmax < xidx)
1260+
xmax = xidx;
1261+
}
12531262
if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size)
12541263
return false;
12551264
if (pdb->perms[i].label &&
12561265
pdb->perms[i].label >= pdb->trans.size)
12571266
return false;
12581267
}
1259-
1268+
/* deal with incorrectly constructed string tables */
1269+
if (xmax == -1) {
1270+
aa_free_str_table(&pdb->trans);
1271+
} else if (pdb->trans.size > xmax + 1) {
1272+
if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL))
1273+
return false;
1274+
}
12601275
return true;
12611276
}
12621277

0 commit comments

Comments
 (0)