1 /*
2  * Copyright (c) 2015-2016, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /** \file
30  * \brief Declarations for the main NFA Engine API.
31  *
32  * This file provides the internal API for all runtime engines ("NFAs", even if
33  * they're not strictly NFA implementations).
34  */
35 
36 #ifndef NFA_API_H
37 #define NFA_API_H
38 
39 #ifdef __cplusplus
40 extern "C"
41 {
42 #endif
43 
44 #include "callback.h"
45 #include "ue2common.h"
46 
47 struct mq;
48 struct NFA;
49 
50 /**
51  * Indicates if an nfa is a zombie. Note: that there were plans for a more
52  * nuanced view of zombiehood but this never eventuated.
53  */
54 enum nfa_zombie_status {
55     NFA_ZOMBIE_NO, /**< nfa is not a zombie and will respond to top events */
56     NFA_ZOMBIE_ALWAYS_YES /**< nfa is a zombie and will always be a zombie */
57 };
58 
59 /**
60  * Compresses an engine's state.
61  * The expanded state (@ref mq::state, @ref mq::streamState) is reduced purely
62  * to a corresponding compressed stream state (@ref mq::streamState).
63  *
64  * @param nfa engine the state belongs to
65  * @param q queue for the engine. The final compressed stream stream is placed
66  *        in the location indicated by @ref mq::streamState
67  * @param loc the location corresponding to the engine's current state
68  */
69 char nfaQueueCompressState(const struct NFA *nfa, const struct mq *q, s64a loc);
70 
71 /**
72  * Expands an engine's compressed stream state, into its scratch space
73  * representation. This is required before an engine starts operating over its
74  * queue.
75  *
76  * @param nfa engine the state belongs to
77  * @param dest location in scratch for decompressed state
78  * @param src compressed stream state
79  * @param offset the current stream offset.
80  * @param key byte corresponding to the location where the compressed state was
81  *        created.
82  */
83 char nfaExpandState(const struct NFA *nfa, void *dest, const void *src,
84                     u64a offset, u8 key);
85 
86 /**
87  * Gives us a properly initialised dead state suitable for later @ref
88  * nfaQueueExec calls.
89  */
90 char nfaQueueInitState(const struct NFA *nfa, struct mq *q);
91 
92 /**
93  * Initialise the state, applying a TOP appropriate for the offset. If the
94  * NFA becomes inactive, return zero. Otherwise, write out its compressed
95  * representation to `state' and return non-zero.
96  *
97  * @param nfa engine the state belongs to
98  * @param offset offset in the stream (relative to start of stream)
99  * @param state pointer indicating where the state is to be written
100  * @param key byte corresponding to the location where the compressed state is
101  *        to be created.
102  */
103 char nfaInitCompressedState(const struct NFA *nfa, u64a offset, void *state,
104                             u8 key);
105 
106 /**
107  * Process the queued commands on the given NFA.
108  *
109  * @param nfa the NFA to execute
110  * @param q the queued commands. It must start with some variant of start and
111  *        end with some variant of end. The location field of the events must
112  *        be monotonically increasing.
113  * @param end stop processing command queue when we reach this point
114  *
115  * @return non-zero if the nfa is still active, if the nfa is not active the
116  *         state data is undefined
117  *
118  * Note: this function can not process events from the past: the location field
119  * of each event must be >= current offset.
120  */
121 char nfaQueueExec(const struct NFA *nfa, struct mq *q, s64a end);
122 
123 /**
124  * Main execution function that doesn't perform the checks and optimisations of
125  * nfaQueueExec() and just dispatches directly to the nfa implementations. It is
126  * intended to be used by the Tamarama engine.
127  */
128 char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end);
129 
130 /** Return value indicating that the engine is dead. */
131 #define MO_DEAD 0
132 
133 /** Return value indicating that the engine is alive. */
134 #define MO_ALIVE 1
135 
136 /** Return value from @ref nfaQueueExecToMatch indicating that engine progress
137  * stopped as a match state was reached. */
138 #define MO_MATCHES_PENDING 2
139 
140 /**
141  * Process the queued commands on the given nfa up to end or the first match.
142  * This function will only fire the callback in response to an report_current
143  * being set and accepts at the starting offset, in all other situations accepts
144  * will result in the queue pausing with a return value of
145  * @ref MO_MATCHES_PENDING.
146  *
147  * @param nfa the NFA to execute
148  * @param q the queued commands. It must start with some variant of start and
149  *        end with some variant of end. The location field of the events must
150  *        be monotonically increasing. If not all the data was processed during
151  *        the call, the queue is updated to reflect the remaining work.
152  * @param end stop processing command queue when we reach this point
153  *
154  * @return @ref MO_ALIVE if the nfa is still active with no matches pending,
155  *         and @ref MO_MATCHES_PENDING if there are matches pending, 0 if not
156  *         alive
157  *
158  * Note: if it can be determined that the stream can never match, the nfa
159  * may be reported as dead even if not all the data was scanned
160  *
161  * Note: if the nfa is not alive the state data is undefined
162  *
163  * Note: this function can not process events from the past: the location field
164  * of each event must be >= current offset.
165  */
166 char nfaQueueExecToMatch(const struct NFA *nfa, struct mq *q, s64a end);
167 
168 /**
169  * Main execution function that doesn't perform the checks and optimisations of
170  * nfaQueueExecToMatch() and just dispatches directly to the nfa
171  * implementations. It is intended to be used by the Tamarama engine.
172  */
173 char nfaQueueExec2_raw(const struct NFA *nfa, struct mq *q, s64a end);
174 
175 /**
176  * Report matches at the current queue location.
177  *
178  * @param nfa the NFA to execute
179  * @param q the queued commands. It must start with some variant of start and
180  *         end with some variant of end. The location field of the events must
181  *         be monotonically increasing.
182  *
183  * Note: the queue MUST be located at position where @ref nfaQueueExecToMatch
184  *       returned @ref MO_MATCHES_PENDING.
185  *
186  * Note: the return value of this call is undefined, and should be ignored.
187  */
188 char nfaReportCurrentMatches(const struct NFA *nfa, struct mq *q);
189 
190 /**
191  * Returns non-zero if the NFA is in an accept state with the given report ID.
192  */
193 char nfaInAcceptState(const struct NFA *nfa, ReportID report, struct mq *q);
194 
195 /**
196  * Returns non-zero if the NFA is in any accept state regardless of report
197  * ID.
198  */
199 char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q);
200 
201 /**
202  * Process the queued commands on the given NFA up to end or the first match.
203  *
204  * Note: This version is meant for rose prefix/infix NFAs:
205  *  - never uses a callback
206  *  - loading of state at a point in history is not special cased
207  *
208  * @param nfa the NFA to execute
209  * @param q the queued commands. It must start with some variant of start and
210  *        end with some variant of end. The location field of the events must
211  *        be monotonically increasing. If not all the data was processed during
212  *        the call, the queue is updated to reflect the remaining work.
213  * @param report we are interested in. If the given report will be raised at
214  *        the end location, the function returns @ref MO_MATCHES_PENDING. If no
215  *        match information is desired, MO_INVALID_IDX should be passed in.
216  * @return @ref MO_ALIVE if the nfa is still active with no matches pending,
217  *         and @ref MO_MATCHES_PENDING if there are matches pending, 0 if not
218  *         alive
219  *
220  * Note: if it can be determined that the stream can never match, the nfa
221  * may be reported as dead even if not all the data was scanned
222  *
223  * Note: if the NFA is not active the state data is undefined.
224  */
225 char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID report);
226 
227 /**
228  * Runs an NFA in reverse from (buf + buflen) to buf and then from (hbuf + hlen)
229  * to hbuf (main buffer and history buffer).
230  *
231  * Note: provides the match location as the "end" offset when the callback is
232  * called.
233  *
234  * @param nfa engine to run
235  * @param offset base offset of buf
236  * @param buf main buffer
237  * @param buflen length of buf
238  * @param hbuf history buf
239  * @param hlen length of hbuf
240  * @param callback the callback to call for each match raised
241  * @param context context pointer passed to each callback
242  */
243 char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
244                          size_t buflen, const u8 *hbuf, size_t hlen,
245                          NfaCallback callback, void *context);
246 
247 /**
248  * Check whether the given NFA's state indicates that it is in one or more
249  * final (accept at end of data) state. If so, call the callback for each
250  * match.
251  *
252  * @param nfa the NFA to execute
253  * @param state current state associated with this NFA
254  * @param streamState stream version of the state associated with this NFA
255  *        (including br region)
256  * @param offset the offset to return (via the callback) with each match
257  * @param callback the callback to call for each match raised
258  * @param context context pointer passed to each callback
259  *
260  * @return @ref MO_HALT_MATCHING if the user instructed us to halt, otherwise
261  *         @ref MO_CONTINUE_MATCHING.
262  */
263 char nfaCheckFinalState(const struct NFA *nfa, const char *state,
264                         const char *streamState, u64a offset,
265                         NfaCallback callback, void *context);
266 
267 /**
268  * Indicates if an engine is a zombie.
269  *
270  * @param nfa engine to consider
271  * @param q queue corresponding to the engine
272  * @param loc current location in the buffer for an engine
273  */
274 enum nfa_zombie_status nfaGetZombieStatus(const struct NFA *nfa, struct mq *q,
275                                           s64a loc);
276 #ifdef __cplusplus
277 }       /* extern "C" */
278 #endif
279 
280 #endif
281