1e06f75a6SJohn Johansen /* 2e06f75a6SJohn Johansen * AppArmor security module 3e06f75a6SJohn Johansen * 4e06f75a6SJohn Johansen * This file contains AppArmor dfa based regular expression matching engine 5e06f75a6SJohn Johansen * 6e06f75a6SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 78e4ff109SJohn Johansen * Copyright 2009-2012 Canonical Ltd. 8e06f75a6SJohn Johansen * 9e06f75a6SJohn Johansen * This program is free software; you can redistribute it and/or 10e06f75a6SJohn Johansen * modify it under the terms of the GNU General Public License as 11e06f75a6SJohn Johansen * published by the Free Software Foundation, version 2 of the 12e06f75a6SJohn Johansen * License. 13e06f75a6SJohn Johansen */ 14e06f75a6SJohn Johansen 15e06f75a6SJohn Johansen #include <linux/errno.h> 16e06f75a6SJohn Johansen #include <linux/kernel.h> 17e06f75a6SJohn Johansen #include <linux/mm.h> 18e06f75a6SJohn Johansen #include <linux/slab.h> 19e06f75a6SJohn Johansen #include <linux/vmalloc.h> 20e06f75a6SJohn Johansen #include <linux/err.h> 21e06f75a6SJohn Johansen #include <linux/kref.h> 22e06f75a6SJohn Johansen 2312557dcbSJohn Johansen #include "include/lib.h" 24e06f75a6SJohn Johansen #include "include/match.h" 25e06f75a6SJohn Johansen 26ed686308SJohn Johansen #define base_idx(X) ((X) & 0xffffff) 27ed686308SJohn Johansen 2811c236b8SJohn Johansen static char nulldfa_src[] = { 2911c236b8SJohn Johansen #include "nulldfa.in" 3011c236b8SJohn Johansen }; 3111c236b8SJohn Johansen struct aa_dfa *nulldfa; 3211c236b8SJohn Johansen 336e0654d2SJohn Johansen static char stacksplitdfa_src[] = { 346e0654d2SJohn Johansen #include "stacksplitdfa.in" 356e0654d2SJohn Johansen }; 366e0654d2SJohn Johansen struct aa_dfa *stacksplitdfa; 376e0654d2SJohn Johansen 3811c236b8SJohn Johansen int aa_setup_dfa_engine(void) 3911c236b8SJohn Johansen { 4011c236b8SJohn Johansen int error; 4111c236b8SJohn Johansen 4211c236b8SJohn Johansen nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 4311c236b8SJohn Johansen TO_ACCEPT1_FLAG(YYTD_DATA32) | 4411c236b8SJohn Johansen TO_ACCEPT2_FLAG(YYTD_DATA32)); 456e0654d2SJohn Johansen if (IS_ERR(nulldfa)) { 4611c236b8SJohn Johansen error = PTR_ERR(nulldfa); 4711c236b8SJohn Johansen nulldfa = NULL; 4811c236b8SJohn Johansen return error; 4911c236b8SJohn Johansen } 5011c236b8SJohn Johansen 516e0654d2SJohn Johansen stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, 526e0654d2SJohn Johansen sizeof(stacksplitdfa_src), 536e0654d2SJohn Johansen TO_ACCEPT1_FLAG(YYTD_DATA32) | 546e0654d2SJohn Johansen TO_ACCEPT2_FLAG(YYTD_DATA32)); 556e0654d2SJohn Johansen if (IS_ERR(stacksplitdfa)) { 566e0654d2SJohn Johansen aa_put_dfa(nulldfa); 576e0654d2SJohn Johansen nulldfa = NULL; 586e0654d2SJohn Johansen error = PTR_ERR(stacksplitdfa); 596e0654d2SJohn Johansen stacksplitdfa = NULL; 606e0654d2SJohn Johansen return error; 616e0654d2SJohn Johansen } 626e0654d2SJohn Johansen 636e0654d2SJohn Johansen return 0; 646e0654d2SJohn Johansen } 656e0654d2SJohn Johansen 6611c236b8SJohn Johansen void aa_teardown_dfa_engine(void) 6711c236b8SJohn Johansen { 686e0654d2SJohn Johansen aa_put_dfa(stacksplitdfa); 6911c236b8SJohn Johansen aa_put_dfa(nulldfa); 7011c236b8SJohn Johansen } 7111c236b8SJohn Johansen 72e06f75a6SJohn Johansen /** 73e06f75a6SJohn Johansen * unpack_table - unpack a dfa table (one of accept, default, base, next check) 74e06f75a6SJohn Johansen * @blob: data to unpack (NOT NULL) 75e06f75a6SJohn Johansen * @bsize: size of blob 76e06f75a6SJohn Johansen * 77e06f75a6SJohn Johansen * Returns: pointer to table else NULL on failure 78e06f75a6SJohn Johansen * 790ca554b9SJohn Johansen * NOTE: must be freed by kvfree (not kfree) 80e06f75a6SJohn Johansen */ 81e06f75a6SJohn Johansen static struct table_header *unpack_table(char *blob, size_t bsize) 82e06f75a6SJohn Johansen { 83e06f75a6SJohn Johansen struct table_header *table = NULL; 84e06f75a6SJohn Johansen struct table_header th; 85e06f75a6SJohn Johansen size_t tsize; 86e06f75a6SJohn Johansen 87e06f75a6SJohn Johansen if (bsize < sizeof(struct table_header)) 88e06f75a6SJohn Johansen goto out; 89e06f75a6SJohn Johansen 90e06f75a6SJohn Johansen /* loaded td_id's start at 1, subtract 1 now to avoid doing 91e06f75a6SJohn Johansen * it every time we use td_id as an index 92e06f75a6SJohn Johansen */ 93e6e8bf41SJohn Johansen th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1; 9415756178SJohn Johansen if (th.td_id > YYTD_ID_MAX) 9515756178SJohn Johansen goto out; 96e6e8bf41SJohn Johansen th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2)); 97e6e8bf41SJohn Johansen th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8)); 98e06f75a6SJohn Johansen blob += sizeof(struct table_header); 99e06f75a6SJohn Johansen 100e06f75a6SJohn Johansen if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 101e06f75a6SJohn Johansen th.td_flags == YYTD_DATA8)) 102e06f75a6SJohn Johansen goto out; 103e06f75a6SJohn Johansen 104e06f75a6SJohn Johansen tsize = table_size(th.td_lolen, th.td_flags); 105e06f75a6SJohn Johansen if (bsize < tsize) 106e06f75a6SJohn Johansen goto out; 107e06f75a6SJohn Johansen 108a7c3e901SMichal Hocko table = kvzalloc(tsize, GFP_KERNEL); 109e06f75a6SJohn Johansen if (table) { 110f4ee2defSHeinrich Schuchardt table->td_id = th.td_id; 111f4ee2defSHeinrich Schuchardt table->td_flags = th.td_flags; 112f4ee2defSHeinrich Schuchardt table->td_lolen = th.td_lolen; 113e06f75a6SJohn Johansen if (th.td_flags == YYTD_DATA8) 114e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 115e6e8bf41SJohn Johansen u8, u8, byte_to_byte); 116e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA16) 117e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 118e6e8bf41SJohn Johansen u16, __be16, be16_to_cpu); 119e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA32) 120e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 121e6e8bf41SJohn Johansen u32, __be32, be32_to_cpu); 122e06f75a6SJohn Johansen else 123e06f75a6SJohn Johansen goto fail; 124e06f75a6SJohn Johansen /* if table was vmalloced make sure the page tables are synced 125e06f75a6SJohn Johansen * before it is used, as it goes live to all cpus. 126e06f75a6SJohn Johansen */ 127e06f75a6SJohn Johansen if (is_vmalloc_addr(table)) 128e06f75a6SJohn Johansen vm_unmap_aliases(); 1293197f5adSJohn Johansen } 1303197f5adSJohn Johansen 1313197f5adSJohn Johansen out: 132e06f75a6SJohn Johansen return table; 133e06f75a6SJohn Johansen fail: 134e06f75a6SJohn Johansen kvfree(table); 135e06f75a6SJohn Johansen return NULL; 136e06f75a6SJohn Johansen } 137e06f75a6SJohn Johansen 138e06f75a6SJohn Johansen /** 139e06f75a6SJohn Johansen * verify_dfa - verify that transitions and states in the tables are in bounds. 140e06f75a6SJohn Johansen * @dfa: dfa to test (NOT NULL) 141e06f75a6SJohn Johansen * @flags: flags controlling what type of accept table are acceptable 142e06f75a6SJohn Johansen * 143e06f75a6SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 144e06f75a6SJohn Johansen * NOTE: this does not valid accept table values 145e06f75a6SJohn Johansen * 146e06f75a6SJohn Johansen * Returns: %0 else error code on failure to verify 147e06f75a6SJohn Johansen */ 148e06f75a6SJohn Johansen static int verify_dfa(struct aa_dfa *dfa, int flags) 149e06f75a6SJohn Johansen { 150e06f75a6SJohn Johansen size_t i, state_count, trans_count; 151e06f75a6SJohn Johansen int error = -EPROTO; 152e06f75a6SJohn Johansen 153e06f75a6SJohn Johansen /* check that required tables exist */ 154e06f75a6SJohn Johansen if (!(dfa->tables[YYTD_ID_DEF] && 155e06f75a6SJohn Johansen dfa->tables[YYTD_ID_BASE] && 156e06f75a6SJohn Johansen dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) 157e06f75a6SJohn Johansen goto out; 158e06f75a6SJohn Johansen 159e06f75a6SJohn Johansen /* accept.size == default.size == base.size */ 160e06f75a6SJohn Johansen state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 161e06f75a6SJohn Johansen if (ACCEPT1_FLAGS(flags)) { 162e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT]) 163e06f75a6SJohn Johansen goto out; 164e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) 165e06f75a6SJohn Johansen goto out; 166e06f75a6SJohn Johansen } 167e06f75a6SJohn Johansen if (ACCEPT2_FLAGS(flags)) { 168e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT2]) 169e06f75a6SJohn Johansen goto out; 170e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) 171e06f75a6SJohn Johansen goto out; 172e06f75a6SJohn Johansen } 173e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) 174e06f75a6SJohn Johansen goto out; 175e06f75a6SJohn Johansen 176e06f75a6SJohn Johansen /* next.size == chk.size */ 177e06f75a6SJohn Johansen trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 178e06f75a6SJohn Johansen if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) 179e06f75a6SJohn Johansen goto out; 180e06f75a6SJohn Johansen 181e06f75a6SJohn Johansen /* if equivalence classes then its table size must be 256 */ 182e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC] && 183e06f75a6SJohn Johansen dfa->tables[YYTD_ID_EC]->td_lolen != 256) 184e06f75a6SJohn Johansen goto out; 185e06f75a6SJohn Johansen 186e06f75a6SJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 187e06f75a6SJohn Johansen for (i = 0; i < state_count; i++) { 188*031dcc8fSJohn Johansen if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && 189*031dcc8fSJohn Johansen (DEFAULT_TABLE(dfa)[i] >= state_count)) 190e06f75a6SJohn Johansen goto out; 191ed686308SJohn Johansen if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { 192e06f75a6SJohn Johansen printk(KERN_ERR "AppArmor DFA next/check upper " 193e06f75a6SJohn Johansen "bounds error\n"); 194e06f75a6SJohn Johansen goto out; 195e06f75a6SJohn Johansen } 196e06f75a6SJohn Johansen } 197e06f75a6SJohn Johansen 198e06f75a6SJohn Johansen for (i = 0; i < trans_count; i++) { 199e06f75a6SJohn Johansen if (NEXT_TABLE(dfa)[i] >= state_count) 200e06f75a6SJohn Johansen goto out; 201e06f75a6SJohn Johansen if (CHECK_TABLE(dfa)[i] >= state_count) 202e06f75a6SJohn Johansen goto out; 203e06f75a6SJohn Johansen } 204e06f75a6SJohn Johansen } 205e06f75a6SJohn Johansen 206*031dcc8fSJohn Johansen /* Now that all the other tables are verified, verify diffencoding */ 207*031dcc8fSJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 208*031dcc8fSJohn Johansen size_t j, k; 209*031dcc8fSJohn Johansen 210*031dcc8fSJohn Johansen for (i = 0; i < state_count; i++) { 211*031dcc8fSJohn Johansen for (j = i; 212*031dcc8fSJohn Johansen (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && 213*031dcc8fSJohn Johansen !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); 214*031dcc8fSJohn Johansen j = k) { 215*031dcc8fSJohn Johansen k = DEFAULT_TABLE(dfa)[j]; 216*031dcc8fSJohn Johansen if (j == k) 217*031dcc8fSJohn Johansen goto out; 218*031dcc8fSJohn Johansen if (k < j) 219*031dcc8fSJohn Johansen break; /* already verified */ 220*031dcc8fSJohn Johansen BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; 221*031dcc8fSJohn Johansen } 222*031dcc8fSJohn Johansen } 223*031dcc8fSJohn Johansen } 224e06f75a6SJohn Johansen error = 0; 225e06f75a6SJohn Johansen out: 226e06f75a6SJohn Johansen return error; 227e06f75a6SJohn Johansen } 228e06f75a6SJohn Johansen 229e06f75a6SJohn Johansen /** 230e06f75a6SJohn Johansen * dfa_free - free a dfa allocated by aa_dfa_unpack 231e06f75a6SJohn Johansen * @dfa: the dfa to free (MAYBE NULL) 232e06f75a6SJohn Johansen * 233e06f75a6SJohn Johansen * Requires: reference count to dfa == 0 234e06f75a6SJohn Johansen */ 235e06f75a6SJohn Johansen static void dfa_free(struct aa_dfa *dfa) 236e06f75a6SJohn Johansen { 237e06f75a6SJohn Johansen if (dfa) { 238e06f75a6SJohn Johansen int i; 239e06f75a6SJohn Johansen 240e06f75a6SJohn Johansen for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 241e06f75a6SJohn Johansen kvfree(dfa->tables[i]); 242e06f75a6SJohn Johansen dfa->tables[i] = NULL; 243e06f75a6SJohn Johansen } 244e06f75a6SJohn Johansen kfree(dfa); 245e06f75a6SJohn Johansen } 246e06f75a6SJohn Johansen } 247e06f75a6SJohn Johansen 248e06f75a6SJohn Johansen /** 249e06f75a6SJohn Johansen * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 250e06f75a6SJohn Johansen * @kr: kref callback for freeing of a dfa (NOT NULL) 251e06f75a6SJohn Johansen */ 252e06f75a6SJohn Johansen void aa_dfa_free_kref(struct kref *kref) 253e06f75a6SJohn Johansen { 254e06f75a6SJohn Johansen struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 255e06f75a6SJohn Johansen dfa_free(dfa); 256e06f75a6SJohn Johansen } 257e06f75a6SJohn Johansen 258e06f75a6SJohn Johansen /** 259e06f75a6SJohn Johansen * aa_dfa_unpack - unpack the binary tables of a serialized dfa 260e06f75a6SJohn Johansen * @blob: aligned serialized stream of data to unpack (NOT NULL) 261e06f75a6SJohn Johansen * @size: size of data to unpack 262e06f75a6SJohn Johansen * @flags: flags controlling what type of accept tables are acceptable 263e06f75a6SJohn Johansen * 264e06f75a6SJohn Johansen * Unpack a dfa that has been serialized. To find information on the dfa 26526fccd9eSKees Cook * format look in Documentation/admin-guide/LSM/apparmor.rst 26625985edcSLucas De Marchi * Assumes the dfa @blob stream has been aligned on a 8 byte boundary 267e06f75a6SJohn Johansen * 268e06f75a6SJohn Johansen * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 269e06f75a6SJohn Johansen */ 270e06f75a6SJohn Johansen struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 271e06f75a6SJohn Johansen { 272e06f75a6SJohn Johansen int hsize; 273e06f75a6SJohn Johansen int error = -ENOMEM; 274e06f75a6SJohn Johansen char *data = blob; 275e06f75a6SJohn Johansen struct table_header *table = NULL; 276e06f75a6SJohn Johansen struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 277e06f75a6SJohn Johansen if (!dfa) 278e06f75a6SJohn Johansen goto fail; 279e06f75a6SJohn Johansen 280e06f75a6SJohn Johansen kref_init(&dfa->count); 281e06f75a6SJohn Johansen 282e06f75a6SJohn Johansen error = -EPROTO; 283e06f75a6SJohn Johansen 284e06f75a6SJohn Johansen /* get dfa table set header */ 285e06f75a6SJohn Johansen if (size < sizeof(struct table_set_header)) 286e06f75a6SJohn Johansen goto fail; 287e06f75a6SJohn Johansen 288e6e8bf41SJohn Johansen if (ntohl(*(__be32 *) data) != YYTH_MAGIC) 289e06f75a6SJohn Johansen goto fail; 290e06f75a6SJohn Johansen 291e6e8bf41SJohn Johansen hsize = ntohl(*(__be32 *) (data + 4)); 292e06f75a6SJohn Johansen if (size < hsize) 293e06f75a6SJohn Johansen goto fail; 294e06f75a6SJohn Johansen 295e6e8bf41SJohn Johansen dfa->flags = ntohs(*(__be16 *) (data + 12)); 296*031dcc8fSJohn Johansen if (dfa->flags != 0 && dfa->flags != YYTH_FLAG_DIFF_ENCODE) 297*031dcc8fSJohn Johansen goto fail; 298*031dcc8fSJohn Johansen 299e06f75a6SJohn Johansen data += hsize; 300e06f75a6SJohn Johansen size -= hsize; 301e06f75a6SJohn Johansen 302e06f75a6SJohn Johansen while (size > 0) { 303e06f75a6SJohn Johansen table = unpack_table(data, size); 304e06f75a6SJohn Johansen if (!table) 305e06f75a6SJohn Johansen goto fail; 306e06f75a6SJohn Johansen 307e06f75a6SJohn Johansen switch (table->td_id) { 308e06f75a6SJohn Johansen case YYTD_ID_ACCEPT: 309e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 310e06f75a6SJohn Johansen goto fail; 311e06f75a6SJohn Johansen break; 312e06f75a6SJohn Johansen case YYTD_ID_ACCEPT2: 313e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 314e06f75a6SJohn Johansen goto fail; 315e06f75a6SJohn Johansen break; 316e06f75a6SJohn Johansen case YYTD_ID_BASE: 317e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA32) 318e06f75a6SJohn Johansen goto fail; 319e06f75a6SJohn Johansen break; 320e06f75a6SJohn Johansen case YYTD_ID_DEF: 321e06f75a6SJohn Johansen case YYTD_ID_NXT: 322e06f75a6SJohn Johansen case YYTD_ID_CHK: 323e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA16) 324e06f75a6SJohn Johansen goto fail; 325e06f75a6SJohn Johansen break; 326e06f75a6SJohn Johansen case YYTD_ID_EC: 327e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA8) 328e06f75a6SJohn Johansen goto fail; 329e06f75a6SJohn Johansen break; 330e06f75a6SJohn Johansen default: 331e06f75a6SJohn Johansen goto fail; 332e06f75a6SJohn Johansen } 333e06f75a6SJohn Johansen /* check for duplicate table entry */ 334e06f75a6SJohn Johansen if (dfa->tables[table->td_id]) 335e06f75a6SJohn Johansen goto fail; 336e06f75a6SJohn Johansen dfa->tables[table->td_id] = table; 337e06f75a6SJohn Johansen data += table_size(table->td_lolen, table->td_flags); 338e06f75a6SJohn Johansen size -= table_size(table->td_lolen, table->td_flags); 339e06f75a6SJohn Johansen table = NULL; 340e06f75a6SJohn Johansen } 341e06f75a6SJohn Johansen 342e06f75a6SJohn Johansen error = verify_dfa(dfa, flags); 343e06f75a6SJohn Johansen if (error) 344e06f75a6SJohn Johansen goto fail; 345e06f75a6SJohn Johansen 346e06f75a6SJohn Johansen return dfa; 347e06f75a6SJohn Johansen 348e06f75a6SJohn Johansen fail: 349e06f75a6SJohn Johansen kvfree(table); 350e06f75a6SJohn Johansen dfa_free(dfa); 351e06f75a6SJohn Johansen return ERR_PTR(error); 352e06f75a6SJohn Johansen } 353e06f75a6SJohn Johansen 354074c1cd7SJohn Johansen #define match_char(state, def, base, next, check, C) \ 355074c1cd7SJohn Johansen do { \ 356074c1cd7SJohn Johansen u32 b = (base)[(state)]; \ 357074c1cd7SJohn Johansen unsigned int pos = base_idx(b) + (C); \ 358074c1cd7SJohn Johansen if ((check)[pos] != (state)) { \ 359074c1cd7SJohn Johansen (state) = (def)[(state)]; \ 360*031dcc8fSJohn Johansen if (b & MATCH_FLAG_DIFF_ENCODE) \ 361*031dcc8fSJohn Johansen continue; \ 362074c1cd7SJohn Johansen break; \ 363074c1cd7SJohn Johansen } \ 364074c1cd7SJohn Johansen (state) = (next)[pos]; \ 365074c1cd7SJohn Johansen break; \ 366074c1cd7SJohn Johansen } while (1) 367074c1cd7SJohn Johansen 368e06f75a6SJohn Johansen /** 369e06f75a6SJohn Johansen * aa_dfa_match_len - traverse @dfa to find state @str stops at 370e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 371e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 372e06f75a6SJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 373e06f75a6SJohn Johansen * @len: length of the string of bytes to match 374e06f75a6SJohn Johansen * 375e06f75a6SJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 376e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 377e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 378e06f75a6SJohn Johansen * 379e06f75a6SJohn Johansen * This function will happily match again the 0 byte and only finishes 380e06f75a6SJohn Johansen * when @len input is consumed. 381e06f75a6SJohn Johansen * 382e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 383e06f75a6SJohn Johansen */ 384e06f75a6SJohn Johansen unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 385e06f75a6SJohn Johansen const char *str, int len) 386e06f75a6SJohn Johansen { 387e06f75a6SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 388e06f75a6SJohn Johansen u32 *base = BASE_TABLE(dfa); 389e06f75a6SJohn Johansen u16 *next = NEXT_TABLE(dfa); 390e06f75a6SJohn Johansen u16 *check = CHECK_TABLE(dfa); 391074c1cd7SJohn Johansen unsigned int state = start; 392e06f75a6SJohn Johansen 393e06f75a6SJohn Johansen if (state == 0) 394e06f75a6SJohn Johansen return 0; 395e06f75a6SJohn Johansen 396e06f75a6SJohn Johansen /* current state is <state>, matching character *str */ 397e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 398e06f75a6SJohn Johansen /* Equivalence class table defined */ 399e06f75a6SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 400074c1cd7SJohn Johansen for (; len; len--) 401074c1cd7SJohn Johansen match_char(state, def, base, next, check, 402074c1cd7SJohn Johansen equiv[(u8) *str++]); 403e06f75a6SJohn Johansen } else { 404e06f75a6SJohn Johansen /* default is direct to next state */ 405074c1cd7SJohn Johansen for (; len; len--) 406074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) *str++); 407e06f75a6SJohn Johansen } 408e06f75a6SJohn Johansen 409e06f75a6SJohn Johansen return state; 410e06f75a6SJohn Johansen } 411e06f75a6SJohn Johansen 412e06f75a6SJohn Johansen /** 4130fe1212dSJohn Johansen * aa_dfa_match - traverse @dfa to find state @str stops at 414e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 415e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 416e06f75a6SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 417e06f75a6SJohn Johansen * 4180fe1212dSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 419e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 420e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 421e06f75a6SJohn Johansen * 422e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 423e06f75a6SJohn Johansen */ 424e06f75a6SJohn Johansen unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 425e06f75a6SJohn Johansen const char *str) 426e06f75a6SJohn Johansen { 4270fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 4280fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 4290fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 4300fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 431074c1cd7SJohn Johansen unsigned int state = start; 4320fe1212dSJohn Johansen 4330fe1212dSJohn Johansen if (state == 0) 4340fe1212dSJohn Johansen return 0; 4350fe1212dSJohn Johansen 4360fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 4370fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 4380fe1212dSJohn Johansen /* Equivalence class table defined */ 4390fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 4400fe1212dSJohn Johansen /* default is direct to next state */ 441074c1cd7SJohn Johansen while (*str) 442074c1cd7SJohn Johansen match_char(state, def, base, next, check, 443074c1cd7SJohn Johansen equiv[(u8) *str++]); 4440fe1212dSJohn Johansen } else { 4450fe1212dSJohn Johansen /* default is direct to next state */ 446074c1cd7SJohn Johansen while (*str) 447074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) *str++); 4480fe1212dSJohn Johansen } 4490fe1212dSJohn Johansen 4500fe1212dSJohn Johansen return state; 4510fe1212dSJohn Johansen } 4520fe1212dSJohn Johansen 4530fe1212dSJohn Johansen /** 4540fe1212dSJohn Johansen * aa_dfa_next - step one character to the next state in the dfa 4550fe1212dSJohn Johansen * @dfa: the dfa to tranverse (NOT NULL) 4560fe1212dSJohn Johansen * @state: the state to start in 4570fe1212dSJohn Johansen * @c: the input character to transition on 4580fe1212dSJohn Johansen * 4590fe1212dSJohn Johansen * aa_dfa_match will step through the dfa by one input character @c 4600fe1212dSJohn Johansen * 4610fe1212dSJohn Johansen * Returns: state reach after input @c 4620fe1212dSJohn Johansen */ 4630fe1212dSJohn Johansen unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 4640fe1212dSJohn Johansen const char c) 4650fe1212dSJohn Johansen { 4660fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 4670fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 4680fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 4690fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 4700fe1212dSJohn Johansen 4710fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 4720fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 4730fe1212dSJohn Johansen /* Equivalence class table defined */ 4740fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 475074c1cd7SJohn Johansen match_char(state, def, base, next, check, equiv[(u8) c]); 476074c1cd7SJohn Johansen } else 477074c1cd7SJohn Johansen match_char(state, def, base, next, check, (u8) c); 4780fe1212dSJohn Johansen 4790fe1212dSJohn Johansen return state; 480e06f75a6SJohn Johansen } 481cf65fabcSJohn Johansen 482cf65fabcSJohn Johansen /** 483cf65fabcSJohn Johansen * aa_dfa_match_until - traverse @dfa until accept state or end of input 484cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 485cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 486cf65fabcSJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 487cf65fabcSJohn Johansen * @retpos: first character in str after match OR end of string 488cf65fabcSJohn Johansen * 489cf65fabcSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 490cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 491cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 492cf65fabcSJohn Johansen * 493cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 494cf65fabcSJohn Johansen */ 495cf65fabcSJohn Johansen unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, 496cf65fabcSJohn Johansen const char *str, const char **retpos) 497cf65fabcSJohn Johansen { 498cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 499cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 500cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 501cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 502cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 503cf65fabcSJohn Johansen unsigned int state = start, pos; 504cf65fabcSJohn Johansen 505cf65fabcSJohn Johansen if (state == 0) 506cf65fabcSJohn Johansen return 0; 507cf65fabcSJohn Johansen 508cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 509cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 510cf65fabcSJohn Johansen /* Equivalence class table defined */ 511cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 512cf65fabcSJohn Johansen /* default is direct to next state */ 513cf65fabcSJohn Johansen while (*str) { 514cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 515cf65fabcSJohn Johansen if (check[pos] == state) 516cf65fabcSJohn Johansen state = next[pos]; 517cf65fabcSJohn Johansen else 518cf65fabcSJohn Johansen state = def[state]; 519cf65fabcSJohn Johansen if (accept[state]) 520cf65fabcSJohn Johansen break; 521cf65fabcSJohn Johansen } 522cf65fabcSJohn Johansen } else { 523cf65fabcSJohn Johansen /* default is direct to next state */ 524cf65fabcSJohn Johansen while (*str) { 525cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 526cf65fabcSJohn Johansen if (check[pos] == state) 527cf65fabcSJohn Johansen state = next[pos]; 528cf65fabcSJohn Johansen else 529cf65fabcSJohn Johansen state = def[state]; 530cf65fabcSJohn Johansen if (accept[state]) 531cf65fabcSJohn Johansen break; 532cf65fabcSJohn Johansen } 533cf65fabcSJohn Johansen } 534cf65fabcSJohn Johansen 535cf65fabcSJohn Johansen *retpos = str; 536cf65fabcSJohn Johansen return state; 537cf65fabcSJohn Johansen } 538cf65fabcSJohn Johansen 539cf65fabcSJohn Johansen 540cf65fabcSJohn Johansen /** 541cf65fabcSJohn Johansen * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed 542cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 543cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 544cf65fabcSJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 545cf65fabcSJohn Johansen * @n: length of the string of bytes to match 546cf65fabcSJohn Johansen * @retpos: first character in str after match OR str + n 547cf65fabcSJohn Johansen * 548cf65fabcSJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 549cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 550cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 551cf65fabcSJohn Johansen * 552cf65fabcSJohn Johansen * This function will happily match again the 0 byte and only finishes 553cf65fabcSJohn Johansen * when @n input is consumed. 554cf65fabcSJohn Johansen * 555cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 556cf65fabcSJohn Johansen */ 557cf65fabcSJohn Johansen unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, 558cf65fabcSJohn Johansen const char *str, int n, const char **retpos) 559cf65fabcSJohn Johansen { 560cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 561cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 562cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 563cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 564cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 565cf65fabcSJohn Johansen unsigned int state = start, pos; 566cf65fabcSJohn Johansen 567cf65fabcSJohn Johansen *retpos = NULL; 568cf65fabcSJohn Johansen if (state == 0) 569cf65fabcSJohn Johansen return 0; 570cf65fabcSJohn Johansen 571cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 572cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 573cf65fabcSJohn Johansen /* Equivalence class table defined */ 574cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 575cf65fabcSJohn Johansen /* default is direct to next state */ 576cf65fabcSJohn Johansen for (; n; n--) { 577cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 578cf65fabcSJohn Johansen if (check[pos] == state) 579cf65fabcSJohn Johansen state = next[pos]; 580cf65fabcSJohn Johansen else 581cf65fabcSJohn Johansen state = def[state]; 582cf65fabcSJohn Johansen if (accept[state]) 583cf65fabcSJohn Johansen break; 584cf65fabcSJohn Johansen } 585cf65fabcSJohn Johansen } else { 586cf65fabcSJohn Johansen /* default is direct to next state */ 587cf65fabcSJohn Johansen for (; n; n--) { 588cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 589cf65fabcSJohn Johansen if (check[pos] == state) 590cf65fabcSJohn Johansen state = next[pos]; 591cf65fabcSJohn Johansen else 592cf65fabcSJohn Johansen state = def[state]; 593cf65fabcSJohn Johansen if (accept[state]) 594cf65fabcSJohn Johansen break; 595cf65fabcSJohn Johansen } 596cf65fabcSJohn Johansen } 597cf65fabcSJohn Johansen 598cf65fabcSJohn Johansen *retpos = str; 599cf65fabcSJohn Johansen return state; 600cf65fabcSJohn Johansen } 601