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 3311c236b8SJohn Johansen int aa_setup_dfa_engine(void) 3411c236b8SJohn Johansen { 3511c236b8SJohn Johansen int error; 3611c236b8SJohn Johansen 3711c236b8SJohn Johansen nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 3811c236b8SJohn Johansen TO_ACCEPT1_FLAG(YYTD_DATA32) | 3911c236b8SJohn Johansen TO_ACCEPT2_FLAG(YYTD_DATA32)); 4011c236b8SJohn Johansen if (!IS_ERR(nulldfa)) 4111c236b8SJohn Johansen return 0; 4211c236b8SJohn Johansen 4311c236b8SJohn Johansen error = PTR_ERR(nulldfa); 4411c236b8SJohn Johansen nulldfa = NULL; 4511c236b8SJohn Johansen 4611c236b8SJohn Johansen return error; 4711c236b8SJohn Johansen } 4811c236b8SJohn Johansen 4911c236b8SJohn Johansen void aa_teardown_dfa_engine(void) 5011c236b8SJohn Johansen { 5111c236b8SJohn Johansen aa_put_dfa(nulldfa); 5211c236b8SJohn Johansen nulldfa = NULL; 5311c236b8SJohn Johansen } 5411c236b8SJohn Johansen 55e06f75a6SJohn Johansen /** 56e06f75a6SJohn Johansen * unpack_table - unpack a dfa table (one of accept, default, base, next check) 57e06f75a6SJohn Johansen * @blob: data to unpack (NOT NULL) 58e06f75a6SJohn Johansen * @bsize: size of blob 59e06f75a6SJohn Johansen * 60e06f75a6SJohn Johansen * Returns: pointer to table else NULL on failure 61e06f75a6SJohn Johansen * 620ca554b9SJohn Johansen * NOTE: must be freed by kvfree (not kfree) 63e06f75a6SJohn Johansen */ 64e06f75a6SJohn Johansen static struct table_header *unpack_table(char *blob, size_t bsize) 65e06f75a6SJohn Johansen { 66e06f75a6SJohn Johansen struct table_header *table = NULL; 67e06f75a6SJohn Johansen struct table_header th; 68e06f75a6SJohn Johansen size_t tsize; 69e06f75a6SJohn Johansen 70e06f75a6SJohn Johansen if (bsize < sizeof(struct table_header)) 71e06f75a6SJohn Johansen goto out; 72e06f75a6SJohn Johansen 73e06f75a6SJohn Johansen /* loaded td_id's start at 1, subtract 1 now to avoid doing 74e06f75a6SJohn Johansen * it every time we use td_id as an index 75e06f75a6SJohn Johansen */ 76e6e8bf41SJohn Johansen th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1; 7715756178SJohn Johansen if (th.td_id > YYTD_ID_MAX) 7815756178SJohn Johansen goto out; 79e6e8bf41SJohn Johansen th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2)); 80e6e8bf41SJohn Johansen th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8)); 81e06f75a6SJohn Johansen blob += sizeof(struct table_header); 82e06f75a6SJohn Johansen 83e06f75a6SJohn Johansen if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 84e06f75a6SJohn Johansen th.td_flags == YYTD_DATA8)) 85e06f75a6SJohn Johansen goto out; 86e06f75a6SJohn Johansen 87e06f75a6SJohn Johansen tsize = table_size(th.td_lolen, th.td_flags); 88e06f75a6SJohn Johansen if (bsize < tsize) 89e06f75a6SJohn Johansen goto out; 90e06f75a6SJohn Johansen 91a7c3e901SMichal Hocko table = kvzalloc(tsize, GFP_KERNEL); 92e06f75a6SJohn Johansen if (table) { 93f4ee2defSHeinrich Schuchardt table->td_id = th.td_id; 94f4ee2defSHeinrich Schuchardt table->td_flags = th.td_flags; 95f4ee2defSHeinrich Schuchardt table->td_lolen = th.td_lolen; 96e06f75a6SJohn Johansen if (th.td_flags == YYTD_DATA8) 97e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 98e6e8bf41SJohn Johansen u8, u8, byte_to_byte); 99e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA16) 100e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 101e6e8bf41SJohn Johansen u16, __be16, be16_to_cpu); 102e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA32) 103e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 104e6e8bf41SJohn Johansen u32, __be32, be32_to_cpu); 105e06f75a6SJohn Johansen else 106e06f75a6SJohn Johansen goto fail; 107e06f75a6SJohn Johansen /* if table was vmalloced make sure the page tables are synced 108e06f75a6SJohn Johansen * before it is used, as it goes live to all cpus. 109e06f75a6SJohn Johansen */ 110e06f75a6SJohn Johansen if (is_vmalloc_addr(table)) 111e06f75a6SJohn Johansen vm_unmap_aliases(); 1123197f5adSJohn Johansen } 1133197f5adSJohn Johansen 1143197f5adSJohn Johansen out: 115e06f75a6SJohn Johansen return table; 116e06f75a6SJohn Johansen fail: 117e06f75a6SJohn Johansen kvfree(table); 118e06f75a6SJohn Johansen return NULL; 119e06f75a6SJohn Johansen } 120e06f75a6SJohn Johansen 121e06f75a6SJohn Johansen /** 122e06f75a6SJohn Johansen * verify_dfa - verify that transitions and states in the tables are in bounds. 123e06f75a6SJohn Johansen * @dfa: dfa to test (NOT NULL) 124e06f75a6SJohn Johansen * @flags: flags controlling what type of accept table are acceptable 125e06f75a6SJohn Johansen * 126e06f75a6SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 127e06f75a6SJohn Johansen * NOTE: this does not valid accept table values 128e06f75a6SJohn Johansen * 129e06f75a6SJohn Johansen * Returns: %0 else error code on failure to verify 130e06f75a6SJohn Johansen */ 131e06f75a6SJohn Johansen static int verify_dfa(struct aa_dfa *dfa, int flags) 132e06f75a6SJohn Johansen { 133e06f75a6SJohn Johansen size_t i, state_count, trans_count; 134e06f75a6SJohn Johansen int error = -EPROTO; 135e06f75a6SJohn Johansen 136e06f75a6SJohn Johansen /* check that required tables exist */ 137e06f75a6SJohn Johansen if (!(dfa->tables[YYTD_ID_DEF] && 138e06f75a6SJohn Johansen dfa->tables[YYTD_ID_BASE] && 139e06f75a6SJohn Johansen dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) 140e06f75a6SJohn Johansen goto out; 141e06f75a6SJohn Johansen 142e06f75a6SJohn Johansen /* accept.size == default.size == base.size */ 143e06f75a6SJohn Johansen state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 144e06f75a6SJohn Johansen if (ACCEPT1_FLAGS(flags)) { 145e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT]) 146e06f75a6SJohn Johansen goto out; 147e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) 148e06f75a6SJohn Johansen goto out; 149e06f75a6SJohn Johansen } 150e06f75a6SJohn Johansen if (ACCEPT2_FLAGS(flags)) { 151e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT2]) 152e06f75a6SJohn Johansen goto out; 153e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) 154e06f75a6SJohn Johansen goto out; 155e06f75a6SJohn Johansen } 156e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) 157e06f75a6SJohn Johansen goto out; 158e06f75a6SJohn Johansen 159e06f75a6SJohn Johansen /* next.size == chk.size */ 160e06f75a6SJohn Johansen trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 161e06f75a6SJohn Johansen if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) 162e06f75a6SJohn Johansen goto out; 163e06f75a6SJohn Johansen 164e06f75a6SJohn Johansen /* if equivalence classes then its table size must be 256 */ 165e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC] && 166e06f75a6SJohn Johansen dfa->tables[YYTD_ID_EC]->td_lolen != 256) 167e06f75a6SJohn Johansen goto out; 168e06f75a6SJohn Johansen 169e06f75a6SJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 170e06f75a6SJohn Johansen for (i = 0; i < state_count; i++) { 171e06f75a6SJohn Johansen if (DEFAULT_TABLE(dfa)[i] >= state_count) 172e06f75a6SJohn Johansen goto out; 173ed686308SJohn Johansen if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { 174e06f75a6SJohn Johansen printk(KERN_ERR "AppArmor DFA next/check upper " 175e06f75a6SJohn Johansen "bounds error\n"); 176e06f75a6SJohn Johansen goto out; 177e06f75a6SJohn Johansen } 178e06f75a6SJohn Johansen } 179e06f75a6SJohn Johansen 180e06f75a6SJohn Johansen for (i = 0; i < trans_count; i++) { 181e06f75a6SJohn Johansen if (NEXT_TABLE(dfa)[i] >= state_count) 182e06f75a6SJohn Johansen goto out; 183e06f75a6SJohn Johansen if (CHECK_TABLE(dfa)[i] >= state_count) 184e06f75a6SJohn Johansen goto out; 185e06f75a6SJohn Johansen } 186e06f75a6SJohn Johansen } 187e06f75a6SJohn Johansen 188e06f75a6SJohn Johansen error = 0; 189e06f75a6SJohn Johansen out: 190e06f75a6SJohn Johansen return error; 191e06f75a6SJohn Johansen } 192e06f75a6SJohn Johansen 193e06f75a6SJohn Johansen /** 194e06f75a6SJohn Johansen * dfa_free - free a dfa allocated by aa_dfa_unpack 195e06f75a6SJohn Johansen * @dfa: the dfa to free (MAYBE NULL) 196e06f75a6SJohn Johansen * 197e06f75a6SJohn Johansen * Requires: reference count to dfa == 0 198e06f75a6SJohn Johansen */ 199e06f75a6SJohn Johansen static void dfa_free(struct aa_dfa *dfa) 200e06f75a6SJohn Johansen { 201e06f75a6SJohn Johansen if (dfa) { 202e06f75a6SJohn Johansen int i; 203e06f75a6SJohn Johansen 204e06f75a6SJohn Johansen for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 205e06f75a6SJohn Johansen kvfree(dfa->tables[i]); 206e06f75a6SJohn Johansen dfa->tables[i] = NULL; 207e06f75a6SJohn Johansen } 208e06f75a6SJohn Johansen kfree(dfa); 209e06f75a6SJohn Johansen } 210e06f75a6SJohn Johansen } 211e06f75a6SJohn Johansen 212e06f75a6SJohn Johansen /** 213e06f75a6SJohn Johansen * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 214e06f75a6SJohn Johansen * @kr: kref callback for freeing of a dfa (NOT NULL) 215e06f75a6SJohn Johansen */ 216e06f75a6SJohn Johansen void aa_dfa_free_kref(struct kref *kref) 217e06f75a6SJohn Johansen { 218e06f75a6SJohn Johansen struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 219e06f75a6SJohn Johansen dfa_free(dfa); 220e06f75a6SJohn Johansen } 221e06f75a6SJohn Johansen 222e06f75a6SJohn Johansen /** 223e06f75a6SJohn Johansen * aa_dfa_unpack - unpack the binary tables of a serialized dfa 224e06f75a6SJohn Johansen * @blob: aligned serialized stream of data to unpack (NOT NULL) 225e06f75a6SJohn Johansen * @size: size of data to unpack 226e06f75a6SJohn Johansen * @flags: flags controlling what type of accept tables are acceptable 227e06f75a6SJohn Johansen * 228e06f75a6SJohn Johansen * Unpack a dfa that has been serialized. To find information on the dfa 22926fccd9eSKees Cook * format look in Documentation/admin-guide/LSM/apparmor.rst 23025985edcSLucas De Marchi * Assumes the dfa @blob stream has been aligned on a 8 byte boundary 231e06f75a6SJohn Johansen * 232e06f75a6SJohn Johansen * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 233e06f75a6SJohn Johansen */ 234e06f75a6SJohn Johansen struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 235e06f75a6SJohn Johansen { 236e06f75a6SJohn Johansen int hsize; 237e06f75a6SJohn Johansen int error = -ENOMEM; 238e06f75a6SJohn Johansen char *data = blob; 239e06f75a6SJohn Johansen struct table_header *table = NULL; 240e06f75a6SJohn Johansen struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 241e06f75a6SJohn Johansen if (!dfa) 242e06f75a6SJohn Johansen goto fail; 243e06f75a6SJohn Johansen 244e06f75a6SJohn Johansen kref_init(&dfa->count); 245e06f75a6SJohn Johansen 246e06f75a6SJohn Johansen error = -EPROTO; 247e06f75a6SJohn Johansen 248e06f75a6SJohn Johansen /* get dfa table set header */ 249e06f75a6SJohn Johansen if (size < sizeof(struct table_set_header)) 250e06f75a6SJohn Johansen goto fail; 251e06f75a6SJohn Johansen 252e6e8bf41SJohn Johansen if (ntohl(*(__be32 *) data) != YYTH_MAGIC) 253e06f75a6SJohn Johansen goto fail; 254e06f75a6SJohn Johansen 255e6e8bf41SJohn Johansen hsize = ntohl(*(__be32 *) (data + 4)); 256e06f75a6SJohn Johansen if (size < hsize) 257e06f75a6SJohn Johansen goto fail; 258e06f75a6SJohn Johansen 259e6e8bf41SJohn Johansen dfa->flags = ntohs(*(__be16 *) (data + 12)); 260e06f75a6SJohn Johansen data += hsize; 261e06f75a6SJohn Johansen size -= hsize; 262e06f75a6SJohn Johansen 263e06f75a6SJohn Johansen while (size > 0) { 264e06f75a6SJohn Johansen table = unpack_table(data, size); 265e06f75a6SJohn Johansen if (!table) 266e06f75a6SJohn Johansen goto fail; 267e06f75a6SJohn Johansen 268e06f75a6SJohn Johansen switch (table->td_id) { 269e06f75a6SJohn Johansen case YYTD_ID_ACCEPT: 270e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 271e06f75a6SJohn Johansen goto fail; 272e06f75a6SJohn Johansen break; 273e06f75a6SJohn Johansen case YYTD_ID_ACCEPT2: 274e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 275e06f75a6SJohn Johansen goto fail; 276e06f75a6SJohn Johansen break; 277e06f75a6SJohn Johansen case YYTD_ID_BASE: 278e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA32) 279e06f75a6SJohn Johansen goto fail; 280e06f75a6SJohn Johansen break; 281e06f75a6SJohn Johansen case YYTD_ID_DEF: 282e06f75a6SJohn Johansen case YYTD_ID_NXT: 283e06f75a6SJohn Johansen case YYTD_ID_CHK: 284e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA16) 285e06f75a6SJohn Johansen goto fail; 286e06f75a6SJohn Johansen break; 287e06f75a6SJohn Johansen case YYTD_ID_EC: 288e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA8) 289e06f75a6SJohn Johansen goto fail; 290e06f75a6SJohn Johansen break; 291e06f75a6SJohn Johansen default: 292e06f75a6SJohn Johansen goto fail; 293e06f75a6SJohn Johansen } 294e06f75a6SJohn Johansen /* check for duplicate table entry */ 295e06f75a6SJohn Johansen if (dfa->tables[table->td_id]) 296e06f75a6SJohn Johansen goto fail; 297e06f75a6SJohn Johansen dfa->tables[table->td_id] = table; 298e06f75a6SJohn Johansen data += table_size(table->td_lolen, table->td_flags); 299e06f75a6SJohn Johansen size -= table_size(table->td_lolen, table->td_flags); 300e06f75a6SJohn Johansen table = NULL; 301e06f75a6SJohn Johansen } 302e06f75a6SJohn Johansen 303e06f75a6SJohn Johansen error = verify_dfa(dfa, flags); 304e06f75a6SJohn Johansen if (error) 305e06f75a6SJohn Johansen goto fail; 306e06f75a6SJohn Johansen 307e06f75a6SJohn Johansen return dfa; 308e06f75a6SJohn Johansen 309e06f75a6SJohn Johansen fail: 310e06f75a6SJohn Johansen kvfree(table); 311e06f75a6SJohn Johansen dfa_free(dfa); 312e06f75a6SJohn Johansen return ERR_PTR(error); 313e06f75a6SJohn Johansen } 314e06f75a6SJohn Johansen 315e06f75a6SJohn Johansen /** 316e06f75a6SJohn Johansen * aa_dfa_match_len - traverse @dfa to find state @str stops at 317e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 318e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 319e06f75a6SJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 320e06f75a6SJohn Johansen * @len: length of the string of bytes to match 321e06f75a6SJohn Johansen * 322e06f75a6SJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 323e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 324e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 325e06f75a6SJohn Johansen * 326e06f75a6SJohn Johansen * This function will happily match again the 0 byte and only finishes 327e06f75a6SJohn Johansen * when @len input is consumed. 328e06f75a6SJohn Johansen * 329e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 330e06f75a6SJohn Johansen */ 331e06f75a6SJohn Johansen unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 332e06f75a6SJohn Johansen const char *str, int len) 333e06f75a6SJohn Johansen { 334e06f75a6SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 335e06f75a6SJohn Johansen u32 *base = BASE_TABLE(dfa); 336e06f75a6SJohn Johansen u16 *next = NEXT_TABLE(dfa); 337e06f75a6SJohn Johansen u16 *check = CHECK_TABLE(dfa); 338e06f75a6SJohn Johansen unsigned int state = start, pos; 339e06f75a6SJohn Johansen 340e06f75a6SJohn Johansen if (state == 0) 341e06f75a6SJohn Johansen return 0; 342e06f75a6SJohn Johansen 343e06f75a6SJohn Johansen /* current state is <state>, matching character *str */ 344e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 345e06f75a6SJohn Johansen /* Equivalence class table defined */ 346e06f75a6SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 347e06f75a6SJohn Johansen /* default is direct to next state */ 348e06f75a6SJohn Johansen for (; len; len--) { 349ed686308SJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 350e06f75a6SJohn Johansen if (check[pos] == state) 351e06f75a6SJohn Johansen state = next[pos]; 352e06f75a6SJohn Johansen else 353e06f75a6SJohn Johansen state = def[state]; 354e06f75a6SJohn Johansen } 355e06f75a6SJohn Johansen } else { 356e06f75a6SJohn Johansen /* default is direct to next state */ 357e06f75a6SJohn Johansen for (; len; len--) { 358ed686308SJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 359e06f75a6SJohn Johansen if (check[pos] == state) 360e06f75a6SJohn Johansen state = next[pos]; 361e06f75a6SJohn Johansen else 362e06f75a6SJohn Johansen state = def[state]; 363e06f75a6SJohn Johansen } 364e06f75a6SJohn Johansen } 365e06f75a6SJohn Johansen 366e06f75a6SJohn Johansen return state; 367e06f75a6SJohn Johansen } 368e06f75a6SJohn Johansen 369e06f75a6SJohn Johansen /** 3700fe1212dSJohn Johansen * aa_dfa_match - traverse @dfa to find state @str stops at 371e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 372e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 373e06f75a6SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 374e06f75a6SJohn Johansen * 3750fe1212dSJohn Johansen * aa_dfa_match 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 * Returns: final state reached after input is consumed 380e06f75a6SJohn Johansen */ 381e06f75a6SJohn Johansen unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 382e06f75a6SJohn Johansen const char *str) 383e06f75a6SJohn Johansen { 3840fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 3850fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 3860fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 3870fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 3880fe1212dSJohn Johansen unsigned int state = start, pos; 3890fe1212dSJohn Johansen 3900fe1212dSJohn Johansen if (state == 0) 3910fe1212dSJohn Johansen return 0; 3920fe1212dSJohn Johansen 3930fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 3940fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 3950fe1212dSJohn Johansen /* Equivalence class table defined */ 3960fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 3970fe1212dSJohn Johansen /* default is direct to next state */ 3980fe1212dSJohn Johansen while (*str) { 399ed686308SJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 4000fe1212dSJohn Johansen if (check[pos] == state) 4010fe1212dSJohn Johansen state = next[pos]; 4020fe1212dSJohn Johansen else 4030fe1212dSJohn Johansen state = def[state]; 4040fe1212dSJohn Johansen } 4050fe1212dSJohn Johansen } else { 4060fe1212dSJohn Johansen /* default is direct to next state */ 4070fe1212dSJohn Johansen while (*str) { 408ed686308SJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 4090fe1212dSJohn Johansen if (check[pos] == state) 4100fe1212dSJohn Johansen state = next[pos]; 4110fe1212dSJohn Johansen else 4120fe1212dSJohn Johansen state = def[state]; 4130fe1212dSJohn Johansen } 4140fe1212dSJohn Johansen } 4150fe1212dSJohn Johansen 4160fe1212dSJohn Johansen return state; 4170fe1212dSJohn Johansen } 4180fe1212dSJohn Johansen 4190fe1212dSJohn Johansen /** 4200fe1212dSJohn Johansen * aa_dfa_next - step one character to the next state in the dfa 4210fe1212dSJohn Johansen * @dfa: the dfa to tranverse (NOT NULL) 4220fe1212dSJohn Johansen * @state: the state to start in 4230fe1212dSJohn Johansen * @c: the input character to transition on 4240fe1212dSJohn Johansen * 4250fe1212dSJohn Johansen * aa_dfa_match will step through the dfa by one input character @c 4260fe1212dSJohn Johansen * 4270fe1212dSJohn Johansen * Returns: state reach after input @c 4280fe1212dSJohn Johansen */ 4290fe1212dSJohn Johansen unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 4300fe1212dSJohn Johansen const char c) 4310fe1212dSJohn Johansen { 4320fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 4330fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 4340fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 4350fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 4360fe1212dSJohn Johansen unsigned int pos; 4370fe1212dSJohn Johansen 4380fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 4390fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 4400fe1212dSJohn Johansen /* Equivalence class table defined */ 4410fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 4420fe1212dSJohn Johansen /* default is direct to next state */ 4430fe1212dSJohn Johansen 444ed686308SJohn Johansen pos = base_idx(base[state]) + equiv[(u8) c]; 4450fe1212dSJohn Johansen if (check[pos] == state) 4460fe1212dSJohn Johansen state = next[pos]; 4470fe1212dSJohn Johansen else 4480fe1212dSJohn Johansen state = def[state]; 4490fe1212dSJohn Johansen } else { 4500fe1212dSJohn Johansen /* default is direct to next state */ 451ed686308SJohn Johansen pos = base_idx(base[state]) + (u8) c; 4520fe1212dSJohn Johansen if (check[pos] == state) 4530fe1212dSJohn Johansen state = next[pos]; 4540fe1212dSJohn Johansen else 4550fe1212dSJohn Johansen state = def[state]; 4560fe1212dSJohn Johansen } 4570fe1212dSJohn Johansen 4580fe1212dSJohn Johansen return state; 459e06f75a6SJohn Johansen } 460*cf65fabcSJohn Johansen 461*cf65fabcSJohn Johansen /** 462*cf65fabcSJohn Johansen * aa_dfa_match_until - traverse @dfa until accept state or end of input 463*cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 464*cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 465*cf65fabcSJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 466*cf65fabcSJohn Johansen * @retpos: first character in str after match OR end of string 467*cf65fabcSJohn Johansen * 468*cf65fabcSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 469*cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 470*cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 471*cf65fabcSJohn Johansen * 472*cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 473*cf65fabcSJohn Johansen */ 474*cf65fabcSJohn Johansen unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, 475*cf65fabcSJohn Johansen const char *str, const char **retpos) 476*cf65fabcSJohn Johansen { 477*cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 478*cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 479*cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 480*cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 481*cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 482*cf65fabcSJohn Johansen unsigned int state = start, pos; 483*cf65fabcSJohn Johansen 484*cf65fabcSJohn Johansen if (state == 0) 485*cf65fabcSJohn Johansen return 0; 486*cf65fabcSJohn Johansen 487*cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 488*cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 489*cf65fabcSJohn Johansen /* Equivalence class table defined */ 490*cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 491*cf65fabcSJohn Johansen /* default is direct to next state */ 492*cf65fabcSJohn Johansen while (*str) { 493*cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 494*cf65fabcSJohn Johansen if (check[pos] == state) 495*cf65fabcSJohn Johansen state = next[pos]; 496*cf65fabcSJohn Johansen else 497*cf65fabcSJohn Johansen state = def[state]; 498*cf65fabcSJohn Johansen if (accept[state]) 499*cf65fabcSJohn Johansen break; 500*cf65fabcSJohn Johansen } 501*cf65fabcSJohn Johansen } else { 502*cf65fabcSJohn Johansen /* default is direct to next state */ 503*cf65fabcSJohn Johansen while (*str) { 504*cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 505*cf65fabcSJohn Johansen if (check[pos] == state) 506*cf65fabcSJohn Johansen state = next[pos]; 507*cf65fabcSJohn Johansen else 508*cf65fabcSJohn Johansen state = def[state]; 509*cf65fabcSJohn Johansen if (accept[state]) 510*cf65fabcSJohn Johansen break; 511*cf65fabcSJohn Johansen } 512*cf65fabcSJohn Johansen } 513*cf65fabcSJohn Johansen 514*cf65fabcSJohn Johansen *retpos = str; 515*cf65fabcSJohn Johansen return state; 516*cf65fabcSJohn Johansen } 517*cf65fabcSJohn Johansen 518*cf65fabcSJohn Johansen 519*cf65fabcSJohn Johansen /** 520*cf65fabcSJohn Johansen * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed 521*cf65fabcSJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 522*cf65fabcSJohn Johansen * @start: the state of the dfa to start matching in 523*cf65fabcSJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 524*cf65fabcSJohn Johansen * @n: length of the string of bytes to match 525*cf65fabcSJohn Johansen * @retpos: first character in str after match OR str + n 526*cf65fabcSJohn Johansen * 527*cf65fabcSJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 528*cf65fabcSJohn Johansen * finished matching in. The final state can be used to look up the accepting 529*cf65fabcSJohn Johansen * label, or as the start state of a continuing match. 530*cf65fabcSJohn Johansen * 531*cf65fabcSJohn Johansen * This function will happily match again the 0 byte and only finishes 532*cf65fabcSJohn Johansen * when @n input is consumed. 533*cf65fabcSJohn Johansen * 534*cf65fabcSJohn Johansen * Returns: final state reached after input is consumed 535*cf65fabcSJohn Johansen */ 536*cf65fabcSJohn Johansen unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, 537*cf65fabcSJohn Johansen const char *str, int n, const char **retpos) 538*cf65fabcSJohn Johansen { 539*cf65fabcSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 540*cf65fabcSJohn Johansen u32 *base = BASE_TABLE(dfa); 541*cf65fabcSJohn Johansen u16 *next = NEXT_TABLE(dfa); 542*cf65fabcSJohn Johansen u16 *check = CHECK_TABLE(dfa); 543*cf65fabcSJohn Johansen u32 *accept = ACCEPT_TABLE(dfa); 544*cf65fabcSJohn Johansen unsigned int state = start, pos; 545*cf65fabcSJohn Johansen 546*cf65fabcSJohn Johansen *retpos = NULL; 547*cf65fabcSJohn Johansen if (state == 0) 548*cf65fabcSJohn Johansen return 0; 549*cf65fabcSJohn Johansen 550*cf65fabcSJohn Johansen /* current state is <state>, matching character *str */ 551*cf65fabcSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 552*cf65fabcSJohn Johansen /* Equivalence class table defined */ 553*cf65fabcSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 554*cf65fabcSJohn Johansen /* default is direct to next state */ 555*cf65fabcSJohn Johansen for (; n; n--) { 556*cf65fabcSJohn Johansen pos = base_idx(base[state]) + equiv[(u8) *str++]; 557*cf65fabcSJohn Johansen if (check[pos] == state) 558*cf65fabcSJohn Johansen state = next[pos]; 559*cf65fabcSJohn Johansen else 560*cf65fabcSJohn Johansen state = def[state]; 561*cf65fabcSJohn Johansen if (accept[state]) 562*cf65fabcSJohn Johansen break; 563*cf65fabcSJohn Johansen } 564*cf65fabcSJohn Johansen } else { 565*cf65fabcSJohn Johansen /* default is direct to next state */ 566*cf65fabcSJohn Johansen for (; n; n--) { 567*cf65fabcSJohn Johansen pos = base_idx(base[state]) + (u8) *str++; 568*cf65fabcSJohn Johansen if (check[pos] == state) 569*cf65fabcSJohn Johansen state = next[pos]; 570*cf65fabcSJohn Johansen else 571*cf65fabcSJohn Johansen state = def[state]; 572*cf65fabcSJohn Johansen if (accept[state]) 573*cf65fabcSJohn Johansen break; 574*cf65fabcSJohn Johansen } 575*cf65fabcSJohn Johansen } 576*cf65fabcSJohn Johansen 577*cf65fabcSJohn Johansen *retpos = str; 578*cf65fabcSJohn Johansen return state; 579*cf65fabcSJohn Johansen } 580