1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * AppArmor security module
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file contains AppArmor dfa based regular expression matching engine
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 1998-2008 Novell/SUSE
8*4882a593Smuzhiyun * Copyright 2009-2012 Canonical Ltd.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/mm.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/vmalloc.h>
16*4882a593Smuzhiyun #include <linux/err.h>
17*4882a593Smuzhiyun #include <linux/kref.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "include/lib.h"
20*4882a593Smuzhiyun #include "include/match.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define base_idx(X) ((X) & 0xffffff)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static char nulldfa_src[] = {
25*4882a593Smuzhiyun #include "nulldfa.in"
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun struct aa_dfa *nulldfa;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static char stacksplitdfa_src[] = {
30*4882a593Smuzhiyun #include "stacksplitdfa.in"
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun struct aa_dfa *stacksplitdfa;
33*4882a593Smuzhiyun
aa_setup_dfa_engine(void)34*4882a593Smuzhiyun int aa_setup_dfa_engine(void)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun int error;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
39*4882a593Smuzhiyun TO_ACCEPT1_FLAG(YYTD_DATA32) |
40*4882a593Smuzhiyun TO_ACCEPT2_FLAG(YYTD_DATA32));
41*4882a593Smuzhiyun if (IS_ERR(nulldfa)) {
42*4882a593Smuzhiyun error = PTR_ERR(nulldfa);
43*4882a593Smuzhiyun nulldfa = NULL;
44*4882a593Smuzhiyun return error;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
48*4882a593Smuzhiyun sizeof(stacksplitdfa_src),
49*4882a593Smuzhiyun TO_ACCEPT1_FLAG(YYTD_DATA32) |
50*4882a593Smuzhiyun TO_ACCEPT2_FLAG(YYTD_DATA32));
51*4882a593Smuzhiyun if (IS_ERR(stacksplitdfa)) {
52*4882a593Smuzhiyun aa_put_dfa(nulldfa);
53*4882a593Smuzhiyun nulldfa = NULL;
54*4882a593Smuzhiyun error = PTR_ERR(stacksplitdfa);
55*4882a593Smuzhiyun stacksplitdfa = NULL;
56*4882a593Smuzhiyun return error;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun return 0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
aa_teardown_dfa_engine(void)62*4882a593Smuzhiyun void aa_teardown_dfa_engine(void)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun aa_put_dfa(stacksplitdfa);
65*4882a593Smuzhiyun aa_put_dfa(nulldfa);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /**
69*4882a593Smuzhiyun * unpack_table - unpack a dfa table (one of accept, default, base, next check)
70*4882a593Smuzhiyun * @blob: data to unpack (NOT NULL)
71*4882a593Smuzhiyun * @bsize: size of blob
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun * Returns: pointer to table else NULL on failure
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun * NOTE: must be freed by kvfree (not kfree)
76*4882a593Smuzhiyun */
unpack_table(char * blob,size_t bsize)77*4882a593Smuzhiyun static struct table_header *unpack_table(char *blob, size_t bsize)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun struct table_header *table = NULL;
80*4882a593Smuzhiyun struct table_header th;
81*4882a593Smuzhiyun size_t tsize;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (bsize < sizeof(struct table_header))
84*4882a593Smuzhiyun goto out;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* loaded td_id's start at 1, subtract 1 now to avoid doing
87*4882a593Smuzhiyun * it every time we use td_id as an index
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1;
90*4882a593Smuzhiyun if (th.td_id > YYTD_ID_MAX)
91*4882a593Smuzhiyun goto out;
92*4882a593Smuzhiyun th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2));
93*4882a593Smuzhiyun th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8));
94*4882a593Smuzhiyun blob += sizeof(struct table_header);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
97*4882a593Smuzhiyun th.td_flags == YYTD_DATA8))
98*4882a593Smuzhiyun goto out;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* if we have a table it must have some entries */
101*4882a593Smuzhiyun if (th.td_lolen == 0)
102*4882a593Smuzhiyun goto out;
103*4882a593Smuzhiyun tsize = table_size(th.td_lolen, th.td_flags);
104*4882a593Smuzhiyun if (bsize < tsize)
105*4882a593Smuzhiyun goto out;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun table = kvzalloc(tsize, GFP_KERNEL);
108*4882a593Smuzhiyun if (table) {
109*4882a593Smuzhiyun table->td_id = th.td_id;
110*4882a593Smuzhiyun table->td_flags = th.td_flags;
111*4882a593Smuzhiyun table->td_lolen = th.td_lolen;
112*4882a593Smuzhiyun if (th.td_flags == YYTD_DATA8)
113*4882a593Smuzhiyun UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
114*4882a593Smuzhiyun u8, u8, byte_to_byte);
115*4882a593Smuzhiyun else if (th.td_flags == YYTD_DATA16)
116*4882a593Smuzhiyun UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
117*4882a593Smuzhiyun u16, __be16, be16_to_cpu);
118*4882a593Smuzhiyun else if (th.td_flags == YYTD_DATA32)
119*4882a593Smuzhiyun UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
120*4882a593Smuzhiyun u32, __be32, be32_to_cpu);
121*4882a593Smuzhiyun else
122*4882a593Smuzhiyun goto fail;
123*4882a593Smuzhiyun /* if table was vmalloced make sure the page tables are synced
124*4882a593Smuzhiyun * before it is used, as it goes live to all cpus.
125*4882a593Smuzhiyun */
126*4882a593Smuzhiyun if (is_vmalloc_addr(table))
127*4882a593Smuzhiyun vm_unmap_aliases();
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun out:
131*4882a593Smuzhiyun return table;
132*4882a593Smuzhiyun fail:
133*4882a593Smuzhiyun kvfree(table);
134*4882a593Smuzhiyun return NULL;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /**
138*4882a593Smuzhiyun * verify_table_headers - verify that the tables headers are as expected
139*4882a593Smuzhiyun * @tables - array of dfa tables to check (NOT NULL)
140*4882a593Smuzhiyun * @flags: flags controlling what type of accept table are acceptable
141*4882a593Smuzhiyun *
142*4882a593Smuzhiyun * Assumes dfa has gone through the first pass verification done by unpacking
143*4882a593Smuzhiyun * NOTE: this does not valid accept table values
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * Returns: %0 else error code on failure to verify
146*4882a593Smuzhiyun */
verify_table_headers(struct table_header ** tables,int flags)147*4882a593Smuzhiyun static int verify_table_headers(struct table_header **tables, int flags)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun size_t state_count, trans_count;
150*4882a593Smuzhiyun int error = -EPROTO;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* check that required tables exist */
153*4882a593Smuzhiyun if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] &&
154*4882a593Smuzhiyun tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK]))
155*4882a593Smuzhiyun goto out;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* accept.size == default.size == base.size */
158*4882a593Smuzhiyun state_count = tables[YYTD_ID_BASE]->td_lolen;
159*4882a593Smuzhiyun if (ACCEPT1_FLAGS(flags)) {
160*4882a593Smuzhiyun if (!tables[YYTD_ID_ACCEPT])
161*4882a593Smuzhiyun goto out;
162*4882a593Smuzhiyun if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen)
163*4882a593Smuzhiyun goto out;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun if (ACCEPT2_FLAGS(flags)) {
166*4882a593Smuzhiyun if (!tables[YYTD_ID_ACCEPT2])
167*4882a593Smuzhiyun goto out;
168*4882a593Smuzhiyun if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen)
169*4882a593Smuzhiyun goto out;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun if (state_count != tables[YYTD_ID_DEF]->td_lolen)
172*4882a593Smuzhiyun goto out;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* next.size == chk.size */
175*4882a593Smuzhiyun trans_count = tables[YYTD_ID_NXT]->td_lolen;
176*4882a593Smuzhiyun if (trans_count != tables[YYTD_ID_CHK]->td_lolen)
177*4882a593Smuzhiyun goto out;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* if equivalence classes then its table size must be 256 */
180*4882a593Smuzhiyun if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256)
181*4882a593Smuzhiyun goto out;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun error = 0;
184*4882a593Smuzhiyun out:
185*4882a593Smuzhiyun return error;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /**
189*4882a593Smuzhiyun * verify_dfa - verify that transitions and states in the tables are in bounds.
190*4882a593Smuzhiyun * @dfa: dfa to test (NOT NULL)
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun * Assumes dfa has gone through the first pass verification done by unpacking
193*4882a593Smuzhiyun * NOTE: this does not valid accept table values
194*4882a593Smuzhiyun *
195*4882a593Smuzhiyun * Returns: %0 else error code on failure to verify
196*4882a593Smuzhiyun */
verify_dfa(struct aa_dfa * dfa)197*4882a593Smuzhiyun static int verify_dfa(struct aa_dfa *dfa)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun size_t i, state_count, trans_count;
200*4882a593Smuzhiyun int error = -EPROTO;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
203*4882a593Smuzhiyun trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
204*4882a593Smuzhiyun if (state_count == 0)
205*4882a593Smuzhiyun goto out;
206*4882a593Smuzhiyun for (i = 0; i < state_count; i++) {
207*4882a593Smuzhiyun if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
208*4882a593Smuzhiyun (DEFAULT_TABLE(dfa)[i] >= state_count))
209*4882a593Smuzhiyun goto out;
210*4882a593Smuzhiyun if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) {
211*4882a593Smuzhiyun pr_err("AppArmor DFA state with invalid match flags");
212*4882a593Smuzhiyun goto out;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE)) {
215*4882a593Smuzhiyun if (!(dfa->flags & YYTH_FLAG_DIFF_ENCODE)) {
216*4882a593Smuzhiyun pr_err("AppArmor DFA diff encoded transition state without header flag");
217*4882a593Smuzhiyun goto out;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_OOB_TRANSITION)) {
221*4882a593Smuzhiyun if (base_idx(BASE_TABLE(dfa)[i]) < dfa->max_oob) {
222*4882a593Smuzhiyun pr_err("AppArmor DFA out of bad transition out of range");
223*4882a593Smuzhiyun goto out;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun if (!(dfa->flags & YYTH_FLAG_OOB_TRANS)) {
226*4882a593Smuzhiyun pr_err("AppArmor DFA out of bad transition state without header flag");
227*4882a593Smuzhiyun goto out;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
231*4882a593Smuzhiyun pr_err("AppArmor DFA next/check upper bounds error\n");
232*4882a593Smuzhiyun goto out;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun for (i = 0; i < trans_count; i++) {
237*4882a593Smuzhiyun if (NEXT_TABLE(dfa)[i] >= state_count)
238*4882a593Smuzhiyun goto out;
239*4882a593Smuzhiyun if (CHECK_TABLE(dfa)[i] >= state_count)
240*4882a593Smuzhiyun goto out;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* Now that all the other tables are verified, verify diffencoding */
244*4882a593Smuzhiyun for (i = 0; i < state_count; i++) {
245*4882a593Smuzhiyun size_t j, k;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun for (j = i;
248*4882a593Smuzhiyun (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
249*4882a593Smuzhiyun !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
250*4882a593Smuzhiyun j = k) {
251*4882a593Smuzhiyun k = DEFAULT_TABLE(dfa)[j];
252*4882a593Smuzhiyun if (j == k)
253*4882a593Smuzhiyun goto out;
254*4882a593Smuzhiyun if (k < j)
255*4882a593Smuzhiyun break; /* already verified */
256*4882a593Smuzhiyun BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun error = 0;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun out:
262*4882a593Smuzhiyun return error;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /**
266*4882a593Smuzhiyun * dfa_free - free a dfa allocated by aa_dfa_unpack
267*4882a593Smuzhiyun * @dfa: the dfa to free (MAYBE NULL)
268*4882a593Smuzhiyun *
269*4882a593Smuzhiyun * Requires: reference count to dfa == 0
270*4882a593Smuzhiyun */
dfa_free(struct aa_dfa * dfa)271*4882a593Smuzhiyun static void dfa_free(struct aa_dfa *dfa)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun if (dfa) {
274*4882a593Smuzhiyun int i;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
277*4882a593Smuzhiyun kvfree(dfa->tables[i]);
278*4882a593Smuzhiyun dfa->tables[i] = NULL;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun kfree(dfa);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /**
285*4882a593Smuzhiyun * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
286*4882a593Smuzhiyun * @kr: kref callback for freeing of a dfa (NOT NULL)
287*4882a593Smuzhiyun */
aa_dfa_free_kref(struct kref * kref)288*4882a593Smuzhiyun void aa_dfa_free_kref(struct kref *kref)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count);
291*4882a593Smuzhiyun dfa_free(dfa);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /**
295*4882a593Smuzhiyun * aa_dfa_unpack - unpack the binary tables of a serialized dfa
296*4882a593Smuzhiyun * @blob: aligned serialized stream of data to unpack (NOT NULL)
297*4882a593Smuzhiyun * @size: size of data to unpack
298*4882a593Smuzhiyun * @flags: flags controlling what type of accept tables are acceptable
299*4882a593Smuzhiyun *
300*4882a593Smuzhiyun * Unpack a dfa that has been serialized. To find information on the dfa
301*4882a593Smuzhiyun * format look in Documentation/admin-guide/LSM/apparmor.rst
302*4882a593Smuzhiyun * Assumes the dfa @blob stream has been aligned on a 8 byte boundary
303*4882a593Smuzhiyun *
304*4882a593Smuzhiyun * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
305*4882a593Smuzhiyun */
aa_dfa_unpack(void * blob,size_t size,int flags)306*4882a593Smuzhiyun struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun int hsize;
309*4882a593Smuzhiyun int error = -ENOMEM;
310*4882a593Smuzhiyun char *data = blob;
311*4882a593Smuzhiyun struct table_header *table = NULL;
312*4882a593Smuzhiyun struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
313*4882a593Smuzhiyun if (!dfa)
314*4882a593Smuzhiyun goto fail;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun kref_init(&dfa->count);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun error = -EPROTO;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* get dfa table set header */
321*4882a593Smuzhiyun if (size < sizeof(struct table_set_header))
322*4882a593Smuzhiyun goto fail;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (ntohl(*(__be32 *) data) != YYTH_MAGIC)
325*4882a593Smuzhiyun goto fail;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun hsize = ntohl(*(__be32 *) (data + 4));
328*4882a593Smuzhiyun if (size < hsize)
329*4882a593Smuzhiyun goto fail;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun dfa->flags = ntohs(*(__be16 *) (data + 12));
332*4882a593Smuzhiyun if (dfa->flags & ~(YYTH_FLAGS))
333*4882a593Smuzhiyun goto fail;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /*
336*4882a593Smuzhiyun * TODO: needed for dfa to support more than 1 oob
337*4882a593Smuzhiyun * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) {
338*4882a593Smuzhiyun * if (hsize < 16 + 4)
339*4882a593Smuzhiyun * goto fail;
340*4882a593Smuzhiyun * dfa->max_oob = ntol(*(__be32 *) (data + 16));
341*4882a593Smuzhiyun * if (dfa->max <= MAX_OOB_SUPPORTED) {
342*4882a593Smuzhiyun * pr_err("AppArmor DFA OOB greater than supported\n");
343*4882a593Smuzhiyun * goto fail;
344*4882a593Smuzhiyun * }
345*4882a593Smuzhiyun * }
346*4882a593Smuzhiyun */
347*4882a593Smuzhiyun dfa->max_oob = 1;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun data += hsize;
350*4882a593Smuzhiyun size -= hsize;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun while (size > 0) {
353*4882a593Smuzhiyun table = unpack_table(data, size);
354*4882a593Smuzhiyun if (!table)
355*4882a593Smuzhiyun goto fail;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun switch (table->td_id) {
358*4882a593Smuzhiyun case YYTD_ID_ACCEPT:
359*4882a593Smuzhiyun if (!(table->td_flags & ACCEPT1_FLAGS(flags)))
360*4882a593Smuzhiyun goto fail;
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun case YYTD_ID_ACCEPT2:
363*4882a593Smuzhiyun if (!(table->td_flags & ACCEPT2_FLAGS(flags)))
364*4882a593Smuzhiyun goto fail;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun case YYTD_ID_BASE:
367*4882a593Smuzhiyun if (table->td_flags != YYTD_DATA32)
368*4882a593Smuzhiyun goto fail;
369*4882a593Smuzhiyun break;
370*4882a593Smuzhiyun case YYTD_ID_DEF:
371*4882a593Smuzhiyun case YYTD_ID_NXT:
372*4882a593Smuzhiyun case YYTD_ID_CHK:
373*4882a593Smuzhiyun if (table->td_flags != YYTD_DATA16)
374*4882a593Smuzhiyun goto fail;
375*4882a593Smuzhiyun break;
376*4882a593Smuzhiyun case YYTD_ID_EC:
377*4882a593Smuzhiyun if (table->td_flags != YYTD_DATA8)
378*4882a593Smuzhiyun goto fail;
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun default:
381*4882a593Smuzhiyun goto fail;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun /* check for duplicate table entry */
384*4882a593Smuzhiyun if (dfa->tables[table->td_id])
385*4882a593Smuzhiyun goto fail;
386*4882a593Smuzhiyun dfa->tables[table->td_id] = table;
387*4882a593Smuzhiyun data += table_size(table->td_lolen, table->td_flags);
388*4882a593Smuzhiyun size -= table_size(table->td_lolen, table->td_flags);
389*4882a593Smuzhiyun table = NULL;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun error = verify_table_headers(dfa->tables, flags);
392*4882a593Smuzhiyun if (error)
393*4882a593Smuzhiyun goto fail;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (flags & DFA_FLAG_VERIFY_STATES) {
396*4882a593Smuzhiyun error = verify_dfa(dfa);
397*4882a593Smuzhiyun if (error)
398*4882a593Smuzhiyun goto fail;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun return dfa;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun fail:
404*4882a593Smuzhiyun kvfree(table);
405*4882a593Smuzhiyun dfa_free(dfa);
406*4882a593Smuzhiyun return ERR_PTR(error);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun #define match_char(state, def, base, next, check, C) \
410*4882a593Smuzhiyun do { \
411*4882a593Smuzhiyun u32 b = (base)[(state)]; \
412*4882a593Smuzhiyun unsigned int pos = base_idx(b) + (C); \
413*4882a593Smuzhiyun if ((check)[pos] != (state)) { \
414*4882a593Smuzhiyun (state) = (def)[(state)]; \
415*4882a593Smuzhiyun if (b & MATCH_FLAG_DIFF_ENCODE) \
416*4882a593Smuzhiyun continue; \
417*4882a593Smuzhiyun break; \
418*4882a593Smuzhiyun } \
419*4882a593Smuzhiyun (state) = (next)[pos]; \
420*4882a593Smuzhiyun break; \
421*4882a593Smuzhiyun } while (1)
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /**
424*4882a593Smuzhiyun * aa_dfa_match_len - traverse @dfa to find state @str stops at
425*4882a593Smuzhiyun * @dfa: the dfa to match @str against (NOT NULL)
426*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
427*4882a593Smuzhiyun * @str: the string of bytes to match against the dfa (NOT NULL)
428*4882a593Smuzhiyun * @len: length of the string of bytes to match
429*4882a593Smuzhiyun *
430*4882a593Smuzhiyun * aa_dfa_match_len will match @str against the dfa and return the state it
431*4882a593Smuzhiyun * finished matching in. The final state can be used to look up the accepting
432*4882a593Smuzhiyun * label, or as the start state of a continuing match.
433*4882a593Smuzhiyun *
434*4882a593Smuzhiyun * This function will happily match again the 0 byte and only finishes
435*4882a593Smuzhiyun * when @len input is consumed.
436*4882a593Smuzhiyun *
437*4882a593Smuzhiyun * Returns: final state reached after input is consumed
438*4882a593Smuzhiyun */
aa_dfa_match_len(struct aa_dfa * dfa,unsigned int start,const char * str,int len)439*4882a593Smuzhiyun unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
440*4882a593Smuzhiyun const char *str, int len)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
443*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
444*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
445*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
446*4882a593Smuzhiyun unsigned int state = start;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (state == 0)
449*4882a593Smuzhiyun return 0;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* current state is <state>, matching character *str */
452*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
453*4882a593Smuzhiyun /* Equivalence class table defined */
454*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
455*4882a593Smuzhiyun for (; len; len--)
456*4882a593Smuzhiyun match_char(state, def, base, next, check,
457*4882a593Smuzhiyun equiv[(u8) *str++]);
458*4882a593Smuzhiyun } else {
459*4882a593Smuzhiyun /* default is direct to next state */
460*4882a593Smuzhiyun for (; len; len--)
461*4882a593Smuzhiyun match_char(state, def, base, next, check, (u8) *str++);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun return state;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /**
468*4882a593Smuzhiyun * aa_dfa_match - traverse @dfa to find state @str stops at
469*4882a593Smuzhiyun * @dfa: the dfa to match @str against (NOT NULL)
470*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
471*4882a593Smuzhiyun * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
472*4882a593Smuzhiyun *
473*4882a593Smuzhiyun * aa_dfa_match will match @str against the dfa and return the state it
474*4882a593Smuzhiyun * finished matching in. The final state can be used to look up the accepting
475*4882a593Smuzhiyun * label, or as the start state of a continuing match.
476*4882a593Smuzhiyun *
477*4882a593Smuzhiyun * Returns: final state reached after input is consumed
478*4882a593Smuzhiyun */
aa_dfa_match(struct aa_dfa * dfa,unsigned int start,const char * str)479*4882a593Smuzhiyun unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
480*4882a593Smuzhiyun const char *str)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
483*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
484*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
485*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
486*4882a593Smuzhiyun unsigned int state = start;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun if (state == 0)
489*4882a593Smuzhiyun return 0;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /* current state is <state>, matching character *str */
492*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
493*4882a593Smuzhiyun /* Equivalence class table defined */
494*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
495*4882a593Smuzhiyun /* default is direct to next state */
496*4882a593Smuzhiyun while (*str)
497*4882a593Smuzhiyun match_char(state, def, base, next, check,
498*4882a593Smuzhiyun equiv[(u8) *str++]);
499*4882a593Smuzhiyun } else {
500*4882a593Smuzhiyun /* default is direct to next state */
501*4882a593Smuzhiyun while (*str)
502*4882a593Smuzhiyun match_char(state, def, base, next, check, (u8) *str++);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun return state;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /**
509*4882a593Smuzhiyun * aa_dfa_next - step one character to the next state in the dfa
510*4882a593Smuzhiyun * @dfa: the dfa to traverse (NOT NULL)
511*4882a593Smuzhiyun * @state: the state to start in
512*4882a593Smuzhiyun * @c: the input character to transition on
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun * aa_dfa_match will step through the dfa by one input character @c
515*4882a593Smuzhiyun *
516*4882a593Smuzhiyun * Returns: state reach after input @c
517*4882a593Smuzhiyun */
aa_dfa_next(struct aa_dfa * dfa,unsigned int state,const char c)518*4882a593Smuzhiyun unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
519*4882a593Smuzhiyun const char c)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
522*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
523*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
524*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* current state is <state>, matching character *str */
527*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
528*4882a593Smuzhiyun /* Equivalence class table defined */
529*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
530*4882a593Smuzhiyun match_char(state, def, base, next, check, equiv[(u8) c]);
531*4882a593Smuzhiyun } else
532*4882a593Smuzhiyun match_char(state, def, base, next, check, (u8) c);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun return state;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
aa_dfa_outofband_transition(struct aa_dfa * dfa,unsigned int state)537*4882a593Smuzhiyun unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, unsigned int state)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
540*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
541*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
542*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
543*4882a593Smuzhiyun u32 b = (base)[(state)];
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun if (!(b & MATCH_FLAG_OOB_TRANSITION))
546*4882a593Smuzhiyun return DFA_NOMATCH;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* No Equivalence class remapping for outofband transitions */
549*4882a593Smuzhiyun match_char(state, def, base, next, check, -1);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return state;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /**
555*4882a593Smuzhiyun * aa_dfa_match_until - traverse @dfa until accept state or end of input
556*4882a593Smuzhiyun * @dfa: the dfa to match @str against (NOT NULL)
557*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
558*4882a593Smuzhiyun * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
559*4882a593Smuzhiyun * @retpos: first character in str after match OR end of string
560*4882a593Smuzhiyun *
561*4882a593Smuzhiyun * aa_dfa_match will match @str against the dfa and return the state it
562*4882a593Smuzhiyun * finished matching in. The final state can be used to look up the accepting
563*4882a593Smuzhiyun * label, or as the start state of a continuing match.
564*4882a593Smuzhiyun *
565*4882a593Smuzhiyun * Returns: final state reached after input is consumed
566*4882a593Smuzhiyun */
aa_dfa_match_until(struct aa_dfa * dfa,unsigned int start,const char * str,const char ** retpos)567*4882a593Smuzhiyun unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start,
568*4882a593Smuzhiyun const char *str, const char **retpos)
569*4882a593Smuzhiyun {
570*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
571*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
572*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
573*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
574*4882a593Smuzhiyun u32 *accept = ACCEPT_TABLE(dfa);
575*4882a593Smuzhiyun unsigned int state = start, pos;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (state == 0)
578*4882a593Smuzhiyun return 0;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /* current state is <state>, matching character *str */
581*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
582*4882a593Smuzhiyun /* Equivalence class table defined */
583*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
584*4882a593Smuzhiyun /* default is direct to next state */
585*4882a593Smuzhiyun while (*str) {
586*4882a593Smuzhiyun pos = base_idx(base[state]) + equiv[(u8) *str++];
587*4882a593Smuzhiyun if (check[pos] == state)
588*4882a593Smuzhiyun state = next[pos];
589*4882a593Smuzhiyun else
590*4882a593Smuzhiyun state = def[state];
591*4882a593Smuzhiyun if (accept[state])
592*4882a593Smuzhiyun break;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun } else {
595*4882a593Smuzhiyun /* default is direct to next state */
596*4882a593Smuzhiyun while (*str) {
597*4882a593Smuzhiyun pos = base_idx(base[state]) + (u8) *str++;
598*4882a593Smuzhiyun if (check[pos] == state)
599*4882a593Smuzhiyun state = next[pos];
600*4882a593Smuzhiyun else
601*4882a593Smuzhiyun state = def[state];
602*4882a593Smuzhiyun if (accept[state])
603*4882a593Smuzhiyun break;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun *retpos = str;
608*4882a593Smuzhiyun return state;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun /**
612*4882a593Smuzhiyun * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed
613*4882a593Smuzhiyun * @dfa: the dfa to match @str against (NOT NULL)
614*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
615*4882a593Smuzhiyun * @str: the string of bytes to match against the dfa (NOT NULL)
616*4882a593Smuzhiyun * @n: length of the string of bytes to match
617*4882a593Smuzhiyun * @retpos: first character in str after match OR str + n
618*4882a593Smuzhiyun *
619*4882a593Smuzhiyun * aa_dfa_match_len will match @str against the dfa and return the state it
620*4882a593Smuzhiyun * finished matching in. The final state can be used to look up the accepting
621*4882a593Smuzhiyun * label, or as the start state of a continuing match.
622*4882a593Smuzhiyun *
623*4882a593Smuzhiyun * This function will happily match again the 0 byte and only finishes
624*4882a593Smuzhiyun * when @n input is consumed.
625*4882a593Smuzhiyun *
626*4882a593Smuzhiyun * Returns: final state reached after input is consumed
627*4882a593Smuzhiyun */
aa_dfa_matchn_until(struct aa_dfa * dfa,unsigned int start,const char * str,int n,const char ** retpos)628*4882a593Smuzhiyun unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
629*4882a593Smuzhiyun const char *str, int n, const char **retpos)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
632*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
633*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
634*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
635*4882a593Smuzhiyun u32 *accept = ACCEPT_TABLE(dfa);
636*4882a593Smuzhiyun unsigned int state = start, pos;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun *retpos = NULL;
639*4882a593Smuzhiyun if (state == 0)
640*4882a593Smuzhiyun return 0;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun /* current state is <state>, matching character *str */
643*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
644*4882a593Smuzhiyun /* Equivalence class table defined */
645*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
646*4882a593Smuzhiyun /* default is direct to next state */
647*4882a593Smuzhiyun for (; n; n--) {
648*4882a593Smuzhiyun pos = base_idx(base[state]) + equiv[(u8) *str++];
649*4882a593Smuzhiyun if (check[pos] == state)
650*4882a593Smuzhiyun state = next[pos];
651*4882a593Smuzhiyun else
652*4882a593Smuzhiyun state = def[state];
653*4882a593Smuzhiyun if (accept[state])
654*4882a593Smuzhiyun break;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun } else {
657*4882a593Smuzhiyun /* default is direct to next state */
658*4882a593Smuzhiyun for (; n; n--) {
659*4882a593Smuzhiyun pos = base_idx(base[state]) + (u8) *str++;
660*4882a593Smuzhiyun if (check[pos] == state)
661*4882a593Smuzhiyun state = next[pos];
662*4882a593Smuzhiyun else
663*4882a593Smuzhiyun state = def[state];
664*4882a593Smuzhiyun if (accept[state])
665*4882a593Smuzhiyun break;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun *retpos = str;
670*4882a593Smuzhiyun return state;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun #define inc_wb_pos(wb) \
674*4882a593Smuzhiyun do { \
675*4882a593Smuzhiyun wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \
676*4882a593Smuzhiyun wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \
677*4882a593Smuzhiyun } while (0)
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun /* For DFAs that don't support extended tagging of states */
is_loop(struct match_workbuf * wb,unsigned int state,unsigned int * adjust)680*4882a593Smuzhiyun static bool is_loop(struct match_workbuf *wb, unsigned int state,
681*4882a593Smuzhiyun unsigned int *adjust)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun unsigned int pos = wb->pos;
684*4882a593Smuzhiyun unsigned int i;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun if (wb->history[pos] < state)
687*4882a593Smuzhiyun return false;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun for (i = 0; i <= wb->len; i++) {
690*4882a593Smuzhiyun if (wb->history[pos] == state) {
691*4882a593Smuzhiyun *adjust = i;
692*4882a593Smuzhiyun return true;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun if (pos == 0)
695*4882a593Smuzhiyun pos = WB_HISTORY_SIZE;
696*4882a593Smuzhiyun pos--;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun *adjust = i;
700*4882a593Smuzhiyun return true;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
leftmatch_fb(struct aa_dfa * dfa,unsigned int start,const char * str,struct match_workbuf * wb,unsigned int * count)703*4882a593Smuzhiyun static unsigned int leftmatch_fb(struct aa_dfa *dfa, unsigned int start,
704*4882a593Smuzhiyun const char *str, struct match_workbuf *wb,
705*4882a593Smuzhiyun unsigned int *count)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun u16 *def = DEFAULT_TABLE(dfa);
708*4882a593Smuzhiyun u32 *base = BASE_TABLE(dfa);
709*4882a593Smuzhiyun u16 *next = NEXT_TABLE(dfa);
710*4882a593Smuzhiyun u16 *check = CHECK_TABLE(dfa);
711*4882a593Smuzhiyun unsigned int state = start, pos;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun AA_BUG(!dfa);
714*4882a593Smuzhiyun AA_BUG(!str);
715*4882a593Smuzhiyun AA_BUG(!wb);
716*4882a593Smuzhiyun AA_BUG(!count);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun *count = 0;
719*4882a593Smuzhiyun if (state == 0)
720*4882a593Smuzhiyun return 0;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun /* current state is <state>, matching character *str */
723*4882a593Smuzhiyun if (dfa->tables[YYTD_ID_EC]) {
724*4882a593Smuzhiyun /* Equivalence class table defined */
725*4882a593Smuzhiyun u8 *equiv = EQUIV_TABLE(dfa);
726*4882a593Smuzhiyun /* default is direct to next state */
727*4882a593Smuzhiyun while (*str) {
728*4882a593Smuzhiyun unsigned int adjust;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun wb->history[wb->pos] = state;
731*4882a593Smuzhiyun pos = base_idx(base[state]) + equiv[(u8) *str++];
732*4882a593Smuzhiyun if (check[pos] == state)
733*4882a593Smuzhiyun state = next[pos];
734*4882a593Smuzhiyun else
735*4882a593Smuzhiyun state = def[state];
736*4882a593Smuzhiyun if (is_loop(wb, state, &adjust)) {
737*4882a593Smuzhiyun state = aa_dfa_match(dfa, state, str);
738*4882a593Smuzhiyun *count -= adjust;
739*4882a593Smuzhiyun goto out;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun inc_wb_pos(wb);
742*4882a593Smuzhiyun (*count)++;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun } else {
745*4882a593Smuzhiyun /* default is direct to next state */
746*4882a593Smuzhiyun while (*str) {
747*4882a593Smuzhiyun unsigned int adjust;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun wb->history[wb->pos] = state;
750*4882a593Smuzhiyun pos = base_idx(base[state]) + (u8) *str++;
751*4882a593Smuzhiyun if (check[pos] == state)
752*4882a593Smuzhiyun state = next[pos];
753*4882a593Smuzhiyun else
754*4882a593Smuzhiyun state = def[state];
755*4882a593Smuzhiyun if (is_loop(wb, state, &adjust)) {
756*4882a593Smuzhiyun state = aa_dfa_match(dfa, state, str);
757*4882a593Smuzhiyun *count -= adjust;
758*4882a593Smuzhiyun goto out;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun inc_wb_pos(wb);
761*4882a593Smuzhiyun (*count)++;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun out:
766*4882a593Smuzhiyun if (!state)
767*4882a593Smuzhiyun *count = 0;
768*4882a593Smuzhiyun return state;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun /**
772*4882a593Smuzhiyun * aa_dfa_leftmatch - traverse @dfa to find state @str stops at
773*4882a593Smuzhiyun * @dfa: the dfa to match @str against (NOT NULL)
774*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
775*4882a593Smuzhiyun * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
776*4882a593Smuzhiyun * @count: current count of longest left.
777*4882a593Smuzhiyun *
778*4882a593Smuzhiyun * aa_dfa_match will match @str against the dfa and return the state it
779*4882a593Smuzhiyun * finished matching in. The final state can be used to look up the accepting
780*4882a593Smuzhiyun * label, or as the start state of a continuing match.
781*4882a593Smuzhiyun *
782*4882a593Smuzhiyun * Returns: final state reached after input is consumed
783*4882a593Smuzhiyun */
aa_dfa_leftmatch(struct aa_dfa * dfa,unsigned int start,const char * str,unsigned int * count)784*4882a593Smuzhiyun unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start,
785*4882a593Smuzhiyun const char *str, unsigned int *count)
786*4882a593Smuzhiyun {
787*4882a593Smuzhiyun DEFINE_MATCH_WB(wb);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun /* TODO: match for extended state dfas */
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun return leftmatch_fb(dfa, start, str, &wb, count);
792*4882a593Smuzhiyun }
793