Skip to content

Commit 9208c05

Browse files
committed
apparmor: add support for 2^24 states to the dfa state machine.
Currently the dfa state machine is limited by its default, next, and check tables using u16. Allow loading of u32 tables, and if u16 tables are loaded map them to u32. The number of states allowed does not increase to 2^32 because the base table uses the top 8 bits of its u32 for flags. Moving the flags into a separate table allowing a full 2^32 bit range wil be done in a separate patch. Link: https://gitlab.com/apparmor/apparmor/-/issues/419 Signed-off-by: John Johansen <[email protected]>
1 parent db93ca1 commit 9208c05

File tree

3 files changed

+83
-25
lines changed

3 files changed

+83
-25
lines changed

security/apparmor/apparmorfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
23662366
AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
23672367
AA_SFS_FILE_U64("permstable32_version", 1),
23682368
AA_SFS_FILE_STRING("permstable32", PERMS32STR),
2369+
AA_SFS_FILE_U64("state32", 1),
23692370
AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined),
23702371
{ }
23712372
};

security/apparmor/include/match.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ struct table_header {
8787
char td_data[];
8888
};
8989

90-
#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
90+
#define TABLE_DATAU16(TABLE) ((u16 *)((TABLE)->td_data))
91+
#define TABLE_DATAU32(TABLE) ((u32 *)((TABLE)->td_data))
92+
#define DEFAULT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
9193
#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
92-
#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
93-
#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
94+
#define NEXT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
95+
#define CHECK_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
9496
#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
9597
#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
9698
#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))

security/apparmor/match.c

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,42 @@ void aa_dfa_free_kref(struct kref *kref)
247247
dfa_free(dfa);
248248
}
249249

