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 7e06f75a6SJohn Johansen * Copyright 2009-2010 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 23e06f75a6SJohn Johansen #include "include/apparmor.h" 24e06f75a6SJohn Johansen #include "include/match.h" 25e06f75a6SJohn Johansen 26e06f75a6SJohn Johansen /** 27e06f75a6SJohn Johansen * unpack_table - unpack a dfa table (one of accept, default, base, next check) 28e06f75a6SJohn Johansen * @blob: data to unpack (NOT NULL) 29e06f75a6SJohn Johansen * @bsize: size of blob 30e06f75a6SJohn Johansen * 31e06f75a6SJohn Johansen * Returns: pointer to table else NULL on failure 32e06f75a6SJohn Johansen * 33*0ca554b9SJohn Johansen * NOTE: must be freed by kvfree (not kfree) 34e06f75a6SJohn Johansen */ 35e06f75a6SJohn Johansen static struct table_header *unpack_table(char *blob, size_t bsize) 36e06f75a6SJohn Johansen { 37e06f75a6SJohn Johansen struct table_header *table = NULL; 38e06f75a6SJohn Johansen struct table_header th; 39e06f75a6SJohn Johansen size_t tsize; 40e06f75a6SJohn Johansen 41e06f75a6SJohn Johansen if (bsize < sizeof(struct table_header)) 42e06f75a6SJohn Johansen goto out; 43e06f75a6SJohn Johansen 44e06f75a6SJohn Johansen /* loaded td_id's start at 1, subtract 1 now to avoid doing 45e06f75a6SJohn Johansen * it every time we use td_id as an index 46e06f75a6SJohn Johansen */ 47e06f75a6SJohn Johansen th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1; 48e06f75a6SJohn Johansen th.td_flags = be16_to_cpu(*(u16 *) (blob + 2)); 49e06f75a6SJohn Johansen th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8)); 50e06f75a6SJohn Johansen blob += sizeof(struct table_header); 51e06f75a6SJohn Johansen 52e06f75a6SJohn Johansen if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 53e06f75a6SJohn Johansen th.td_flags == YYTD_DATA8)) 54e06f75a6SJohn Johansen goto out; 55e06f75a6SJohn Johansen 56e06f75a6SJohn Johansen tsize = table_size(th.td_lolen, th.td_flags); 57e06f75a6SJohn Johansen if (bsize < tsize) 58e06f75a6SJohn Johansen goto out; 59e06f75a6SJohn Johansen 60*0ca554b9SJohn Johansen table = kvzalloc(tsize); 61e06f75a6SJohn Johansen if (table) { 62e06f75a6SJohn Johansen *table = th; 63e06f75a6SJohn Johansen if (th.td_flags == YYTD_DATA8) 64e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 65e06f75a6SJohn Johansen u8, byte_to_byte); 66e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA16) 67e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 68e06f75a6SJohn Johansen u16, be16_to_cpu); 69e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA32) 70e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 71e06f75a6SJohn Johansen u32, be32_to_cpu); 72e06f75a6SJohn Johansen else 73e06f75a6SJohn Johansen goto fail; 74e06f75a6SJohn Johansen } 75e06f75a6SJohn Johansen 76e06f75a6SJohn Johansen out: 77e06f75a6SJohn Johansen /* if table was vmalloced make sure the page tables are synced 78e06f75a6SJohn Johansen * before it is used, as it goes live to all cpus. 79e06f75a6SJohn Johansen */ 80e06f75a6SJohn Johansen if (is_vmalloc_addr(table)) 81e06f75a6SJohn Johansen vm_unmap_aliases(); 82e06f75a6SJohn Johansen return table; 83e06f75a6SJohn Johansen fail: 84e06f75a6SJohn Johansen kvfree(table); 85e06f75a6SJohn Johansen return NULL; 86e06f75a6SJohn Johansen } 87e06f75a6SJohn Johansen 88e06f75a6SJohn Johansen /** 89e06f75a6SJohn Johansen * verify_dfa - verify that transitions and states in the tables are in bounds. 90e06f75a6SJohn Johansen * @dfa: dfa to test (NOT NULL) 91e06f75a6SJohn Johansen * @flags: flags controlling what type of accept table are acceptable 92e06f75a6SJohn Johansen * 93e06f75a6SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 94e06f75a6SJohn Johansen * NOTE: this does not valid accept table values 95e06f75a6SJohn Johansen * 96e06f75a6SJohn Johansen * Returns: %0 else error code on failure to verify 97e06f75a6SJohn Johansen */ 98e06f75a6SJohn Johansen static int verify_dfa(struct aa_dfa *dfa, int flags) 99e06f75a6SJohn Johansen { 100e06f75a6SJohn Johansen size_t i, state_count, trans_count; 101e06f75a6SJohn Johansen int error = -EPROTO; 102e06f75a6SJohn Johansen 103e06f75a6SJohn Johansen /* check that required tables exist */ 104e06f75a6SJohn Johansen if (!(dfa->tables[YYTD_ID_DEF] && 105e06f75a6SJohn Johansen dfa->tables[YYTD_ID_BASE] && 106e06f75a6SJohn Johansen dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) 107e06f75a6SJohn Johansen goto out; 108e06f75a6SJohn Johansen 109e06f75a6SJohn Johansen /* accept.size == default.size == base.size */ 110e06f75a6SJohn Johansen state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 111e06f75a6SJohn Johansen if (ACCEPT1_FLAGS(flags)) { 112e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT]) 113e06f75a6SJohn Johansen goto out; 114e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) 115e06f75a6SJohn Johansen goto out; 116e06f75a6SJohn Johansen } 117e06f75a6SJohn Johansen if (ACCEPT2_FLAGS(flags)) { 118e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT2]) 119e06f75a6SJohn Johansen goto out; 120e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) 121e06f75a6SJohn Johansen goto out; 122e06f75a6SJohn Johansen } 123e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) 124e06f75a6SJohn Johansen goto out; 125e06f75a6SJohn Johansen 126e06f75a6SJohn Johansen /* next.size == chk.size */ 127e06f75a6SJohn Johansen trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 128e06f75a6SJohn Johansen if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) 129e06f75a6SJohn Johansen goto out; 130e06f75a6SJohn Johansen 131e06f75a6SJohn Johansen /* if equivalence classes then its table size must be 256 */ 132e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC] && 133e06f75a6SJohn Johansen dfa->tables[YYTD_ID_EC]->td_lolen != 256) 134e06f75a6SJohn Johansen goto out; 135e06f75a6SJohn Johansen 136e06f75a6SJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 137e06f75a6SJohn Johansen for (i = 0; i < state_count; i++) { 138e06f75a6SJohn Johansen if (DEFAULT_TABLE(dfa)[i] >= state_count) 139e06f75a6SJohn Johansen goto out; 140e06f75a6SJohn Johansen /* TODO: do check that DEF state recursion terminates */ 141e06f75a6SJohn Johansen if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { 142e06f75a6SJohn Johansen printk(KERN_ERR "AppArmor DFA next/check upper " 143e06f75a6SJohn Johansen "bounds error\n"); 144e06f75a6SJohn Johansen goto out; 145e06f75a6SJohn Johansen } 146e06f75a6SJohn Johansen } 147e06f75a6SJohn Johansen 148e06f75a6SJohn Johansen for (i = 0; i < trans_count; i++) { 149e06f75a6SJohn Johansen if (NEXT_TABLE(dfa)[i] >= state_count) 150e06f75a6SJohn Johansen goto out; 151e06f75a6SJohn Johansen if (CHECK_TABLE(dfa)[i] >= state_count) 152e06f75a6SJohn Johansen goto out; 153e06f75a6SJohn Johansen } 154e06f75a6SJohn Johansen } 155e06f75a6SJohn Johansen 156e06f75a6SJohn Johansen error = 0; 157e06f75a6SJohn Johansen out: 158e06f75a6SJohn Johansen return error; 159e06f75a6SJohn Johansen } 160e06f75a6SJohn Johansen 161e06f75a6SJohn Johansen /** 162e06f75a6SJohn Johansen * dfa_free - free a dfa allocated by aa_dfa_unpack 163e06f75a6SJohn Johansen * @dfa: the dfa to free (MAYBE NULL) 164e06f75a6SJohn Johansen * 165e06f75a6SJohn Johansen * Requires: reference count to dfa == 0 166e06f75a6SJohn Johansen */ 167e06f75a6SJohn Johansen static void dfa_free(struct aa_dfa *dfa) 168e06f75a6SJohn Johansen { 169e06f75a6SJohn Johansen if (dfa) { 170e06f75a6SJohn Johansen int i; 171e06f75a6SJohn Johansen 172e06f75a6SJohn Johansen for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 173e06f75a6SJohn Johansen kvfree(dfa->tables[i]); 174e06f75a6SJohn Johansen dfa->tables[i] = NULL; 175e06f75a6SJohn Johansen } 176e06f75a6SJohn Johansen kfree(dfa); 177e06f75a6SJohn Johansen } 178e06f75a6SJohn Johansen } 179e06f75a6SJohn Johansen 180e06f75a6SJohn Johansen /** 181e06f75a6SJohn Johansen * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 182e06f75a6SJohn Johansen * @kr: kref callback for freeing of a dfa (NOT NULL) 183e06f75a6SJohn Johansen */ 184e06f75a6SJohn Johansen void aa_dfa_free_kref(struct kref *kref) 185e06f75a6SJohn Johansen { 186e06f75a6SJohn Johansen struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 187e06f75a6SJohn Johansen dfa_free(dfa); 188e06f75a6SJohn Johansen } 189e06f75a6SJohn Johansen 190e06f75a6SJohn Johansen /** 191e06f75a6SJohn Johansen * aa_dfa_unpack - unpack the binary tables of a serialized dfa 192e06f75a6SJohn Johansen * @blob: aligned serialized stream of data to unpack (NOT NULL) 193e06f75a6SJohn Johansen * @size: size of data to unpack 194e06f75a6SJohn Johansen * @flags: flags controlling what type of accept tables are acceptable 195e06f75a6SJohn Johansen * 196e06f75a6SJohn Johansen * Unpack a dfa that has been serialized. To find information on the dfa 197d410fa4eSRandy Dunlap * format look in Documentation/security/apparmor.txt 19825985edcSLucas De Marchi * Assumes the dfa @blob stream has been aligned on a 8 byte boundary 199e06f75a6SJohn Johansen * 200e06f75a6SJohn Johansen * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 201e06f75a6SJohn Johansen */ 202e06f75a6SJohn Johansen struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 203e06f75a6SJohn Johansen { 204e06f75a6SJohn Johansen int hsize; 205e06f75a6SJohn Johansen int error = -ENOMEM; 206e06f75a6SJohn Johansen char *data = blob; 207e06f75a6SJohn Johansen struct table_header *table = NULL; 208e06f75a6SJohn Johansen struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 209e06f75a6SJohn Johansen if (!dfa) 210e06f75a6SJohn Johansen goto fail; 211e06f75a6SJohn Johansen 212e06f75a6SJohn Johansen kref_init(&dfa->count); 213e06f75a6SJohn Johansen 214e06f75a6SJohn Johansen error = -EPROTO; 215e06f75a6SJohn Johansen 216e06f75a6SJohn Johansen /* get dfa table set header */ 217e06f75a6SJohn Johansen if (size < sizeof(struct table_set_header)) 218e06f75a6SJohn Johansen goto fail; 219e06f75a6SJohn Johansen 220e06f75a6SJohn Johansen if (ntohl(*(u32 *) data) != YYTH_MAGIC) 221e06f75a6SJohn Johansen goto fail; 222e06f75a6SJohn Johansen 223e06f75a6SJohn Johansen hsize = ntohl(*(u32 *) (data + 4)); 224e06f75a6SJohn Johansen if (size < hsize) 225e06f75a6SJohn Johansen goto fail; 226e06f75a6SJohn Johansen 227e06f75a6SJohn Johansen dfa->flags = ntohs(*(u16 *) (data + 12)); 228e06f75a6SJohn Johansen data += hsize; 229e06f75a6SJohn Johansen size -= hsize; 230e06f75a6SJohn Johansen 231e06f75a6SJohn Johansen while (size > 0) { 232e06f75a6SJohn Johansen table = unpack_table(data, size); 233e06f75a6SJohn Johansen if (!table) 234e06f75a6SJohn Johansen goto fail; 235e06f75a6SJohn Johansen 236e06f75a6SJohn Johansen switch (table->td_id) { 237e06f75a6SJohn Johansen case YYTD_ID_ACCEPT: 238e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 239e06f75a6SJohn Johansen goto fail; 240e06f75a6SJohn Johansen break; 241e06f75a6SJohn Johansen case YYTD_ID_ACCEPT2: 242e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 243e06f75a6SJohn Johansen goto fail; 244e06f75a6SJohn Johansen break; 245e06f75a6SJohn Johansen case YYTD_ID_BASE: 246e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA32) 247e06f75a6SJohn Johansen goto fail; 248e06f75a6SJohn Johansen break; 249e06f75a6SJohn Johansen case YYTD_ID_DEF: 250e06f75a6SJohn Johansen case YYTD_ID_NXT: 251e06f75a6SJohn Johansen case YYTD_ID_CHK: 252e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA16) 253e06f75a6SJohn Johansen goto fail; 254e06f75a6SJohn Johansen break; 255e06f75a6SJohn Johansen case YYTD_ID_EC: 256e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA8) 257e06f75a6SJohn Johansen goto fail; 258e06f75a6SJohn Johansen break; 259e06f75a6SJohn Johansen default: 260e06f75a6SJohn Johansen goto fail; 261e06f75a6SJohn Johansen } 262e06f75a6SJohn Johansen /* check for duplicate table entry */ 263e06f75a6SJohn Johansen if (dfa->tables[table->td_id]) 264e06f75a6SJohn Johansen goto fail; 265e06f75a6SJohn Johansen dfa->tables[table->td_id] = table; 266e06f75a6SJohn Johansen data += table_size(table->td_lolen, table->td_flags); 267e06f75a6SJohn Johansen size -= table_size(table->td_lolen, table->td_flags); 268e06f75a6SJohn Johansen table = NULL; 269e06f75a6SJohn Johansen } 270e06f75a6SJohn Johansen 271e06f75a6SJohn Johansen error = verify_dfa(dfa, flags); 272e06f75a6SJohn Johansen if (error) 273e06f75a6SJohn Johansen goto fail; 274e06f75a6SJohn Johansen 275e06f75a6SJohn Johansen return dfa; 276e06f75a6SJohn Johansen 277e06f75a6SJohn Johansen fail: 278e06f75a6SJohn Johansen kvfree(table); 279e06f75a6SJohn Johansen dfa_free(dfa); 280e06f75a6SJohn Johansen return ERR_PTR(error); 281e06f75a6SJohn Johansen } 282e06f75a6SJohn Johansen 283e06f75a6SJohn Johansen /** 284e06f75a6SJohn Johansen * aa_dfa_match_len - traverse @dfa to find state @str stops at 285e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 286e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 287e06f75a6SJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 288e06f75a6SJohn Johansen * @len: length of the string of bytes to match 289e06f75a6SJohn Johansen * 290e06f75a6SJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 291e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 292e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 293e06f75a6SJohn Johansen * 294e06f75a6SJohn Johansen * This function will happily match again the 0 byte and only finishes 295e06f75a6SJohn Johansen * when @len input is consumed. 296e06f75a6SJohn Johansen * 297e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 298e06f75a6SJohn Johansen */ 299e06f75a6SJohn Johansen unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 300e06f75a6SJohn Johansen const char *str, int len) 301e06f75a6SJohn Johansen { 302e06f75a6SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 303e06f75a6SJohn Johansen u32 *base = BASE_TABLE(dfa); 304e06f75a6SJohn Johansen u16 *next = NEXT_TABLE(dfa); 305e06f75a6SJohn Johansen u16 *check = CHECK_TABLE(dfa); 306e06f75a6SJohn Johansen unsigned int state = start, pos; 307e06f75a6SJohn Johansen 308e06f75a6SJohn Johansen if (state == 0) 309e06f75a6SJohn Johansen return 0; 310e06f75a6SJohn Johansen 311e06f75a6SJohn Johansen /* current state is <state>, matching character *str */ 312e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 313e06f75a6SJohn Johansen /* Equivalence class table defined */ 314e06f75a6SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 315e06f75a6SJohn Johansen /* default is direct to next state */ 316e06f75a6SJohn Johansen for (; len; len--) { 317e06f75a6SJohn Johansen pos = base[state] + equiv[(u8) *str++]; 318e06f75a6SJohn Johansen if (check[pos] == state) 319e06f75a6SJohn Johansen state = next[pos]; 320e06f75a6SJohn Johansen else 321e06f75a6SJohn Johansen state = def[state]; 322e06f75a6SJohn Johansen } 323e06f75a6SJohn Johansen } else { 324e06f75a6SJohn Johansen /* default is direct to next state */ 325e06f75a6SJohn Johansen for (; len; len--) { 326e06f75a6SJohn Johansen pos = base[state] + (u8) *str++; 327e06f75a6SJohn Johansen if (check[pos] == state) 328e06f75a6SJohn Johansen state = next[pos]; 329e06f75a6SJohn Johansen else 330e06f75a6SJohn Johansen state = def[state]; 331e06f75a6SJohn Johansen } 332e06f75a6SJohn Johansen } 333e06f75a6SJohn Johansen 334e06f75a6SJohn Johansen return state; 335e06f75a6SJohn Johansen } 336e06f75a6SJohn Johansen 337e06f75a6SJohn Johansen /** 3380fe1212dSJohn Johansen * aa_dfa_match - traverse @dfa to find state @str stops at 339e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 340e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 341e06f75a6SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 342e06f75a6SJohn Johansen * 3430fe1212dSJohn Johansen * aa_dfa_match will match @str against the dfa and return the state it 344e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 345e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 346e06f75a6SJohn Johansen * 347e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 348e06f75a6SJohn Johansen */ 349e06f75a6SJohn Johansen unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 350e06f75a6SJohn Johansen const char *str) 351e06f75a6SJohn Johansen { 3520fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 3530fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 3540fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 3550fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 3560fe1212dSJohn Johansen unsigned int state = start, pos; 3570fe1212dSJohn Johansen 3580fe1212dSJohn Johansen if (state == 0) 3590fe1212dSJohn Johansen return 0; 3600fe1212dSJohn Johansen 3610fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 3620fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 3630fe1212dSJohn Johansen /* Equivalence class table defined */ 3640fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 3650fe1212dSJohn Johansen /* default is direct to next state */ 3660fe1212dSJohn Johansen while (*str) { 3670fe1212dSJohn Johansen pos = base[state] + equiv[(u8) *str++]; 3680fe1212dSJohn Johansen if (check[pos] == state) 3690fe1212dSJohn Johansen state = next[pos]; 3700fe1212dSJohn Johansen else 3710fe1212dSJohn Johansen state = def[state]; 3720fe1212dSJohn Johansen } 3730fe1212dSJohn Johansen } else { 3740fe1212dSJohn Johansen /* default is direct to next state */ 3750fe1212dSJohn Johansen while (*str) { 3760fe1212dSJohn Johansen pos = base[state] + (u8) *str++; 3770fe1212dSJohn Johansen if (check[pos] == state) 3780fe1212dSJohn Johansen state = next[pos]; 3790fe1212dSJohn Johansen else 3800fe1212dSJohn Johansen state = def[state]; 3810fe1212dSJohn Johansen } 3820fe1212dSJohn Johansen } 3830fe1212dSJohn Johansen 3840fe1212dSJohn Johansen return state; 3850fe1212dSJohn Johansen } 3860fe1212dSJohn Johansen 3870fe1212dSJohn Johansen /** 3880fe1212dSJohn Johansen * aa_dfa_next - step one character to the next state in the dfa 3890fe1212dSJohn Johansen * @dfa: the dfa to tranverse (NOT NULL) 3900fe1212dSJohn Johansen * @state: the state to start in 3910fe1212dSJohn Johansen * @c: the input character to transition on 3920fe1212dSJohn Johansen * 3930fe1212dSJohn Johansen * aa_dfa_match will step through the dfa by one input character @c 3940fe1212dSJohn Johansen * 3950fe1212dSJohn Johansen * Returns: state reach after input @c 3960fe1212dSJohn Johansen */ 3970fe1212dSJohn Johansen unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 3980fe1212dSJohn Johansen const char c) 3990fe1212dSJohn Johansen { 4000fe1212dSJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 4010fe1212dSJohn Johansen u32 *base = BASE_TABLE(dfa); 4020fe1212dSJohn Johansen u16 *next = NEXT_TABLE(dfa); 4030fe1212dSJohn Johansen u16 *check = CHECK_TABLE(dfa); 4040fe1212dSJohn Johansen unsigned int pos; 4050fe1212dSJohn Johansen 4060fe1212dSJohn Johansen /* current state is <state>, matching character *str */ 4070fe1212dSJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 4080fe1212dSJohn Johansen /* Equivalence class table defined */ 4090fe1212dSJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 4100fe1212dSJohn Johansen /* default is direct to next state */ 4110fe1212dSJohn Johansen 4120fe1212dSJohn Johansen pos = base[state] + equiv[(u8) c]; 4130fe1212dSJohn Johansen if (check[pos] == state) 4140fe1212dSJohn Johansen state = next[pos]; 4150fe1212dSJohn Johansen else 4160fe1212dSJohn Johansen state = def[state]; 4170fe1212dSJohn Johansen } else { 4180fe1212dSJohn Johansen /* default is direct to next state */ 4190fe1212dSJohn Johansen pos = base[state] + (u8) c; 4200fe1212dSJohn Johansen if (check[pos] == state) 4210fe1212dSJohn Johansen state = next[pos]; 4220fe1212dSJohn Johansen else 4230fe1212dSJohn Johansen state = def[state]; 4240fe1212dSJohn Johansen } 4250fe1212dSJohn Johansen 4260fe1212dSJohn Johansen return state; 427e06f75a6SJohn Johansen } 428