/** * aa_dfa_match - traverse @dfa to find state @str stops at * @dfa: the dfa to match @str against (NOT NULL) * @start: the state of the dfa to start matching in * @str: the null terminated string of bytes to match against the dfa (NOT NULL) * * aa_dfa_match will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. * * Returns: final state reached after input is consumed */ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int state = start; if (state == 0) return 0; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ while (*str) match_char(state, def, base, next, check, equiv[(u8) *str++]); } else { /* default is direct to next state */ while (*str) match_char(state, def, base, next, check, (u8) *str++); } return state; }
/** * aa_dfa_next - step one character to the next state in the dfa * @dfa: the dfa to tranverse (NOT NULL) * @state: the state to start in * @c: the input character to transition on * * aa_dfa_match will step through the dfa by one input character @c * * Returns: state reach after input @c */ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, const char c) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int pos; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ pos = base_idx(base[state]) + equiv[(u8) c]; if (check[pos] == state) state = next[pos]; else state = def[state]; } else { /* default is direct to next state */ pos = base_idx(base[state]) + (u8) c; if (check[pos] == state) state = next[pos]; else state = def[state]; } return state; }
unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, const char c) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int pos; if (dfa->tables[YYTD_ID_EC]) { u8 *equiv = EQUIV_TABLE(dfa); pos = base[state] + equiv[(u8) c]; if (check[pos] == state) state = next[pos]; else state = def[state]; } else { pos = base[state] + (u8) c; if (check[pos] == state) state = next[pos]; else state = def[state]; } return state; }
/** * aa_dfa_next_state - traverse @dfa to find state @str stops at * @dfa: the dfa to match @str against * @start: the state of the dfa to start matching in * @str: the string to match against the dfa * * aa_dfa_next_state will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. */ unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start, const char *str) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int state = start, pos; if (state == 0) return 0; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC - 1]) { u8 *equiv = EQUIV_TABLE(dfa); while (*str) { pos = base[state] + equiv[(u8)*str++]; if (check[pos] == state) state = next[pos]; else state = def[state]; } } else { while (*str) { pos = base[state] + (u8)*str++; if (check[pos] == state) state = next[pos]; else state = def[state]; } } return state; }
/** * verify_dfa - verify that all the transitions and states in the dfa tables * are in bounds. * @dfa: dfa to test (NOT NULL) * @flags: flags controlling what type of accept table are acceptable * * Assumes dfa has gone through the first pass verification done by unpacking * NOTE: this does not valid accept table values * * Returns: %0 else error code on failure to verify */ static int verify_dfa(struct aa_dfa *dfa, int flags) { size_t i, state_count, trans_count; int error = -EPROTO; /* check that required tables exist */ if (!(dfa->tables[YYTD_ID_DEF] && dfa->tables[YYTD_ID_BASE] && dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) goto out; /* accept.size == default.size == base.size */ state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; if (ACCEPT1_FLAGS(flags)) { if (!dfa->tables[YYTD_ID_ACCEPT]) goto out; if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) goto out; } if (ACCEPT2_FLAGS(flags)) { if (!dfa->tables[YYTD_ID_ACCEPT2]) goto out; if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) goto out; } if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) goto out; /* next.size == chk.size */ trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) goto out; /* if equivalence classes then its table size must be 256 */ if (dfa->tables[YYTD_ID_EC] && dfa->tables[YYTD_ID_EC]->td_lolen != 256) goto out; if (flags & DFA_FLAG_VERIFY_STATES) { for (i = 0; i < state_count; i++) { if (DEFAULT_TABLE(dfa)[i] >= state_count) goto out; /* TODO: do check that DEF state recursion terminates */ if (BASE_TABLE(dfa)[i] >= trans_count + 256) goto out; } for (i = 0; i < trans_count; i++) { if (NEXT_TABLE(dfa)[i] >= state_count) goto out; if (CHECK_TABLE(dfa)[i] >= state_count) goto out; } } error = 0; out: return error; }
/** * verify_dfa - verify that transitions and states in the tables are in bounds. * @dfa: dfa to test (NOT NULL) * * Assumes dfa has gone through the first pass verification done by unpacking * NOTE: this does not valid accept table values * * Returns: %0 else error code on failure to verify */ static int verify_dfa(struct aa_dfa *dfa) { size_t i, state_count, trans_count; int error = -EPROTO; state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; for (i = 0; i < state_count; i++) { if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && (DEFAULT_TABLE(dfa)[i] >= state_count)) goto out; if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { pr_err("AppArmor DFA next/check upper bounds error\n"); goto out; } } for (i = 0; i < trans_count; i++) { if (NEXT_TABLE(dfa)[i] >= state_count) goto out; if (CHECK_TABLE(dfa)[i] >= state_count) goto out; } /* Now that all the other tables are verified, verify diffencoding */ for (i = 0; i < state_count; i++) { size_t j, k; for (j = i; (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); j = k) { k = DEFAULT_TABLE(dfa)[j]; if (j == k) goto out; if (k < j) break; /* already verified */ BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; } } error = 0; out: return error; }
/** * verify_dfa - verify that all the transitions and states in the dfa tables * are in bounds. * @dfa: dfa to test * * assumes dfa has gone through the verification done by unpacking */ int verify_dfa(struct aa_dfa *dfa) { size_t i, state_count, trans_count; int error = -EPROTO; /* check that required tables exist */ if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] && dfa->tables[YYTD_ID_DEF - 1] && dfa->tables[YYTD_ID_BASE - 1] && dfa->tables[YYTD_ID_NXT - 1] && dfa->tables[YYTD_ID_CHK - 1])) goto out; /* accept.size == default.size == base.size */ state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen; if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen && state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen)) goto out; /* next.size == chk.size */ trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen; if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen) goto out; /* if equivalence classes then its table size must be 256 */ if (dfa->tables[YYTD_ID_EC - 1] && dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256) goto out; for (i = 0; i < state_count; i++) { if (DEFAULT_TABLE(dfa)[i] >= state_count) goto out; if (BASE_TABLE(dfa)[i] >= trans_count + 256) goto out; } for (i = 0; i < trans_count ; i++) { if (NEXT_TABLE(dfa)[i] >= state_count) goto out; if (CHECK_TABLE(dfa)[i] >= state_count) goto out; } /* verify accept permissions */ for (i = 0; i < state_count; i++) { int mode = ACCEPT_TABLE(dfa)[i]; if (mode & ~AA_VALID_PERM_MASK) { goto out; } } error = 0; out: return error; }
/** * aa_dfa_next - step one character to the next state in the dfa * @dfa: the dfa to tranverse (NOT NULL) * @state: the state to start in * @c: the input character to transition on * * aa_dfa_match will step through the dfa by one input character @c * * Returns: state reach after input @c */ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, const char c) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); match_char(state, def, base, next, check, equiv[(u8) c]); } else match_char(state, def, base, next, check, (u8) c); return state; }
/** * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed * @dfa: the dfa to match @str against (NOT NULL) * @start: the state of the dfa to start matching in * @str: the string of bytes to match against the dfa (NOT NULL) * @n: length of the string of bytes to match * @retpos: first character in str after match OR str + n * * aa_dfa_match_len will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. * * This function will happily match again the 0 byte and only finishes * when @n input is consumed. * * Returns: final state reached after input is consumed */ unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, const char *str, int n, const char **retpos) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); u32 *accept = ACCEPT_TABLE(dfa); unsigned int state = start, pos; *retpos = NULL; if (state == 0) return 0; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ for (; n; n--) { pos = base_idx(base[state]) + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else state = def[state]; if (accept[state]) break; } } else { /* default is direct to next state */ for (; n; n--) { pos = base_idx(base[state]) + (u8) *str++; if (check[pos] == state) state = next[pos]; else state = def[state]; if (accept[state]) break; } } *retpos = str; return state; }
unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, const char *str, int len) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int state = start, pos; if (state == 0) return 0; if (dfa->tables[YYTD_ID_EC]) { u8 *equiv = EQUIV_TABLE(dfa); for (; len; len--) { pos = base[state] + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else state = def[state]; } } else { for (; len; len--) { pos = base[state] + (u8) *str++; if (check[pos] == state) state = next[pos]; else state = def[state]; } } return state; }
/** * aa_dfa_match_len - traverse @dfa to find state @str stops at * @dfa: the dfa to match @str against (NOT NULL) * @start: the state of the dfa to start matching in * @str: the string of bytes to match against the dfa (NOT NULL) * @len: length of the string of bytes to match * * aa_dfa_match_len will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. * * This function will happily match again the 0 byte and only finishes * when @len input is consumed. * * Returns: final state reached after input is consumed */ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, const char *str, int len) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int state = start, pos; if (state == 0) return 0; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ for (; len; len--) { pos = base[state] + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else state = def[state]; } } else { /* default is direct to next state */ for (; len; len--) { pos = base[state] + (u8) *str++; if (check[pos] == state) state = next[pos]; else state = def[state]; } } return state; }
static unsigned int leftmatch_fb(struct aa_dfa *dfa, unsigned int start, const char *str, struct match_workbuf *wb, unsigned int *count) { u16 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); u16 *next = NEXT_TABLE(dfa); u16 *check = CHECK_TABLE(dfa); unsigned int state = start, pos; AA_BUG(!dfa); AA_BUG(!str); AA_BUG(!wb); AA_BUG(!count); *count = 0; if (state == 0) return 0; /* current state is <state>, matching character *str */ if (dfa->tables[YYTD_ID_EC]) { /* Equivalence class table defined */ u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ while (*str) { unsigned int adjust; wb->history[wb->pos] = state; pos = base_idx(base[state]) + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else state = def[state]; if (is_loop(wb, state, &adjust)) { state = aa_dfa_match(dfa, state, str); *count -= adjust; goto out; } inc_wb_pos(wb); (*count)++; } } else { /* default is direct to next state */ while (*str) { unsigned int adjust; wb->history[wb->pos] = state; pos = base_idx(base[state]) + (u8) *str++; if (check[pos] == state) state = next[pos]; else state = def[state]; if (is_loop(wb, state, &adjust)) { state = aa_dfa_match(dfa, state, str); *count -= adjust; goto out; } inc_wb_pos(wb); (*count)++; } } out: if (!state) *count = 0; return state; }
static int verify_dfa(struct aa_dfa *dfa, int flags) { size_t i, state_count, trans_count; int error = -EPROTO; if (!(dfa->tables[YYTD_ID_DEF] && dfa->tables[YYTD_ID_BASE] && dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) goto out; state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; if (ACCEPT1_FLAGS(flags)) { if (!dfa->tables[YYTD_ID_ACCEPT]) goto out; if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) goto out; } if (ACCEPT2_FLAGS(flags)) { if (!dfa->tables[YYTD_ID_ACCEPT2]) goto out; if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) goto out; } if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) goto out; trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) goto out; if (dfa->tables[YYTD_ID_EC] && dfa->tables[YYTD_ID_EC]->td_lolen != 256) goto out; if (flags & DFA_FLAG_VERIFY_STATES) { for (i = 0; i < state_count; i++) { if (DEFAULT_TABLE(dfa)[i] >= state_count) goto out; if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { printk(KERN_ERR "AppArmor DFA next/check upper " "bounds error\n"); goto out; } } for (i = 0; i < trans_count; i++) { if (NEXT_TABLE(dfa)[i] >= state_count) goto out; if (CHECK_TABLE(dfa)[i] >= state_count) goto out; } } error = 0; out: return error; }