250+
251+
252+
/**
253+
* remap_data16_to_data32 - remap u16 @old table to a u32 based table
254+
* @old: table to remap
255+
*
256+
* Returns: new table with u32 entries instead of u16.
257+
*
258+
* Note: will free @old so caller does not have to
259+
*/
260+
static struct table_header *remap_data16_to_data32(struct table_header *old)
261+
{
262+
struct table_header *new;
263+
size_t tsize;
264+
u32 i;
265+
266+
tsize = table_size(old->td_lolen, YYTD_DATA32);
267+
new = kvzalloc(tsize, GFP_KERNEL);
268+
if (!new) {
269+
kvfree(old);
270+
return NULL;
271+
}
272+
new->td_id = old->td_id;
273+
new->td_flags = YYTD_DATA32;
274+
new->td_lolen = old->td_lolen;
275+
276+
for (i = 0; i < old->td_lolen; i++)
277+
TABLE_DATAU32(new)[i] = (u32) TABLE_DATAU16(old)[i];
278+
279+
kvfree(old);
280+
if (is_vmalloc_addr(new))
281+
vm_unmap_aliases();
282+
283+
return new;
284+
}
285+
250286
/**
251287
* aa_dfa_unpack - unpack the binary tables of a serialized dfa
252288
* @blob: aligned serialized stream of data to unpack (NOT NULL)
@@ -326,8 +362,10 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
326362
case YYTD_ID_DEF:
327363
case YYTD_ID_NXT:
328364
case YYTD_ID_CHK:
329-
if (table->td_flags != YYTD_DATA16)
365+
if (!(table->td_flags == YYTD_DATA16 ||
366+
table->td_flags == YYTD_DATA32)) {
330367
goto fail;
368+
}
331369
break;
332370
case YYTD_ID_EC:
333371
if (table->td_flags != YYTD_DATA8)
@@ -342,6 +380,23 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
342380
dfa->tables[table->td_id] = table;
343381
data += table_size(table->td_lolen, table->td_flags);
344382
size -= table_size(table->td_lolen, table->td_flags);
383+
384+
/*
385+
* this remapping has to be done after incrementing data above
386+
* for now straight remap, later have dfa support both
387+
*/
388+
switch (table->td_id) {
389+
case YYTD_ID_DEF:
390+
case YYTD_ID_NXT:
391+
case YYTD_ID_CHK:
392+
if (table->td_flags == YYTD_DATA16) {
393+
table = remap_data16_to_data32(table);
394+
if (!table)
395+
goto fail;
396+
}
397+
dfa->tables[table->td_id] = table;
398+
break;
399+
}
345400
table = NULL;
346401
}
347402
error = verify_table_headers(dfa->tables, flags);
@@ -395,10 +450,10 @@ do { \
395450
aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start,
396451
const char *str, int len)
397452
{
398-
u16 *def = DEFAULT_TABLE(dfa);
453+
u32 *def = DEFAULT_TABLE(dfa);
399454
u32 *base = BASE_TABLE(dfa);
400-
u16 *next = NEXT_TABLE(dfa);
401-
u16 *check = CHECK_TABLE(dfa);
455+
u32 *next = NEXT_TABLE(dfa);
456+
u32 *check = CHECK_TABLE(dfa);
402457
aa_state_t state = start;
403458

404459
if (state == DFA_NOMATCH)
@@ -434,10 +489,10 @@ aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start,
434489
*/
435490
aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str)
436491
{
437-
u16 *def = DEFAULT_TABLE(dfa);
492+
u32 *def = DEFAULT_TABLE(dfa);
438493
u32 *base = BASE_TABLE(dfa);
439-
u16 *next = NEXT_TABLE(dfa);
440-
u16 *check = CHECK_TABLE(dfa);
494+
u32 *next = NEXT_TABLE(dfa);
495+
u32 *check = CHECK_TABLE(dfa);
441496
aa_state_t state = start;
442497

443498
if (state == DFA_NOMATCH)
@@ -472,10 +527,10 @@ aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str)
472527
*/
473528
aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c)
474529
{
475-
u16 *def = DEFAULT_TABLE(dfa);
530+
u32 *def = DEFAULT_TABLE(dfa);
476531
u32 *base = BASE_TABLE(dfa);
477-
u16 *next = NEXT_TABLE(dfa);
478-
u16 *check = CHECK_TABLE(dfa);
532+
u32 *next = NEXT_TABLE(dfa);
533+
u32 *check = CHECK_TABLE(dfa);
479534

480535
/* current state is <state>, matching character *str */
481536
if (dfa->tables[YYTD_ID_EC]) {
@@ -490,10 +545,10 @@ aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c)
490545

491546
aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state)
492547
{
493-
u16 *def = DEFAULT_TABLE(dfa);
548+
u32 *def = DEFAULT_TABLE(dfa);
494549
u32 *base = BASE_TABLE(dfa);
495-
u16 *next = NEXT_TABLE(dfa);
496-
u16 *check = CHECK_TABLE(dfa);
550+
u32 *next = NEXT_TABLE(dfa);
551+
u32 *check = CHECK_TABLE(dfa);
497552
u32 b = (base)[(state)];
498553

499554
if (!(b & MATCH_FLAG_OOB_TRANSITION))
@@ -521,10 +576,10 @@ aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state)
521576
aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start,
522577
const char *str, const char **retpos)
523578
{
524-
u16 *def = DEFAULT_TABLE(dfa);
579+
u32 *def = DEFAULT_TABLE(dfa);
525580
u32 *base = BASE_TABLE(dfa);
526-
u16 *next = NEXT_TABLE(dfa);
527-
u16 *check = CHECK_TABLE(dfa);
581+
u32 *next = NEXT_TABLE(dfa);
582+
u32 *check = CHECK_TABLE(dfa);
528583
u32 *accept = ACCEPT_TABLE(dfa);
529584
aa_state_t state = start, pos;
530585

@@ -582,10 +637,10 @@ aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start,
582637
aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start,
583638
const char *str, int n, const char **retpos)
584639
{
585-
u16 *def = DEFAULT_TABLE(dfa);
640+
u32 *def = DEFAULT_TABLE(dfa);
586641
u32 *base = BASE_TABLE(dfa);
587-
u16 *next = NEXT_TABLE(dfa);
588-
u16 *check = CHECK_TABLE(dfa);
642+
u32 *next = NEXT_TABLE(dfa);
643+
u32 *check = CHECK_TABLE(dfa);
589644
u32 *accept = ACCEPT_TABLE(dfa);
590645
aa_state_t state = start, pos;
591646

@@ -658,10 +713,10 @@ static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start,
658713
const char *str, struct match_workbuf *wb,
659714
unsigned int *count)
660715
{
661-
u16 *def = DEFAULT_TABLE(dfa);
716+
u32 *def = DEFAULT_TABLE(dfa);
662717
u32 *base = BASE_TABLE(dfa);
663-
u16 *next = NEXT_TABLE(dfa);
664-
u16 *check = CHECK_TABLE(dfa);
718+
u32 *next = NEXT_TABLE(dfa);
719+
u32 *check = CHECK_TABLE(dfa);
665720
aa_state_t state = start, pos;
666721

667722
AA_BUG(!dfa);

0 commit comments

Comments
 (0)