1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e06f75a6SJohn Johansen /* 3e06f75a6SJohn Johansen * AppArmor security module 4e06f75a6SJohn Johansen * 5e06f75a6SJohn Johansen * This file contains AppArmor dfa based regular expression matching engine 6e06f75a6SJohn Johansen * 7e06f75a6SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 88e4ff109SJohn Johansen * Copyright 2009-2012 Canonical Ltd. 9e06f75a6SJohn Johansen */ 10e06f75a6SJohn Johansen 11e06f75a6SJohn Johansen #include <linux/errno.h> 12e06f75a6SJohn Johansen #include <linux/kernel.h> 13e06f75a6SJohn Johansen #include <linux/mm.h> 14e06f75a6SJohn Johansen #include <linux/slab.h> 15e06f75a6SJohn Johansen #include <linux/vmalloc.h> 16e06f75a6SJohn Johansen #include <linux/err.h> 17e06f75a6SJohn Johansen #include <linux/kref.h> 18e06f75a6SJohn Johansen 1912557dcbSJohn Johansen #include "include/lib.h" 20e06f75a6SJohn Johansen #include "include/match.h" 21e06f75a6SJohn Johansen 22ed686308SJohn Johansen #define base_idx(X) ((X) & 0xffffff) 23ed686308SJohn Johansen 2411c236b8SJohn Johansen static char nulldfa_src[] = { 2511c236b8SJohn Johansen #include "nulldfa.in" 2611c236b8SJohn Johansen }; 2711c236b8SJohn Johansen struct aa_dfa *nulldfa; 2811c236b8SJohn Johansen 296e0654d2SJohn Johansen static char stacksplitdfa_src[] = { 306e0654d2SJohn Johansen #include "stacksplitdfa.in" 316e0654d2SJohn Johansen }; 326e0654d2SJohn Johansen struct aa_dfa *stacksplitdfa; 336e0654d2SJohn Johansen 34*f6c64dc3SXiu Jianfeng int __init aa_setup_dfa_engine(void) 3511c236b8SJohn Johansen { 3611c236b8SJohn Johansen int error; 3711c236b8SJohn Johansen 3811c236b8SJohn Johansen nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 3911c236b8SJohn Johansen TO_ACCEPT1_FLAG(YYTD_DATA32) | 4011c236b8SJohn Johansen TO_ACCEPT2_FLAG(YYTD_DATA32)); 416e0654d2SJohn Johansen if (IS_ERR(nulldfa)) { 4211c236b8SJohn Johansen error = PTR_ERR(nulldfa); 4311c236b8SJohn Johansen nulldfa = NULL; 4411c236b8SJohn Johansen return error; 4511c236b8SJohn Johansen } 4611c236b8SJohn Johansen 476e0654d2SJohn Johansen stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, 486e0654d2SJohn Johansen sizeof(stacksplitdfa_src), 496e0654d2SJohn Johansen TO_ACCEPT1_FLAG(YYTD_DATA32) | 506e0654d2SJohn Johansen TO_ACCEPT2_FLAG(YYTD_DATA32)); 516e0654d2SJohn Johansen if (IS_ERR(stacksplitdfa)) { 526e0654d2SJohn Johansen aa_put_dfa(nulldfa); 536e0654d2SJohn Johansen nulldfa = NULL; 546e0654d2SJohn Johansen error = PTR_ERR(stacksplitdfa); 556e0654d2SJohn Johansen stacksplitdfa = NULL; 566e0654d2SJohn Johansen return error; 576e0654d2SJohn Johansen } 586e0654d2SJohn Johansen 596e0654d2SJohn Johansen return 0; 606e0654d2SJohn Johansen } 616e0654d2SJohn Johansen 62*f6c64dc3SXiu Jianfeng void __init aa_teardown_dfa_engine(void) 6311c236b8SJohn Johansen { 646e0654d2SJohn Johansen aa_put_dfa(stacksplitdfa); 6511c236b8SJohn Johansen aa_put_dfa(nulldfa); 6611c236b8SJohn Johansen } 6711c236b8SJohn Johansen 68e06f75a6SJohn Johansen /** 69e06f75a6SJohn Johansen * unpack_table - unpack a dfa table (one of accept, default, base, next check) 70e06f75a6SJohn Johansen * @blob: data to unpack (NOT NULL) 71e06f75a6SJohn Johansen * @bsize: size of blob 72e06f75a6SJohn Johansen * 73e06f75a6SJohn Johansen * Returns: pointer to table else NULL on failure 74e06f75a6SJohn Johansen * 750ca554b9SJohn Johansen * NOTE: must be freed by kvfree (not kfree) 76e06f75a6SJohn Johansen */ 77e06f75a6SJohn Johansen static struct table_header *unpack_table(char *blob, size_t bsize) 78e06f75a6SJohn Johansen { 79e06f75a6SJohn Johansen struct table_header *table = NULL; 80e06f75a6SJohn Johansen struct table_header th; 81e06f75a6SJohn Johansen size_t tsize; 82e06f75a6SJohn Johansen 83e06f75a6SJohn Johansen if (bsize < sizeof(struct table_header)) 84e06f75a6SJohn Johansen goto out; 85e06f75a6SJohn Johansen 86e06f75a6SJohn Johansen /* loaded td_id's start at 1, subtract 1 now to avoid doing 87e06f75a6SJohn Johansen * it every time we use td_id as an index 88e06f75a6SJohn Johansen */ 89e6e8bf41SJohn Johansen th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1; 9015756178SJohn Johansen if (th.td_id > YYTD_ID_MAX) 9115756178SJohn Johansen goto out; 92e6e8bf41SJohn Johansen th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2)); 93e6e8bf41SJohn Johansen th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8)); 94e06f75a6SJohn Johansen blob += sizeof(struct table_header); 95e06f75a6SJohn Johansen 96e06f75a6SJohn Johansen if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 97e06f75a6SJohn Johansen th.td_flags == YYTD_DATA8)) 98e06f75a6SJohn Johansen goto out; 99e06f75a6SJohn Johansen 100c27c6bd2SJohn Johansen /* if we have a table it must have some entries */ 101c27c6bd2SJohn Johansen if (th.td_lolen == 0) 102c27c6bd2SJohn Johansen goto out; 103e06f75a6SJohn Johansen tsize = table_size(th.td_lolen, th.td_flags); 104e06f75a6SJohn Johansen if (bsize < tsize) 105e06f75a6SJohn Johansen goto out; 106e06f75a6SJohn Johansen 107a7c3e901SMichal Hocko table = kvzalloc(tsize, GFP_KERNEL); 108e06f75a6SJohn Johansen if (table) { 109f4ee2defSHeinrich Schuchardt table->td_id = th.td_id; 110f4ee2defSHeinrich Schuchardt table->td_flags = th.td_flags; 111f4ee2defSHeinrich Schuchardt table->td_lolen = th.td_lolen; 112e06f75a6SJohn Johansen if (th.td_flags == YYTD_DATA8) 113e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 114e6e8bf41SJohn Johansen u8, u8, byte_to_byte); 115e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA16) 116e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 117e6e8bf41SJohn Johansen u16, __be16, be16_to_cpu); 118e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA32) 119e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 120e6e8bf41SJohn Johansen u32, __be32, be32_to_cpu); 121e06f75a6SJohn Johansen else 122e06f75a6SJohn Johansen goto fail; 123e06f75a6SJohn Johansen /* if table was vmalloced make sure the page tables are synced 124e06f75a6SJohn Johansen * before it is used, as it goes live to all cpus. 125e06f75a6SJohn Johansen */ 126e06f75a6SJohn Johansen if (is_vmalloc_addr(table)) 127e06f75a6SJohn Johansen vm_unmap_aliases(); 1283197f5adSJohn Johansen } 1293197f5adSJohn Johansen 1303197f5adSJohn Johansen out: 131e06f75a6SJohn Johansen return table; 132e06f75a6SJohn Johansen fail: 133e06f75a6SJohn Johansen kvfree(table); 134e06f75a6SJohn Johansen return NULL; 135e06f75a6SJohn Johansen } 136e06f75a6SJohn Johansen 137e06f75a6SJohn Johansen /** 138d901d6a2SJohn Johansen * verify_table_headers - verify that the tables headers are as expected 139d901d6a2SJohn Johansen * @tables - array of dfa tables to check (NOT NULL) 140e06f75a6SJohn Johansen * @flags: flags controlling what type of accept table are acceptable 141e06f75a6SJohn Johansen * 142e06f75a6SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 143e06f75a6SJohn Johansen * NOTE: this does not valid accept table values 144e06f75a6SJohn Johansen * 145e06f75a6SJohn Johansen * Returns: %0 else error code on failure to verify 146e06f75a6SJohn Johansen */ 147d901d6a2SJohn Johansen static int verify_table_headers(struct table_header **tables, int flags) 148e06f75a6SJohn Johansen { 149d901d6a2SJohn Johansen size_t state_count, trans_count; 150e06f75a6SJohn Johansen int error = -EPROTO; 151e06f75a6SJohn Johansen 152e06f75a6SJohn Johansen /* check that required tables exist */ 153d901d6a2SJohn Johansen if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] && 154d901d6a2SJohn Johansen tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK])) 155e06f75a6SJohn Johansen goto out; 156e06f75a6SJohn Johansen 157e06f75a6SJohn Johansen /* accept.size == default.size == base.size */ 158d901d6a2SJohn Johansen state_count = tables[YYTD_ID_BASE]->td_lolen; 159e06f75a6SJohn Johansen if (ACCEPT1_FLAGS(flags)) { 160d901d6a2SJohn Johansen if (!tables[YYTD_ID_ACCEPT]) 161e06f75a6SJohn Johansen goto out; 162d901d6a2SJohn Johansen if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen) 163e06f75a6SJohn Johansen goto out; 164e06f75a6SJohn Johansen } 165e06f75a6SJohn Johansen if (ACCEPT2_FLAGS(flags)) { 166d901d6a2SJohn Johansen if (!tables[YYTD_ID_ACCEPT2]) 167e06f75a6SJohn Johansen goto out; 168d901d6a2SJohn Johansen if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen) 169e06f75a6SJohn Johansen goto out; 170e06f75a6SJohn Johansen } 171d901d6a2SJohn Johansen if (state_count != tables[YYTD_ID_DEF]->td_lolen) 172e06f75a6SJohn Johansen goto out; 173e06f75a6SJohn Johansen 174e06f75a6SJohn Johansen /* next.size == chk.size */ 175d901d6a2SJohn Johansen trans_count = tables[YYTD_ID_NXT]->td_lolen; 176d901d6a2SJohn Johansen if (trans_count != tables[YYTD_ID_CHK]->td_lolen) 177e06f75a6SJohn Johansen goto out; 178e06f75a6SJohn Johansen 179e06f75a6SJohn Johansen /* if equivalence classes then its table size must be 256 */ 180d901d6a2SJohn Johansen if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256) 181e06f75a6SJohn Johansen goto out; 182e06f75a6SJohn Johansen 183d901d6a2SJohn Johansen error = 0; 184d901d6a2SJohn Johansen out: 185d901d6a2SJohn Johansen return error; 186d901d6a2SJohn Johansen } 187d901d6a2SJohn Johansen 188d901d6a2SJohn Johansen /** 189d901d6a2SJohn Johansen * verify_dfa - verify that transitions and states in the tables are in bounds. 190d901d6a2SJohn Johansen * @dfa: dfa to test (NOT NULL) 191d901d6a2SJohn Johansen * 192d901d6a2SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 193d901d6a2SJohn Johansen * NOTE: this does not valid accept table values 194d901d6a2SJohn Johansen * 195d901d6a2SJohn Johansen * Returns: %0 else error code on failure to verify 196d901d6a2SJohn Johansen */ 197d901d6a2SJohn Johansen static int verify_dfa(struct aa_dfa *dfa) 198d901d6a2SJohn Johansen { 199d901d6a2SJohn Johansen size_t i, state_count, trans_count; 200d53c9f4dSDan Carpenter int error = -EPROTO; 201d901d6a2SJohn Johansen 202d901d6a2SJohn Johansen state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 203d901d6a2SJohn Johansen trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 204c27c6bd2SJohn Johansen if (state_count == 0) 205c27c6bd2SJohn Johansen goto out; 206e06f75a6SJohn Johansen for (i = 0; i < state_count; i++) { 207031dcc8fSJohn Johansen if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && 208031dcc8fSJohn Johansen (DEFAULT_TABLE(dfa)[i] >= state_count)) 209e06f75a6SJohn Johansen goto out; 210c6596969SJohn Johansen if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) { 211c6596969SJohn Johansen pr_err("AppArmor DFA state with invalid match flags"); 212c6596969SJohn Johansen goto out; 213c6596969SJohn Johansen } 214dae60293SJohn Johansen if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE)) { 215dae60293SJohn Johansen if (!(dfa->flags & YYTH_FLAG_DIFF_ENCODE)) { 216dae60293SJohn Johansen pr_err("AppArmor DFA diff encoded transition state without header flag"); 217dae60293SJohn Johansen goto out; 218dae60293SJohn Johansen } 219dae60293SJohn Johansen } 2200df34a64SJohn Johansen if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_OOB_TRANSITION)) { 2210df34a64SJohn Johansen if (base_idx(BASE_TABLE(dfa)[i]) < dfa->max_oob) { 2220df34a64SJohn Johansen pr_err("AppArmor DFA out of bad transition out of range"); 2230df34a64SJohn Johansen goto out; 2240df34a64SJohn Johansen } 2250df34a64SJohn Johansen if (!(dfa->flags & YYTH_FLAG_OOB_TRANS)) { 2260df34a64SJohn Johansen pr_err("AppArmor DFA out of bad transition state without header flag"); 2270df34a64SJohn Johansen goto out; 2280df34a64SJohn Johansen } 2290df34a64SJohn Johansen } 230ed686308SJohn Johansen if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { 231d901d6a2SJohn Johansen pr_err("AppArmor DFA next/check upper bounds error\n"); 232e06f75a6SJohn Johansen goto out; 233e06f75a6SJohn Johansen } 234e06f75a6SJohn Johansen } 235e06f75a6SJohn Johansen 236e06f75a6SJohn Johansen for (i = 0; i < trans_count; i++) { 237e06f75a6SJohn Johansen if (NEXT_TABLE(dfa)[i] >= state_count) 238e06f75a6SJohn Johansen goto out; 239e06f75a6SJohn Johansen if (CHECK_TABLE(dfa)[i] >= state_count) 240e06f75a6SJohn Johansen goto out; 241e06f75a6SJohn Johansen } 242e06f75a6SJohn Johansen 243031dcc8fSJohn Johansen /* Now that all the other tables are verified, verify diffencoding */ 244d901d6a2SJohn Johansen for (i = 0; i < state_count; i++) { 245031dcc8fSJohn Johansen size_t j, k; 246031dcc8fSJohn Johansen 247031dcc8fSJohn Johansen for (j = i; 248031dcc8fSJohn Johansen (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && 249031dcc8fSJohn Johansen !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); 250031dcc8fSJohn Johansen j = k) { 251031dcc8fSJohn Johansen k = DEFAULT_TABLE(dfa)[j]; 252031dcc8fSJohn Johansen if (j == k) 253031dcc8fSJohn Johansen goto out; 254031dcc8fSJohn Johansen if (k < j) 255031dcc8fSJohn Johansen break; /* already verified */ 256031dcc8fSJohn Johansen BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; 257031dcc8fSJohn Johansen } 258031dcc8fSJohn Johansen } 259e06f75a6SJohn Johansen error = 0; 260d901d6a2SJohn Johansen 261e06f75a6SJohn Johansen out: 262e06f75a6SJohn Johansen return error; 263e06f75a6SJohn Johansen } 264e06f75a6SJohn Johansen 265e06f75a6SJohn Johansen /** 266e06f75a6SJohn Johansen * dfa_free - free a dfa allocated by aa_dfa_unpack 267e06f75a6SJohn Johansen * @dfa: the dfa to free (MAYBE NULL) 268e06f75a6SJohn Johansen * 269e06f75a6SJohn Johansen * Requires: reference count to dfa == 0 270e06f75a6SJohn Johansen */ 271e06f75a6SJohn Johansen static void dfa_free(struct aa_dfa *dfa) 272e06f75a6SJohn Johansen { 273e06f75a6SJohn Johansen if (dfa) { 274e06f75a6SJohn Johansen int i; 275e06f75a6SJohn Johansen 276e06f75a6SJohn Johansen for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 277e06f75a6SJohn Johansen kvfree(dfa->tables[i]); 278e06f75a6SJohn Johansen dfa->tables[i] = NULL; 279e06f75a6SJohn Johansen } 280e06f75a6SJohn Johansen kfree(dfa); 281e06f75a6SJohn Johansen } 282e06f75a6SJohn Johansen } 283e06f75a6SJohn Johansen 284e06f75a6SJohn Johansen /** 285e06f75a6SJohn Johansen * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 286e06f75a6SJohn Johansen * @kr: kref callback for freeing of a dfa (NOT NULL) 287e06f75a6SJohn Johansen */ 288e06f75a6SJohn Johansen void aa_dfa_free_kref(struct kref *kref) 289e06f75a6SJohn Johansen { 290e06f75a6SJohn Johansen struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 291e06f75a6SJohn Johansen dfa_free(dfa); 292e06f75a6SJohn Johansen } 293e06f75a6SJohn Johansen 294e06f75a6SJohn Johansen /** 295e06f75a6SJohn Johansen * aa_dfa_unpack - unpack the binary tables of a serialized dfa 296e06f75a6SJohn Johansen * @blob: aligned serialized stream of data to unpack (NOT NULL) 297e06f75a6SJohn Johansen * @size: size of data to unpack 298e06f75a6SJohn Johansen * @flags: flags controlling what type of accept tables are acceptable 299e06f75a6SJohn Johansen * 300e06f75a6SJohn Johansen * Unpack a dfa that has been serialized. To find information on the dfa 30126fccd9eSKees Cook * format look in Documentation/admin-guide/LSM/apparmor.rst 30225985edcSLucas De Marchi * Assumes the dfa @blob stream has been aligned on a 8 byte boundary 303e06f75a6SJohn Johansen * 304e06f75a6SJohn Johansen * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 305e06f75a6SJohn Johansen */ 306e06f75a6SJohn Johansen struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 307e06f75a6SJohn Johansen { 308e06f75a6SJohn Johansen int hsize; 309e06f75a6SJohn Johansen int error = -ENOMEM; 310e06f75a6SJohn Johansen char *data = blob; 311e06f75a6SJohn Johansen struct table_header *table = NULL; 312e06f75a6SJohn Johansen struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 313e06f75a6SJohn Johansen if (!dfa) 314e06f75a6SJohn Johansen goto fail; 315e06f75a6SJohn Johansen 316e06f75a6SJohn Johansen kref_init(&dfa->count); 317e06f75a6SJohn Johansen 318e06f75a6SJohn Johansen error = -EPROTO; 319e06f75a6SJohn Johansen 320e06f75a6SJohn Johansen /* get dfa table set header */ 321e06f75a6SJohn Johansen if (size < sizeof(struct table_set_header)) 322e06f75a6SJohn Johansen goto fail; 323e06f75a6SJohn Johansen 324e6e8bf41SJohn Johansen if (ntohl(*(__be32 *) data) != YYTH_MAGIC) 325e06f75a6SJohn Johansen goto fail; 326e06f75a6SJohn Johansen 327e6e8bf41SJohn Johansen hsize = ntohl(*(__be32 *) (data + 4)); 328e06f75a6SJohn Johansen if (size < hsize) 329e06f75a6SJohn Johansen goto fail; 330e06f75a6SJohn Johansen 331e6e8bf41SJohn Johansen dfa->flags = ntohs(*(__be16 *) (data + 12)); 3320df34a64SJohn Johansen if (dfa->flags & ~(YYTH_FLAGS)) 333031dcc8fSJohn Johansen goto fail; 334031dcc8fSJohn Johansen 3350df34a64SJohn Johansen /* 3360df34a64SJohn Johansen * TODO: needed for dfa to support more than 1 oob 3370df34a64SJohn Johansen * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) { 3380df34a64SJohn Johansen * if (hsize < 16 + 4) 3390df34a64SJohn Johansen * goto fail; 3400df34a64SJohn Johansen * dfa->max_oob = ntol(*(__be32 *) (data + 16)); 3410df34a64SJohn Johansen * if (dfa->max <= MAX_OOB_SUPPORTED) { 3420df34a64SJohn Johansen * pr_err("AppArmor DFA OOB greater than supported\n"); 3430df34a64SJohn Johansen * goto fail; 3440df34a64SJohn Johansen * } 3450df34a64SJohn Johansen * } 3460df34a64SJohn Johansen */ 3470df34a64SJohn Johansen dfa->max_oob = 1; 3480df34a64SJohn Johansen 349e06f75a6SJohn Johansen data += hsize; 350e06f75a6SJohn Johansen size -= hsize; 351e06f75a6SJohn Johansen 352e06f75a6SJohn Johansen while (size > 0) { 353e06f75a6SJohn Johansen table = unpack_table(data, size); 354e06f75a6SJohn Johansen if (!table) 355e06f75a6SJohn Johansen goto fail; 356e06f75a6SJohn Johansen 357e06f75a6SJohn Johansen switch (table->td_id) { 358e06f75a6SJohn Johansen case YYTD_ID_ACCEPT: 359e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 360e06f75a6SJohn Johansen goto fail; 361e06f75a6SJohn Johansen break; 362e06f75a6SJohn Johansen case YYTD_ID_ACCEPT2: 363e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 364e06f75a6SJohn Johansen goto fail; 365e06f75a6SJohn Johansen break; 366e06f75a6SJohn Johansen case YYTD_ID_BASE: 367e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA32) 368e06f75a6SJohn Johansen goto fail; 369e06f75a6SJohn Johansen break; 370e06f75a6SJohn Johansen case YYTD_ID_DEF: 371e06f75a6SJohn Johansen case YYTD_ID_NXT: 372e06f75a6SJohn Johansen case YYTD_ID_CHK: 373e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA16) 374e06f75a6SJohn Johansen goto fail; 375e06f75a6SJohn Johansen break; 376e06f75a6SJohn Johansen case YYTD_ID_EC: 377e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA8) 378e06f75a6SJohn Johansen goto fail; 379e06f75a6SJohn Johansen break; 380e06f75a6SJohn Johansen default: 381e06f75a6SJohn Johansen goto fail; 382e06f75a6SJohn Johansen } 383e06f75a6SJohn Johansen /* check for duplicate table entry */ 384e06f75a6SJohn Johansen if (dfa->tables[table->td_id]) 385e06f75a6SJohn Johansen goto fail; 386e06f75a6SJohn Johansen dfa->tables[table->td_id] = table; 387e06f75a6SJohn Johansen data += table_size(table->td_lolen, table->td_flags); 388e06f75a6SJohn Johansen size -= table_size(table->td_lolen, table->td_flags); 389e06f75a6SJohn Johansen table = NULL; 390e06f75a6SJohn Johansen } 391d901d6a2SJohn Johansen error = verify_table_headers(dfa->tables, flags); 392e06f75a6SJohn Johansen if (error) 393e06f75a6SJohn Johansen goto fail; 394e06f75a6SJohn Johansen 395d901d6a2SJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 396d901d6a2SJohn Johansen error = verify_dfa(dfa); 397d901d6a2SJohn Johansen if (error) 398d901d6a2SJohn Johansen goto fail; 399d901d6a2SJohn Johansen } 400d901d6a2SJohn Johansen 401e06f75a6SJohn Johansen return dfa; 402e06f75a6SJohn Johansen 403e06f75a6SJohn Johansen fail: 404e06f75a6SJohn Johansen kvfree(table); 405e06f75a6SJohn Johansen dfa_free(dfa); 406e06f75a6SJohn Johansen return ERR_PTR(error); 407e06f75a6SJohn Johansen } 408e06f75a6SJohn Johansen 409074c1cd7SJohn Johansen #define match_char(state, def, base, next, check, C) \ 410074c1cd7SJohn Johansen do { \ 411074c1cd7SJohn Johansen u32 b = (base)[(state)]; \ 412074c1cd7SJohn Johansen unsigned int pos = base_idx(b) + (C); \ 413074c1cd7SJohn Johansen if ((check)[pos] != (state)) { \ 414074c1cd7SJohn Johansen (state) = (def)[(state)]; \ 415031dcc8fSJohn Johansen if (b & MATCH_FLAG_DIFF_ENCODE) \ 416031dcc8fSJohn Johansen continue; \ 417074c1cd7SJohn Johansen break; \ 418074c1cd7SJohn Johansen } \ 419074c1cd7SJohn Johansen (state) = (next)[pos]; \ 420074c1cd7SJohn Johansen break; \ 421074c1cd7SJohn Johansen } while (1) 422074c1cd7SJohn Johansen 423e06f75a6SJohn Johansen /** 424e06f75a6SJohn Johansen * aa_dfa_match_len - traverse @dfa to find state @str stops at 425e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 426e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 427e06f75a6SJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 428e06f75a6SJohn Johansen * @len: length of the string of bytes to match 429e06f75a6SJohn Johansen * 430e06f75a6SJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 431e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 432e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 433e06f75a6SJohn Johansen * 434e06f75a6SJohn Johansen * This function will happily match again the 0 byte and only finishes 435e06f75a6SJohn Johansen * when @len input is consumed. 436e06f75a6SJohn Johansen * 437e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 438e06f75a6SJohn Johansen */ 43933fc95d8SJohn Johansen aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, 440e06f75a6SJohn Johansen const char *str, int len) 441e06f75a6SJohn Johansen { 442e06f75a6SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 443e06f75a6SJohn Johansen u32 *base = BASE_TABLE(dfa); 444e06f75a6SJohn Johansen u16 *next = NEXT_TABLE(dfa); 445e06f75a6SJohn Johansen u16 *check = CHECK_TABLE(dfa); 44633fc95d8SJohn Johansen aa_state_t state = start; 447e06f75a6SJohn Johansen 44833fc95d8SJohn Johansen if (state == DFA_NOMATCH) 44933fc95d8SJohn Johansen return DFA_NOMATCH; 450e06f75a6SJohn Johansen 451e06f75a6SJohn Johansen /* current state is <state>, matching character *str */ 452e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 453e06f75a6SJohn Johansen /* Equivalence class table defined */ 454e06f75a6SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 455074c1cd7SJohn Johansen for (; len; len--) 456074c1cd7SJohn Johansen match_char(state, def, base, next, check, 457074c1cd7SJohn Johansen equiv[(u8) *str++]); 458e06f75a6SJohn Johansen } else { 459e06f75a6SJohn Johansen /* default is direct to next state */ 460074c1cd7SJohn Johansen for (; len; len--) 461074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) *str++); 462e06f75a6SJohn Johansen } 463e06f75a6SJohn Johansen 464e06f75a6SJohn Johansen return state; 465e06f75a6SJohn Johansen } 466e06f75a6SJohn Johansen 467e06f75a6SJohn Johansen /** 4680fe1212dSJohn Johansen * aa_dfa_match - traverse @dfa to find state @str stops at 469e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 470e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 471e06f75a6SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 472e06f75a6SJohn Johansen * 4730fe1212dSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 474e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 475e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 476e06f75a6SJohn Johansen * 477e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 478e06f75a6SJohn Johansen */ 47933fc95d8SJohn Johansen aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) 480e06f75a6SJohn Johansen { 4810fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 4820fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 4830fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 4840fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 48533fc95d8SJohn Johansen aa_state_t state = start; 4860fe1212dSJohn Johansen 48733fc95d8SJohn Johansen if (state == DFA_NOMATCH) 48833fc95d8SJohn Johansen return DFA_NOMATCH; 4890fe1212dSJohn Johansen 4900fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 4910fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 4920fe1212dSJohn Johansen /* Equivalence class table defined */ 4930fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 4940fe1212dSJohn Johansen /* default is direct to next state */ 495074c1cd7SJohn Johansen while (*str) 496074c1cd7SJohn Johansen match_char(state, def, base, next, check, 497074c1cd7SJohn Johansen equiv[(u8) *str++]); 4980fe1212dSJohn Johansen } else { 4990fe1212dSJohn Johansen /* default is direct to next state */ 500074c1cd7SJohn Johansen while (*str) 501074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) *str++); 5020fe1212dSJohn Johansen } 5030fe1212dSJohn Johansen 5040fe1212dSJohn Johansen return state; 5050fe1212dSJohn Johansen } 5060fe1212dSJohn Johansen 5070fe1212dSJohn Johansen /** 5080fe1212dSJohn Johansen * aa_dfa_next - step one character to the next state in the dfa 5095d2371e1SZygmunt Krynicki * @dfa: the dfa to traverse (NOT NULL) 5100fe1212dSJohn Johansen * @state: the state to start in 5110fe1212dSJohn Johansen * @c: the input character to transition on 5120fe1212dSJohn Johansen * 5130fe1212dSJohn Johansen * aa_dfa_match will step through the dfa by one input character @c 5140fe1212dSJohn Johansen * 5150fe1212dSJohn Johansen * Returns: state reach after input @c 5160fe1212dSJohn Johansen */ 51733fc95d8SJohn Johansen aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c) 5180fe1212dSJohn Johansen { 5190fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 5200fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 5210fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 5220fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 5230fe1212dSJohn Johansen 5240fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 5250fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 5260fe1212dSJohn Johansen /* Equivalence class table defined */ 5270fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 528074c1cd7SJohn Johansen match_char(state, def, base, next, check, equiv[(u8) c]); 529074c1cd7SJohn Johansen } else 530074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) c); 5310fe1212dSJohn Johansen 5320fe1212dSJohn Johansen return state; 533e06f75a6SJohn Johansen } 534cf65fabcSJohn Johansen 53533fc95d8SJohn Johansen aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state) 5360df34a64SJohn Johansen { 5370df34a64SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 5380df34a64SJohn Johansen u32 *base = BASE_TABLE(dfa); 5390df34a64SJohn Johansen u16 *next = NEXT_TABLE(dfa); 5400df34a64SJohn Johansen u16 *check = CHECK_TABLE(dfa); 5410df34a64SJohn Johansen u32 b = (base)[(state)]; 5420df34a64SJohn Johansen 5430df34a64SJohn Johansen if (!(b & MATCH_FLAG_OOB_TRANSITION)) 5440df34a64SJohn Johansen return DFA_NOMATCH; 5450df34a64SJohn Johansen 5460df34a64SJohn Johansen /* No Equivalence class remapping for outofband transitions */ 5470df34a64SJohn Johansen match_char(state, def, base, next, check, -1); 5480df34a64SJohn Johansen 5490df34a64SJohn Johansen return state; 5500df34a64SJohn Johansen } 5510df34a64SJohn Johansen 552cf65fabcSJohn Johansen /** 553cf65fabcSJohn Johansen * aa_dfa_match_until - traverse @dfa until accept state or end of input 554cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 555cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 556cf65fabcSJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 557cf65fabcSJohn Johansen * @retpos: first character in str after match OR end of string 558cf65fabcSJohn Johansen * 559cf65fabcSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 560cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 561cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 562cf65fabcSJohn Johansen * 563cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 564cf65fabcSJohn Johansen */ 56533fc95d8SJohn Johansen aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, 566cf65fabcSJohn Johansen const char *str, const char **retpos) 567cf65fabcSJohn Johansen { 568cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 569cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 570cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 571cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 572cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 57333fc95d8SJohn Johansen aa_state_t state = start, pos; 574cf65fabcSJohn Johansen 57533fc95d8SJohn Johansen if (state == DFA_NOMATCH) 57633fc95d8SJohn Johansen return DFA_NOMATCH; 577cf65fabcSJohn Johansen 578cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 579cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 580cf65fabcSJohn Johansen /* Equivalence class table defined */ 581cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 582cf65fabcSJohn Johansen /* default is direct to next state */ 583cf65fabcSJohn Johansen while (*str) { 584cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 585cf65fabcSJohn Johansen if (check[pos] == state) 586cf65fabcSJohn Johansen state = next[pos]; 587cf65fabcSJohn Johansen else 588cf65fabcSJohn Johansen state = def[state]; 589cf65fabcSJohn Johansen if (accept[state]) 590cf65fabcSJohn Johansen break; 591cf65fabcSJohn Johansen } 592cf65fabcSJohn Johansen } else { 593cf65fabcSJohn Johansen /* default is direct to next state */ 594cf65fabcSJohn Johansen while (*str) { 595cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 596cf65fabcSJohn Johansen if (check[pos] == state) 597cf65fabcSJohn Johansen state = next[pos]; 598cf65fabcSJohn Johansen else 599cf65fabcSJohn Johansen state = def[state]; 600cf65fabcSJohn Johansen if (accept[state]) 601cf65fabcSJohn Johansen break; 602cf65fabcSJohn Johansen } 603cf65fabcSJohn Johansen } 604cf65fabcSJohn Johansen 605cf65fabcSJohn Johansen *retpos = str; 606cf65fabcSJohn Johansen return state; 607cf65fabcSJohn Johansen } 608cf65fabcSJohn Johansen 609cf65fabcSJohn Johansen /** 610cf65fabcSJohn Johansen * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed 611cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 612cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 613cf65fabcSJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 614cf65fabcSJohn Johansen * @n: length of the string of bytes to match 615cf65fabcSJohn Johansen * @retpos: first character in str after match OR str + n 616cf65fabcSJohn Johansen * 617cf65fabcSJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 618cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 619cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 620cf65fabcSJohn Johansen * 621cf65fabcSJohn Johansen * This function will happily match again the 0 byte and only finishes 622cf65fabcSJohn Johansen * when @n input is consumed. 623cf65fabcSJohn Johansen * 624cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 625cf65fabcSJohn Johansen */ 62633fc95d8SJohn Johansen aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start, 627cf65fabcSJohn Johansen const char *str, int n, const char **retpos) 628cf65fabcSJohn Johansen { 629cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 630cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 631cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 632cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 633cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 63433fc95d8SJohn Johansen aa_state_t state = start, pos; 635cf65fabcSJohn Johansen 636cf65fabcSJohn Johansen *retpos = NULL; 63733fc95d8SJohn Johansen if (state == DFA_NOMATCH) 63833fc95d8SJohn Johansen return DFA_NOMATCH; 639cf65fabcSJohn Johansen 640cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 641cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 642cf65fabcSJohn Johansen /* Equivalence class table defined */ 643cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 644cf65fabcSJohn Johansen /* default is direct to next state */ 645cf65fabcSJohn Johansen for (; n; n--) { 646cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 647cf65fabcSJohn Johansen if (check[pos] == state) 648cf65fabcSJohn Johansen state = next[pos]; 649cf65fabcSJohn Johansen else 650cf65fabcSJohn Johansen state = def[state]; 651cf65fabcSJohn Johansen if (accept[state]) 652cf65fabcSJohn Johansen break; 653cf65fabcSJohn Johansen } 654cf65fabcSJohn Johansen } else { 655cf65fabcSJohn Johansen /* default is direct to next state */ 656cf65fabcSJohn Johansen for (; n; n--) { 657cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 658cf65fabcSJohn Johansen if (check[pos] == state) 659cf65fabcSJohn Johansen state = next[pos]; 660cf65fabcSJohn Johansen else 661cf65fabcSJohn Johansen state = def[state]; 662cf65fabcSJohn Johansen if (accept[state]) 663cf65fabcSJohn Johansen break; 664cf65fabcSJohn Johansen } 665cf65fabcSJohn Johansen } 666cf65fabcSJohn Johansen 667cf65fabcSJohn Johansen *retpos = str; 668cf65fabcSJohn Johansen return state; 669cf65fabcSJohn Johansen } 67021f60661SJohn Johansen 67121f60661SJohn Johansen #define inc_wb_pos(wb) \ 67221f60661SJohn Johansen do { \ 673136db994SJohn Johansen wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \ 674136db994SJohn Johansen wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \ 67521f60661SJohn Johansen } while (0) 67621f60661SJohn Johansen 67721f60661SJohn Johansen /* For DFAs that don't support extended tagging of states */ 67833fc95d8SJohn Johansen static bool is_loop(struct match_workbuf *wb, aa_state_t state, 67921f60661SJohn Johansen unsigned int *adjust) 68021f60661SJohn Johansen { 68133fc95d8SJohn Johansen aa_state_t pos = wb->pos; 68233fc95d8SJohn Johansen aa_state_t i; 68321f60661SJohn Johansen 68421f60661SJohn Johansen if (wb->history[pos] < state) 68521f60661SJohn Johansen return false; 68621f60661SJohn Johansen 68721f60661SJohn Johansen for (i = 0; i <= wb->len; i++) { 68821f60661SJohn Johansen if (wb->history[pos] == state) { 68921f60661SJohn Johansen *adjust = i; 69021f60661SJohn Johansen return true; 69121f60661SJohn Johansen } 69221f60661SJohn Johansen if (pos == 0) 693136db994SJohn Johansen pos = WB_HISTORY_SIZE; 69421f60661SJohn Johansen pos--; 69521f60661SJohn Johansen } 69621f60661SJohn Johansen 69721f60661SJohn Johansen *adjust = i; 69821f60661SJohn Johansen return true; 69921f60661SJohn Johansen } 70021f60661SJohn Johansen 70133fc95d8SJohn Johansen static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start, 70221f60661SJohn Johansen const char *str, struct match_workbuf *wb, 70321f60661SJohn Johansen unsigned int *count) 70421f60661SJohn Johansen { 70521f60661SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 70621f60661SJohn Johansen u32 *base = BASE_TABLE(dfa); 70721f60661SJohn Johansen u16 *next = NEXT_TABLE(dfa); 70821f60661SJohn Johansen u16 *check = CHECK_TABLE(dfa); 70933fc95d8SJohn Johansen aa_state_t state = start, pos; 71021f60661SJohn Johansen 71121f60661SJohn Johansen AA_BUG(!dfa); 71221f60661SJohn Johansen AA_BUG(!str); 71321f60661SJohn Johansen AA_BUG(!wb); 71421f60661SJohn Johansen AA_BUG(!count); 71521f60661SJohn Johansen 71621f60661SJohn Johansen *count = 0; 71733fc95d8SJohn Johansen if (state == DFA_NOMATCH) 71833fc95d8SJohn Johansen return DFA_NOMATCH; 71921f60661SJohn Johansen 72021f60661SJohn Johansen /* current state is <state>, matching character *str */ 72121f60661SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 72221f60661SJohn Johansen /* Equivalence class table defined */ 72321f60661SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 72421f60661SJohn Johansen /* default is direct to next state */ 72521f60661SJohn Johansen while (*str) { 72621f60661SJohn Johansen unsigned int adjust; 72721f60661SJohn Johansen 72821f60661SJohn Johansen wb->history[wb->pos] = state; 72921f60661SJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 73021f60661SJohn Johansen if (check[pos] == state) 73121f60661SJohn Johansen state = next[pos]; 73221f60661SJohn Johansen else 73321f60661SJohn Johansen state = def[state]; 73421f60661SJohn Johansen if (is_loop(wb, state, &adjust)) { 73521f60661SJohn Johansen state = aa_dfa_match(dfa, state, str); 73621f60661SJohn Johansen *count -= adjust; 73721f60661SJohn Johansen goto out; 73821f60661SJohn Johansen } 73921f60661SJohn Johansen inc_wb_pos(wb); 74021f60661SJohn Johansen (*count)++; 74121f60661SJohn Johansen } 74221f60661SJohn Johansen } else { 74321f60661SJohn Johansen /* default is direct to next state */ 74421f60661SJohn Johansen while (*str) { 74521f60661SJohn Johansen unsigned int adjust; 74621f60661SJohn Johansen 74721f60661SJohn Johansen wb->history[wb->pos] = state; 74821f60661SJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 74921f60661SJohn Johansen if (check[pos] == state) 75021f60661SJohn Johansen state = next[pos]; 75121f60661SJohn Johansen else 75221f60661SJohn Johansen state = def[state]; 75321f60661SJohn Johansen if (is_loop(wb, state, &adjust)) { 75421f60661SJohn Johansen state = aa_dfa_match(dfa, state, str); 75521f60661SJohn Johansen *count -= adjust; 75621f60661SJohn Johansen goto out; 75721f60661SJohn Johansen } 75821f60661SJohn Johansen inc_wb_pos(wb); 75921f60661SJohn Johansen (*count)++; 76021f60661SJohn Johansen } 76121f60661SJohn Johansen } 76221f60661SJohn Johansen 76321f60661SJohn Johansen out: 76421f60661SJohn Johansen if (!state) 76521f60661SJohn Johansen *count = 0; 76621f60661SJohn Johansen return state; 76721f60661SJohn Johansen } 76821f60661SJohn Johansen 76921f60661SJohn Johansen /** 77021f60661SJohn Johansen * aa_dfa_leftmatch - traverse @dfa to find state @str stops at 77121f60661SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 77221f60661SJohn Johansen * @start: the state of the dfa to start matching in 77321f60661SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 77421f60661SJohn Johansen * @count: current count of longest left. 77521f60661SJohn Johansen * 77621f60661SJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 77721f60661SJohn Johansen * finished matching in. The final state can be used to look up the accepting 77821f60661SJohn Johansen * label, or as the start state of a continuing match. 77921f60661SJohn Johansen * 78021f60661SJohn Johansen * Returns: final state reached after input is consumed 78121f60661SJohn Johansen */ 78233fc95d8SJohn Johansen aa_state_t aa_dfa_leftmatch(struct aa_dfa *dfa, aa_state_t start, 78321f60661SJohn Johansen const char *str, unsigned int *count) 78421f60661SJohn Johansen { 78521f60661SJohn Johansen DEFINE_MATCH_WB(wb); 78621f60661SJohn Johansen 78721f60661SJohn Johansen /* TODO: match for extended state dfas */ 78821f60661SJohn Johansen 78921f60661SJohn Johansen return leftmatch_fb(dfa, start, str, &wb, count); 79021f60661SJohn Johansen } 791