18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor dfa based regular expression matching engine 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2012 Canonical Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/kref.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "include/lib.h" 208c2ecf20Sopenharmony_ci#include "include/match.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define base_idx(X) ((X) & 0xffffff) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic char nulldfa_src[] = { 258c2ecf20Sopenharmony_ci #include "nulldfa.in" 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_cistruct aa_dfa *nulldfa; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic char stacksplitdfa_src[] = { 308c2ecf20Sopenharmony_ci #include "stacksplitdfa.in" 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_cistruct aa_dfa *stacksplitdfa; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciint aa_setup_dfa_engine(void) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int error; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 398c2ecf20Sopenharmony_ci TO_ACCEPT1_FLAG(YYTD_DATA32) | 408c2ecf20Sopenharmony_ci TO_ACCEPT2_FLAG(YYTD_DATA32)); 418c2ecf20Sopenharmony_ci if (IS_ERR(nulldfa)) { 428c2ecf20Sopenharmony_ci error = PTR_ERR(nulldfa); 438c2ecf20Sopenharmony_ci nulldfa = NULL; 448c2ecf20Sopenharmony_ci return error; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, 488c2ecf20Sopenharmony_ci sizeof(stacksplitdfa_src), 498c2ecf20Sopenharmony_ci TO_ACCEPT1_FLAG(YYTD_DATA32) | 508c2ecf20Sopenharmony_ci TO_ACCEPT2_FLAG(YYTD_DATA32)); 518c2ecf20Sopenharmony_ci if (IS_ERR(stacksplitdfa)) { 528c2ecf20Sopenharmony_ci aa_put_dfa(nulldfa); 538c2ecf20Sopenharmony_ci nulldfa = NULL; 548c2ecf20Sopenharmony_ci error = PTR_ERR(stacksplitdfa); 558c2ecf20Sopenharmony_ci stacksplitdfa = NULL; 568c2ecf20Sopenharmony_ci return error; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_civoid aa_teardown_dfa_engine(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci aa_put_dfa(stacksplitdfa); 658c2ecf20Sopenharmony_ci aa_put_dfa(nulldfa); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/** 698c2ecf20Sopenharmony_ci * unpack_table - unpack a dfa table (one of accept, default, base, next check) 708c2ecf20Sopenharmony_ci * @blob: data to unpack (NOT NULL) 718c2ecf20Sopenharmony_ci * @bsize: size of blob 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Returns: pointer to table else NULL on failure 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * NOTE: must be freed by kvfree (not kfree) 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistatic struct table_header *unpack_table(char *blob, size_t bsize) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct table_header *table = NULL; 808c2ecf20Sopenharmony_ci struct table_header th; 818c2ecf20Sopenharmony_ci size_t tsize; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (bsize < sizeof(struct table_header)) 848c2ecf20Sopenharmony_ci goto out; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* loaded td_id's start at 1, subtract 1 now to avoid doing 878c2ecf20Sopenharmony_ci * it every time we use td_id as an index 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1; 908c2ecf20Sopenharmony_ci if (th.td_id > YYTD_ID_MAX) 918c2ecf20Sopenharmony_ci goto out; 928c2ecf20Sopenharmony_ci th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2)); 938c2ecf20Sopenharmony_ci th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8)); 948c2ecf20Sopenharmony_ci blob += sizeof(struct table_header); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 978c2ecf20Sopenharmony_ci th.td_flags == YYTD_DATA8)) 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* if we have a table it must have some entries */ 1018c2ecf20Sopenharmony_ci if (th.td_lolen == 0) 1028c2ecf20Sopenharmony_ci goto out; 1038c2ecf20Sopenharmony_ci tsize = table_size(th.td_lolen, th.td_flags); 1048c2ecf20Sopenharmony_ci if (bsize < tsize) 1058c2ecf20Sopenharmony_ci goto out; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci table = kvzalloc(tsize, GFP_KERNEL); 1088c2ecf20Sopenharmony_ci if (table) { 1098c2ecf20Sopenharmony_ci table->td_id = th.td_id; 1108c2ecf20Sopenharmony_ci table->td_flags = th.td_flags; 1118c2ecf20Sopenharmony_ci table->td_lolen = th.td_lolen; 1128c2ecf20Sopenharmony_ci if (th.td_flags == YYTD_DATA8) 1138c2ecf20Sopenharmony_ci UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 1148c2ecf20Sopenharmony_ci u8, u8, byte_to_byte); 1158c2ecf20Sopenharmony_ci else if (th.td_flags == YYTD_DATA16) 1168c2ecf20Sopenharmony_ci UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 1178c2ecf20Sopenharmony_ci u16, __be16, be16_to_cpu); 1188c2ecf20Sopenharmony_ci else if (th.td_flags == YYTD_DATA32) 1198c2ecf20Sopenharmony_ci UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 1208c2ecf20Sopenharmony_ci u32, __be32, be32_to_cpu); 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci goto fail; 1238c2ecf20Sopenharmony_ci /* if table was vmalloced make sure the page tables are synced 1248c2ecf20Sopenharmony_ci * before it is used, as it goes live to all cpus. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci if (is_vmalloc_addr(table)) 1278c2ecf20Sopenharmony_ci vm_unmap_aliases(); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciout: 1318c2ecf20Sopenharmony_ci return table; 1328c2ecf20Sopenharmony_cifail: 1338c2ecf20Sopenharmony_ci kvfree(table); 1348c2ecf20Sopenharmony_ci return NULL; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/** 1388c2ecf20Sopenharmony_ci * verify_table_headers - verify that the tables headers are as expected 1398c2ecf20Sopenharmony_ci * @tables - array of dfa tables to check (NOT NULL) 1408c2ecf20Sopenharmony_ci * @flags: flags controlling what type of accept table are acceptable 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * Assumes dfa has gone through the first pass verification done by unpacking 1438c2ecf20Sopenharmony_ci * NOTE: this does not valid accept table values 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Returns: %0 else error code on failure to verify 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_cistatic int verify_table_headers(struct table_header **tables, int flags) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci size_t state_count, trans_count; 1508c2ecf20Sopenharmony_ci int error = -EPROTO; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* check that required tables exist */ 1538c2ecf20Sopenharmony_ci if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] && 1548c2ecf20Sopenharmony_ci tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK])) 1558c2ecf20Sopenharmony_ci goto out; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* accept.size == default.size == base.size */ 1588c2ecf20Sopenharmony_ci state_count = tables[YYTD_ID_BASE]->td_lolen; 1598c2ecf20Sopenharmony_ci if (ACCEPT1_FLAGS(flags)) { 1608c2ecf20Sopenharmony_ci if (!tables[YYTD_ID_ACCEPT]) 1618c2ecf20Sopenharmony_ci goto out; 1628c2ecf20Sopenharmony_ci if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen) 1638c2ecf20Sopenharmony_ci goto out; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci if (ACCEPT2_FLAGS(flags)) { 1668c2ecf20Sopenharmony_ci if (!tables[YYTD_ID_ACCEPT2]) 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen) 1698c2ecf20Sopenharmony_ci goto out; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci if (state_count != tables[YYTD_ID_DEF]->td_lolen) 1728c2ecf20Sopenharmony_ci goto out; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* next.size == chk.size */ 1758c2ecf20Sopenharmony_ci trans_count = tables[YYTD_ID_NXT]->td_lolen; 1768c2ecf20Sopenharmony_ci if (trans_count != tables[YYTD_ID_CHK]->td_lolen) 1778c2ecf20Sopenharmony_ci goto out; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* if equivalence classes then its table size must be 256 */ 1808c2ecf20Sopenharmony_ci if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256) 1818c2ecf20Sopenharmony_ci goto out; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci error = 0; 1848c2ecf20Sopenharmony_ciout: 1858c2ecf20Sopenharmony_ci return error; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * verify_dfa - verify that transitions and states in the tables are in bounds. 1908c2ecf20Sopenharmony_ci * @dfa: dfa to test (NOT NULL) 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Assumes dfa has gone through the first pass verification done by unpacking 1938c2ecf20Sopenharmony_ci * NOTE: this does not valid accept table values 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * Returns: %0 else error code on failure to verify 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic int verify_dfa(struct aa_dfa *dfa) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci size_t i, state_count, trans_count; 2008c2ecf20Sopenharmony_ci int error = -EPROTO; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 2038c2ecf20Sopenharmony_ci trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 2048c2ecf20Sopenharmony_ci if (state_count == 0) 2058c2ecf20Sopenharmony_ci goto out; 2068c2ecf20Sopenharmony_ci for (i = 0; i < state_count; i++) { 2078c2ecf20Sopenharmony_ci if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && 2088c2ecf20Sopenharmony_ci (DEFAULT_TABLE(dfa)[i] >= state_count)) 2098c2ecf20Sopenharmony_ci goto out; 2108c2ecf20Sopenharmony_ci if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) { 2118c2ecf20Sopenharmony_ci pr_err("AppArmor DFA state with invalid match flags"); 2128c2ecf20Sopenharmony_ci goto out; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE)) { 2158c2ecf20Sopenharmony_ci if (!(dfa->flags & YYTH_FLAG_DIFF_ENCODE)) { 2168c2ecf20Sopenharmony_ci pr_err("AppArmor DFA diff encoded transition state without header flag"); 2178c2ecf20Sopenharmony_ci goto out; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_OOB_TRANSITION)) { 2218c2ecf20Sopenharmony_ci if (base_idx(BASE_TABLE(dfa)[i]) < dfa->max_oob) { 2228c2ecf20Sopenharmony_ci pr_err("AppArmor DFA out of bad transition out of range"); 2238c2ecf20Sopenharmony_ci goto out; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci if (!(dfa->flags & YYTH_FLAG_OOB_TRANS)) { 2268c2ecf20Sopenharmony_ci pr_err("AppArmor DFA out of bad transition state without header flag"); 2278c2ecf20Sopenharmony_ci goto out; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { 2318c2ecf20Sopenharmony_ci pr_err("AppArmor DFA next/check upper bounds error\n"); 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci for (i = 0; i < trans_count; i++) { 2378c2ecf20Sopenharmony_ci if (NEXT_TABLE(dfa)[i] >= state_count) 2388c2ecf20Sopenharmony_ci goto out; 2398c2ecf20Sopenharmony_ci if (CHECK_TABLE(dfa)[i] >= state_count) 2408c2ecf20Sopenharmony_ci goto out; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Now that all the other tables are verified, verify diffencoding */ 2448c2ecf20Sopenharmony_ci for (i = 0; i < state_count; i++) { 2458c2ecf20Sopenharmony_ci size_t j, k; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci for (j = i; 2488c2ecf20Sopenharmony_ci (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && 2498c2ecf20Sopenharmony_ci !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); 2508c2ecf20Sopenharmony_ci j = k) { 2518c2ecf20Sopenharmony_ci k = DEFAULT_TABLE(dfa)[j]; 2528c2ecf20Sopenharmony_ci if (j == k) 2538c2ecf20Sopenharmony_ci goto out; 2548c2ecf20Sopenharmony_ci if (k < j) 2558c2ecf20Sopenharmony_ci break; /* already verified */ 2568c2ecf20Sopenharmony_ci BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci error = 0; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciout: 2628c2ecf20Sopenharmony_ci return error; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci/** 2668c2ecf20Sopenharmony_ci * dfa_free - free a dfa allocated by aa_dfa_unpack 2678c2ecf20Sopenharmony_ci * @dfa: the dfa to free (MAYBE NULL) 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Requires: reference count to dfa == 0 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic void dfa_free(struct aa_dfa *dfa) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci if (dfa) { 2748c2ecf20Sopenharmony_ci int i; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 2778c2ecf20Sopenharmony_ci kvfree(dfa->tables[i]); 2788c2ecf20Sopenharmony_ci dfa->tables[i] = NULL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci kfree(dfa); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/** 2858c2ecf20Sopenharmony_ci * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 2868c2ecf20Sopenharmony_ci * @kr: kref callback for freeing of a dfa (NOT NULL) 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_civoid aa_dfa_free_kref(struct kref *kref) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 2918c2ecf20Sopenharmony_ci dfa_free(dfa); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/** 2958c2ecf20Sopenharmony_ci * aa_dfa_unpack - unpack the binary tables of a serialized dfa 2968c2ecf20Sopenharmony_ci * @blob: aligned serialized stream of data to unpack (NOT NULL) 2978c2ecf20Sopenharmony_ci * @size: size of data to unpack 2988c2ecf20Sopenharmony_ci * @flags: flags controlling what type of accept tables are acceptable 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Unpack a dfa that has been serialized. To find information on the dfa 3018c2ecf20Sopenharmony_ci * format look in Documentation/admin-guide/LSM/apparmor.rst 3028c2ecf20Sopenharmony_ci * Assumes the dfa @blob stream has been aligned on a 8 byte boundary 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistruct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci int hsize; 3098c2ecf20Sopenharmony_ci int error = -ENOMEM; 3108c2ecf20Sopenharmony_ci char *data = blob; 3118c2ecf20Sopenharmony_ci struct table_header *table = NULL; 3128c2ecf20Sopenharmony_ci struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 3138c2ecf20Sopenharmony_ci if (!dfa) 3148c2ecf20Sopenharmony_ci goto fail; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci kref_init(&dfa->count); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci error = -EPROTO; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* get dfa table set header */ 3218c2ecf20Sopenharmony_ci if (size < sizeof(struct table_set_header)) 3228c2ecf20Sopenharmony_ci goto fail; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (ntohl(*(__be32 *) data) != YYTH_MAGIC) 3258c2ecf20Sopenharmony_ci goto fail; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci hsize = ntohl(*(__be32 *) (data + 4)); 3288c2ecf20Sopenharmony_ci if (size < hsize) 3298c2ecf20Sopenharmony_ci goto fail; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dfa->flags = ntohs(*(__be16 *) (data + 12)); 3328c2ecf20Sopenharmony_ci if (dfa->flags & ~(YYTH_FLAGS)) 3338c2ecf20Sopenharmony_ci goto fail; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * TODO: needed for dfa to support more than 1 oob 3378c2ecf20Sopenharmony_ci * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) { 3388c2ecf20Sopenharmony_ci * if (hsize < 16 + 4) 3398c2ecf20Sopenharmony_ci * goto fail; 3408c2ecf20Sopenharmony_ci * dfa->max_oob = ntol(*(__be32 *) (data + 16)); 3418c2ecf20Sopenharmony_ci * if (dfa->max <= MAX_OOB_SUPPORTED) { 3428c2ecf20Sopenharmony_ci * pr_err("AppArmor DFA OOB greater than supported\n"); 3438c2ecf20Sopenharmony_ci * goto fail; 3448c2ecf20Sopenharmony_ci * } 3458c2ecf20Sopenharmony_ci * } 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci dfa->max_oob = 1; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci data += hsize; 3508c2ecf20Sopenharmony_ci size -= hsize; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci while (size > 0) { 3538c2ecf20Sopenharmony_ci table = unpack_table(data, size); 3548c2ecf20Sopenharmony_ci if (!table) 3558c2ecf20Sopenharmony_ci goto fail; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci switch (table->td_id) { 3588c2ecf20Sopenharmony_ci case YYTD_ID_ACCEPT: 3598c2ecf20Sopenharmony_ci if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 3608c2ecf20Sopenharmony_ci goto fail; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci case YYTD_ID_ACCEPT2: 3638c2ecf20Sopenharmony_ci if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 3648c2ecf20Sopenharmony_ci goto fail; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci case YYTD_ID_BASE: 3678c2ecf20Sopenharmony_ci if (table->td_flags != YYTD_DATA32) 3688c2ecf20Sopenharmony_ci goto fail; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case YYTD_ID_DEF: 3718c2ecf20Sopenharmony_ci case YYTD_ID_NXT: 3728c2ecf20Sopenharmony_ci case YYTD_ID_CHK: 3738c2ecf20Sopenharmony_ci if (table->td_flags != YYTD_DATA16) 3748c2ecf20Sopenharmony_ci goto fail; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case YYTD_ID_EC: 3778c2ecf20Sopenharmony_ci if (table->td_flags != YYTD_DATA8) 3788c2ecf20Sopenharmony_ci goto fail; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci default: 3818c2ecf20Sopenharmony_ci goto fail; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci /* check for duplicate table entry */ 3848c2ecf20Sopenharmony_ci if (dfa->tables[table->td_id]) 3858c2ecf20Sopenharmony_ci goto fail; 3868c2ecf20Sopenharmony_ci dfa->tables[table->td_id] = table; 3878c2ecf20Sopenharmony_ci data += table_size(table->td_lolen, table->td_flags); 3888c2ecf20Sopenharmony_ci size -= table_size(table->td_lolen, table->td_flags); 3898c2ecf20Sopenharmony_ci table = NULL; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci error = verify_table_headers(dfa->tables, flags); 3928c2ecf20Sopenharmony_ci if (error) 3938c2ecf20Sopenharmony_ci goto fail; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (flags & DFA_FLAG_VERIFY_STATES) { 3968c2ecf20Sopenharmony_ci error = verify_dfa(dfa); 3978c2ecf20Sopenharmony_ci if (error) 3988c2ecf20Sopenharmony_ci goto fail; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return dfa; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cifail: 4048c2ecf20Sopenharmony_ci kvfree(table); 4058c2ecf20Sopenharmony_ci dfa_free(dfa); 4068c2ecf20Sopenharmony_ci return ERR_PTR(error); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#define match_char(state, def, base, next, check, C) \ 4108c2ecf20Sopenharmony_cido { \ 4118c2ecf20Sopenharmony_ci u32 b = (base)[(state)]; \ 4128c2ecf20Sopenharmony_ci unsigned int pos = base_idx(b) + (C); \ 4138c2ecf20Sopenharmony_ci if ((check)[pos] != (state)) { \ 4148c2ecf20Sopenharmony_ci (state) = (def)[(state)]; \ 4158c2ecf20Sopenharmony_ci if (b & MATCH_FLAG_DIFF_ENCODE) \ 4168c2ecf20Sopenharmony_ci continue; \ 4178c2ecf20Sopenharmony_ci break; \ 4188c2ecf20Sopenharmony_ci } \ 4198c2ecf20Sopenharmony_ci (state) = (next)[pos]; \ 4208c2ecf20Sopenharmony_ci break; \ 4218c2ecf20Sopenharmony_ci} while (1) 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/** 4248c2ecf20Sopenharmony_ci * aa_dfa_match_len - traverse @dfa to find state @str stops at 4258c2ecf20Sopenharmony_ci * @dfa: the dfa to match @str against (NOT NULL) 4268c2ecf20Sopenharmony_ci * @start: the state of the dfa to start matching in 4278c2ecf20Sopenharmony_ci * @str: the string of bytes to match against the dfa (NOT NULL) 4288c2ecf20Sopenharmony_ci * @len: length of the string of bytes to match 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * aa_dfa_match_len will match @str against the dfa and return the state it 4318c2ecf20Sopenharmony_ci * finished matching in. The final state can be used to look up the accepting 4328c2ecf20Sopenharmony_ci * label, or as the start state of a continuing match. 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * This function will happily match again the 0 byte and only finishes 4358c2ecf20Sopenharmony_ci * when @len input is consumed. 4368c2ecf20Sopenharmony_ci * 4378c2ecf20Sopenharmony_ci * Returns: final state reached after input is consumed 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ciunsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 4408c2ecf20Sopenharmony_ci const char *str, int len) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 4438c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 4448c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 4458c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 4468c2ecf20Sopenharmony_ci unsigned int state = start; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (state == 0) 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 4528c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 4538c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 4548c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 4558c2ecf20Sopenharmony_ci for (; len; len--) 4568c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, 4578c2ecf20Sopenharmony_ci equiv[(u8) *str++]); 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci /* default is direct to next state */ 4608c2ecf20Sopenharmony_ci for (; len; len--) 4618c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, (u8) *str++); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return state; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/** 4688c2ecf20Sopenharmony_ci * aa_dfa_match - traverse @dfa to find state @str stops at 4698c2ecf20Sopenharmony_ci * @dfa: the dfa to match @str against (NOT NULL) 4708c2ecf20Sopenharmony_ci * @start: the state of the dfa to start matching in 4718c2ecf20Sopenharmony_ci * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 4728c2ecf20Sopenharmony_ci * 4738c2ecf20Sopenharmony_ci * aa_dfa_match will match @str against the dfa and return the state it 4748c2ecf20Sopenharmony_ci * finished matching in. The final state can be used to look up the accepting 4758c2ecf20Sopenharmony_ci * label, or as the start state of a continuing match. 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * Returns: final state reached after input is consumed 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ciunsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 4808c2ecf20Sopenharmony_ci const char *str) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 4838c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 4848c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 4858c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 4868c2ecf20Sopenharmony_ci unsigned int state = start; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (state == 0) 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 4928c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 4938c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 4948c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 4958c2ecf20Sopenharmony_ci /* default is direct to next state */ 4968c2ecf20Sopenharmony_ci while (*str) 4978c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, 4988c2ecf20Sopenharmony_ci equiv[(u8) *str++]); 4998c2ecf20Sopenharmony_ci } else { 5008c2ecf20Sopenharmony_ci /* default is direct to next state */ 5018c2ecf20Sopenharmony_ci while (*str) 5028c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, (u8) *str++); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return state; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/** 5098c2ecf20Sopenharmony_ci * aa_dfa_next - step one character to the next state in the dfa 5108c2ecf20Sopenharmony_ci * @dfa: the dfa to traverse (NOT NULL) 5118c2ecf20Sopenharmony_ci * @state: the state to start in 5128c2ecf20Sopenharmony_ci * @c: the input character to transition on 5138c2ecf20Sopenharmony_ci * 5148c2ecf20Sopenharmony_ci * aa_dfa_match will step through the dfa by one input character @c 5158c2ecf20Sopenharmony_ci * 5168c2ecf20Sopenharmony_ci * Returns: state reach after input @c 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ciunsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 5198c2ecf20Sopenharmony_ci const char c) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 5228c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 5238c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 5248c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 5278c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 5288c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 5298c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 5308c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, equiv[(u8) c]); 5318c2ecf20Sopenharmony_ci } else 5328c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, (u8) c); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return state; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ciunsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, unsigned int state) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 5408c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 5418c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 5428c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 5438c2ecf20Sopenharmony_ci u32 b = (base)[(state)]; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!(b & MATCH_FLAG_OOB_TRANSITION)) 5468c2ecf20Sopenharmony_ci return DFA_NOMATCH; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* No Equivalence class remapping for outofband transitions */ 5498c2ecf20Sopenharmony_ci match_char(state, def, base, next, check, -1); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return state; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * aa_dfa_match_until - traverse @dfa until accept state or end of input 5568c2ecf20Sopenharmony_ci * @dfa: the dfa to match @str against (NOT NULL) 5578c2ecf20Sopenharmony_ci * @start: the state of the dfa to start matching in 5588c2ecf20Sopenharmony_ci * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 5598c2ecf20Sopenharmony_ci * @retpos: first character in str after match OR end of string 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * aa_dfa_match will match @str against the dfa and return the state it 5628c2ecf20Sopenharmony_ci * finished matching in. The final state can be used to look up the accepting 5638c2ecf20Sopenharmony_ci * label, or as the start state of a continuing match. 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * Returns: final state reached after input is consumed 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ciunsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, 5688c2ecf20Sopenharmony_ci const char *str, const char **retpos) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 5718c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 5728c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 5738c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 5748c2ecf20Sopenharmony_ci u32 *accept = ACCEPT_TABLE(dfa); 5758c2ecf20Sopenharmony_ci unsigned int state = start, pos; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (state == 0) 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 5818c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 5828c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 5838c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 5848c2ecf20Sopenharmony_ci /* default is direct to next state */ 5858c2ecf20Sopenharmony_ci while (*str) { 5868c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + equiv[(u8) *str++]; 5878c2ecf20Sopenharmony_ci if (check[pos] == state) 5888c2ecf20Sopenharmony_ci state = next[pos]; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci state = def[state]; 5918c2ecf20Sopenharmony_ci if (accept[state]) 5928c2ecf20Sopenharmony_ci break; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci } else { 5958c2ecf20Sopenharmony_ci /* default is direct to next state */ 5968c2ecf20Sopenharmony_ci while (*str) { 5978c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + (u8) *str++; 5988c2ecf20Sopenharmony_ci if (check[pos] == state) 5998c2ecf20Sopenharmony_ci state = next[pos]; 6008c2ecf20Sopenharmony_ci else 6018c2ecf20Sopenharmony_ci state = def[state]; 6028c2ecf20Sopenharmony_ci if (accept[state]) 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci *retpos = str; 6088c2ecf20Sopenharmony_ci return state; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed 6138c2ecf20Sopenharmony_ci * @dfa: the dfa to match @str against (NOT NULL) 6148c2ecf20Sopenharmony_ci * @start: the state of the dfa to start matching in 6158c2ecf20Sopenharmony_ci * @str: the string of bytes to match against the dfa (NOT NULL) 6168c2ecf20Sopenharmony_ci * @n: length of the string of bytes to match 6178c2ecf20Sopenharmony_ci * @retpos: first character in str after match OR str + n 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * aa_dfa_match_len will match @str against the dfa and return the state it 6208c2ecf20Sopenharmony_ci * finished matching in. The final state can be used to look up the accepting 6218c2ecf20Sopenharmony_ci * label, or as the start state of a continuing match. 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * This function will happily match again the 0 byte and only finishes 6248c2ecf20Sopenharmony_ci * when @n input is consumed. 6258c2ecf20Sopenharmony_ci * 6268c2ecf20Sopenharmony_ci * Returns: final state reached after input is consumed 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ciunsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, 6298c2ecf20Sopenharmony_ci const char *str, int n, const char **retpos) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 6328c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 6338c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 6348c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 6358c2ecf20Sopenharmony_ci u32 *accept = ACCEPT_TABLE(dfa); 6368c2ecf20Sopenharmony_ci unsigned int state = start, pos; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci *retpos = NULL; 6398c2ecf20Sopenharmony_ci if (state == 0) 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 6438c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 6448c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 6458c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 6468c2ecf20Sopenharmony_ci /* default is direct to next state */ 6478c2ecf20Sopenharmony_ci for (; n; n--) { 6488c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + equiv[(u8) *str++]; 6498c2ecf20Sopenharmony_ci if (check[pos] == state) 6508c2ecf20Sopenharmony_ci state = next[pos]; 6518c2ecf20Sopenharmony_ci else 6528c2ecf20Sopenharmony_ci state = def[state]; 6538c2ecf20Sopenharmony_ci if (accept[state]) 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } else { 6578c2ecf20Sopenharmony_ci /* default is direct to next state */ 6588c2ecf20Sopenharmony_ci for (; n; n--) { 6598c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + (u8) *str++; 6608c2ecf20Sopenharmony_ci if (check[pos] == state) 6618c2ecf20Sopenharmony_ci state = next[pos]; 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci state = def[state]; 6648c2ecf20Sopenharmony_ci if (accept[state]) 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci *retpos = str; 6708c2ecf20Sopenharmony_ci return state; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci#define inc_wb_pos(wb) \ 6748c2ecf20Sopenharmony_cido { \ 6758c2ecf20Sopenharmony_ci wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \ 6768c2ecf20Sopenharmony_ci wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \ 6778c2ecf20Sopenharmony_ci} while (0) 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci/* For DFAs that don't support extended tagging of states */ 6808c2ecf20Sopenharmony_cistatic bool is_loop(struct match_workbuf *wb, unsigned int state, 6818c2ecf20Sopenharmony_ci unsigned int *adjust) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci unsigned int pos = wb->pos; 6848c2ecf20Sopenharmony_ci unsigned int i; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (wb->history[pos] < state) 6878c2ecf20Sopenharmony_ci return false; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci for (i = 0; i <= wb->len; i++) { 6908c2ecf20Sopenharmony_ci if (wb->history[pos] == state) { 6918c2ecf20Sopenharmony_ci *adjust = i; 6928c2ecf20Sopenharmony_ci return true; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci if (pos == 0) 6958c2ecf20Sopenharmony_ci pos = WB_HISTORY_SIZE; 6968c2ecf20Sopenharmony_ci pos--; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci *adjust = i; 7008c2ecf20Sopenharmony_ci return true; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic unsigned int leftmatch_fb(struct aa_dfa *dfa, unsigned int start, 7048c2ecf20Sopenharmony_ci const char *str, struct match_workbuf *wb, 7058c2ecf20Sopenharmony_ci unsigned int *count) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci u16 *def = DEFAULT_TABLE(dfa); 7088c2ecf20Sopenharmony_ci u32 *base = BASE_TABLE(dfa); 7098c2ecf20Sopenharmony_ci u16 *next = NEXT_TABLE(dfa); 7108c2ecf20Sopenharmony_ci u16 *check = CHECK_TABLE(dfa); 7118c2ecf20Sopenharmony_ci unsigned int state = start, pos; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci AA_BUG(!dfa); 7148c2ecf20Sopenharmony_ci AA_BUG(!str); 7158c2ecf20Sopenharmony_ci AA_BUG(!wb); 7168c2ecf20Sopenharmony_ci AA_BUG(!count); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci *count = 0; 7198c2ecf20Sopenharmony_ci if (state == 0) 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* current state is <state>, matching character *str */ 7238c2ecf20Sopenharmony_ci if (dfa->tables[YYTD_ID_EC]) { 7248c2ecf20Sopenharmony_ci /* Equivalence class table defined */ 7258c2ecf20Sopenharmony_ci u8 *equiv = EQUIV_TABLE(dfa); 7268c2ecf20Sopenharmony_ci /* default is direct to next state */ 7278c2ecf20Sopenharmony_ci while (*str) { 7288c2ecf20Sopenharmony_ci unsigned int adjust; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci wb->history[wb->pos] = state; 7318c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + equiv[(u8) *str++]; 7328c2ecf20Sopenharmony_ci if (check[pos] == state) 7338c2ecf20Sopenharmony_ci state = next[pos]; 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci state = def[state]; 7368c2ecf20Sopenharmony_ci if (is_loop(wb, state, &adjust)) { 7378c2ecf20Sopenharmony_ci state = aa_dfa_match(dfa, state, str); 7388c2ecf20Sopenharmony_ci *count -= adjust; 7398c2ecf20Sopenharmony_ci goto out; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci inc_wb_pos(wb); 7428c2ecf20Sopenharmony_ci (*count)++; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci /* default is direct to next state */ 7468c2ecf20Sopenharmony_ci while (*str) { 7478c2ecf20Sopenharmony_ci unsigned int adjust; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci wb->history[wb->pos] = state; 7508c2ecf20Sopenharmony_ci pos = base_idx(base[state]) + (u8) *str++; 7518c2ecf20Sopenharmony_ci if (check[pos] == state) 7528c2ecf20Sopenharmony_ci state = next[pos]; 7538c2ecf20Sopenharmony_ci else 7548c2ecf20Sopenharmony_ci state = def[state]; 7558c2ecf20Sopenharmony_ci if (is_loop(wb, state, &adjust)) { 7568c2ecf20Sopenharmony_ci state = aa_dfa_match(dfa, state, str); 7578c2ecf20Sopenharmony_ci *count -= adjust; 7588c2ecf20Sopenharmony_ci goto out; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci inc_wb_pos(wb); 7618c2ecf20Sopenharmony_ci (*count)++; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciout: 7668c2ecf20Sopenharmony_ci if (!state) 7678c2ecf20Sopenharmony_ci *count = 0; 7688c2ecf20Sopenharmony_ci return state; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci/** 7728c2ecf20Sopenharmony_ci * aa_dfa_leftmatch - traverse @dfa to find state @str stops at 7738c2ecf20Sopenharmony_ci * @dfa: the dfa to match @str against (NOT NULL) 7748c2ecf20Sopenharmony_ci * @start: the state of the dfa to start matching in 7758c2ecf20Sopenharmony_ci * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 7768c2ecf20Sopenharmony_ci * @count: current count of longest left. 7778c2ecf20Sopenharmony_ci * 7788c2ecf20Sopenharmony_ci * aa_dfa_match will match @str against the dfa and return the state it 7798c2ecf20Sopenharmony_ci * finished matching in. The final state can be used to look up the accepting 7808c2ecf20Sopenharmony_ci * label, or as the start state of a continuing match. 7818c2ecf20Sopenharmony_ci * 7828c2ecf20Sopenharmony_ci * Returns: final state reached after input is consumed 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ciunsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start, 7858c2ecf20Sopenharmony_ci const char *str, unsigned int *count) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci DEFINE_MATCH_WB(wb); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* TODO: match for extended state dfas */ 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return leftmatch_fb(dfa, start, str, &wb, count); 7928c2ecf20Sopenharmony_ci} 793