/src/suricata7/src/detect-engine-content-inspection.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2017 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Anoop Saldanha <anoopsaldanha@gmail.com> |
22 | | * |
23 | | * Performs content inspection on any buffer supplied. |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "suricata.h" |
28 | | |
29 | | #include "decode.h" |
30 | | |
31 | | #include "detect.h" |
32 | | #include "detect-engine.h" |
33 | | #include "detect-parse.h" |
34 | | #include "detect-content.h" |
35 | | #include "detect-pcre.h" |
36 | | #include "detect-isdataat.h" |
37 | | #include "detect-bytetest.h" |
38 | | #include "detect-bytemath.h" |
39 | | #include "detect-bytejump.h" |
40 | | #include "detect-byte-extract.h" |
41 | | #include "detect-replace.h" |
42 | | #include "detect-engine-content-inspection.h" |
43 | | #include "detect-uricontent.h" |
44 | | #include "detect-urilen.h" |
45 | | #include "detect-engine-uint.h" |
46 | | #include "detect-bsize.h" |
47 | | #include "detect-lua.h" |
48 | | #include "detect-base64-decode.h" |
49 | | #include "detect-base64-data.h" |
50 | | #include "detect-dataset.h" |
51 | | #include "detect-datarep.h" |
52 | | |
53 | | #include "util-spm.h" |
54 | | #include "util-debug.h" |
55 | | #include "util-print.h" |
56 | | #include "util-validate.h" |
57 | | |
58 | | #include "util-unittest.h" |
59 | | #include "util-unittest-helper.h" |
60 | | #include "util-profiling.h" |
61 | | |
62 | | #include "rust.h" |
63 | | |
64 | | #ifdef HAVE_LUA |
65 | | #include "util-lua.h" |
66 | | #endif |
67 | | |
68 | | /** |
69 | | * \brief Run the actual payload match functions |
70 | | * |
71 | | * The following keywords are inspected: |
72 | | * - content, including all the http and dce modified contents |
73 | | * - isdataat |
74 | | * - pcre |
75 | | * - bytejump |
76 | | * - bytetest |
77 | | * - byte_extract |
78 | | * - urilen |
79 | | * - |
80 | | * |
81 | | * All keywords are evaluated against the buffer with buffer_len. |
82 | | * |
83 | | * For accounting the last match in relative matching the |
84 | | * det_ctx->buffer_offset int is used. |
85 | | * |
86 | | * \param de_ctx Detection engine context |
87 | | * \param det_ctx Detection engine thread context |
88 | | * \param s Signature to inspect |
89 | | * \param sm SigMatch to inspect |
90 | | * \param p Packet. Can be NULL. |
91 | | * \param f Flow (for pcre flowvar storage) |
92 | | * \param buffer Ptr to the buffer to inspect |
93 | | * \param buffer_len Length of the payload |
94 | | * \param stream_start_offset Indicates the start of the current buffer in |
95 | | * the whole buffer stream inspected. This |
96 | | * applies if the current buffer is inspected |
97 | | * in chunks. |
98 | | * \param inspection_mode Refers to the engine inspection mode we are currently |
99 | | * inspecting. Can be payload, stream, one of the http |
100 | | * buffer inspection modes or dce inspection mode. |
101 | | * \param flags DETECT_CI_FLAG_* |
102 | | * |
103 | | * \retval 0 no match |
104 | | * \retval 1 match |
105 | | */ |
106 | | uint8_t DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, |
107 | | const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const uint8_t *buffer, |
108 | | uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode) |
109 | 828k | { |
110 | 828k | SCEnter(); |
111 | 828k | KEYWORD_PROFILING_START; |
112 | | |
113 | 828k | det_ctx->inspection_recursion_counter++; |
114 | | |
115 | 828k | if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { |
116 | 0 | det_ctx->discontinue_matching = 1; |
117 | 0 | KEYWORD_PROFILING_END(det_ctx, smd->type, 0); |
118 | 0 | SCReturnInt(0); |
119 | 0 | } |
120 | | |
121 | | // we want the ability to match on bsize: 0 |
122 | 828k | if (smd == NULL || buffer == NULL) { |
123 | 7.43k | KEYWORD_PROFILING_END(det_ctx, smd->type, 0); |
124 | 7.43k | SCReturnInt(0); |
125 | 7.43k | } |
126 | | |
127 | | /* \todo unify this which is phase 2 of payload inspection unification */ |
128 | 821k | if (smd->type == DETECT_CONTENT) { |
129 | | |
130 | 200k | DetectContentData *cd = (DetectContentData *)smd->ctx; |
131 | 200k | SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); |
132 | | |
133 | | /* we might have already have this content matched by the mpm. |
134 | | * (if there is any other reason why we'd want to avoid checking |
135 | | * it here, please fill it in) */ |
136 | | //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { |
137 | | // goto match; |
138 | | //} |
139 | | |
140 | | /* rule parsers should take care of this */ |
141 | | #ifdef DEBUG |
142 | | BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); |
143 | | #endif |
144 | | |
145 | | /* search for our pattern, checking the matches recursively. |
146 | | * if we match we look for the next SigMatch as well */ |
147 | 200k | const uint8_t *found = NULL; |
148 | 200k | uint32_t offset = 0; |
149 | 200k | uint32_t depth = buffer_len; |
150 | 200k | uint32_t prev_offset = 0; /**< used in recursive searching */ |
151 | 200k | uint32_t prev_buffer_offset = det_ctx->buffer_offset; |
152 | | |
153 | 207k | do { |
154 | 207k | if ((cd->flags & DETECT_CONTENT_DISTANCE) || |
155 | 207k | (cd->flags & DETECT_CONTENT_WITHIN)) { |
156 | 1.84k | SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset); |
157 | | |
158 | 1.84k | offset = prev_buffer_offset; |
159 | 1.84k | depth = buffer_len; |
160 | | |
161 | 1.84k | int distance = cd->distance; |
162 | 1.84k | if (cd->flags & DETECT_CONTENT_DISTANCE) { |
163 | 701 | if (cd->flags & DETECT_CONTENT_DISTANCE_VAR) { |
164 | 42 | distance = det_ctx->byte_values[cd->distance]; |
165 | 42 | } |
166 | 701 | if (distance < 0 && (uint32_t)(abs(distance)) > offset) |
167 | 0 | offset = 0; |
168 | 701 | else |
169 | 701 | offset += distance; |
170 | | |
171 | 701 | SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, |
172 | 701 | distance, offset, depth); |
173 | 701 | } |
174 | | |
175 | 1.84k | if (cd->flags & DETECT_CONTENT_WITHIN) { |
176 | 1.59k | if (cd->flags & DETECT_CONTENT_WITHIN_VAR) { |
177 | 24 | if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->byte_values[cd->within] + distance)) { |
178 | 24 | depth = prev_buffer_offset + det_ctx->byte_values[cd->within] + distance; |
179 | 24 | } |
180 | 1.57k | } else { |
181 | 1.57k | if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { |
182 | 715 | depth = prev_buffer_offset + cd->within + distance; |
183 | 715 | } |
184 | | |
185 | 1.57k | SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, |
186 | 1.57k | cd->within, prev_buffer_offset, depth); |
187 | 1.57k | } |
188 | | |
189 | 1.59k | if (stream_start_offset != 0 && prev_buffer_offset == 0) { |
190 | 0 | if (depth <= stream_start_offset) { |
191 | 0 | goto no_match; |
192 | 0 | } else if (depth >= (stream_start_offset + buffer_len)) { |
193 | 0 | ; |
194 | 0 | } else { |
195 | 0 | depth = depth - stream_start_offset; |
196 | 0 | } |
197 | 0 | } |
198 | 1.59k | } |
199 | | |
200 | 1.84k | if (cd->flags & DETECT_CONTENT_DEPTH_VAR) { |
201 | 0 | if ((det_ctx->byte_values[cd->depth] + prev_buffer_offset) < depth) { |
202 | 0 | depth = prev_buffer_offset + det_ctx->byte_values[cd->depth]; |
203 | 0 | } |
204 | 1.84k | } else { |
205 | 1.84k | if (cd->depth != 0) { |
206 | 298 | if ((cd->depth + prev_buffer_offset) < depth) { |
207 | 0 | depth = prev_buffer_offset + cd->depth; |
208 | 0 | } |
209 | | |
210 | 298 | SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); |
211 | 298 | } |
212 | 1.84k | } |
213 | | |
214 | 1.84k | if (cd->flags & DETECT_CONTENT_OFFSET_VAR) { |
215 | 0 | if (det_ctx->byte_values[cd->offset] > offset) |
216 | 0 | offset = det_ctx->byte_values[cd->offset]; |
217 | 1.84k | } else { |
218 | 1.84k | if (cd->offset > offset) { |
219 | 0 | offset = cd->offset; |
220 | 0 | SCLogDebug("setting offset %"PRIu32, offset); |
221 | 0 | } |
222 | 1.84k | } |
223 | 205k | } else { /* implied no relative matches */ |
224 | | /* set depth */ |
225 | 205k | if (cd->flags & DETECT_CONTENT_DEPTH_VAR) { |
226 | 1.50k | depth = det_ctx->byte_values[cd->depth]; |
227 | 204k | } else { |
228 | 204k | if (cd->depth != 0) { |
229 | 17.1k | depth = cd->depth; |
230 | 17.1k | } |
231 | 204k | } |
232 | | |
233 | 205k | if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { |
234 | 10 | if (depth <= stream_start_offset) { |
235 | 10 | goto no_match; |
236 | 10 | } else if (depth >= (stream_start_offset + buffer_len)) { |
237 | 0 | ; |
238 | 0 | } else { |
239 | 0 | depth = depth - stream_start_offset; |
240 | 0 | } |
241 | 10 | } |
242 | | |
243 | | /* set offset */ |
244 | 205k | if (cd->flags & DETECT_CONTENT_OFFSET_VAR) |
245 | 1.48k | offset = det_ctx->byte_values[cd->offset]; |
246 | 204k | else |
247 | 204k | offset = cd->offset; |
248 | 205k | prev_buffer_offset = 0; |
249 | 205k | } |
250 | | |
251 | | /* If the value came from a variable, make sure to adjust the depth so it's relative |
252 | | * to the offset value. |
253 | | */ |
254 | 207k | if (cd->flags & (DETECT_CONTENT_OFFSET_VAR | DETECT_CONTENT_DEPTH_VAR)) { |
255 | 1.52k | depth += offset; |
256 | 1.52k | } |
257 | | |
258 | | /* update offset with prev_offset if we're searching for |
259 | | * matches after the first occurrence. */ |
260 | 207k | SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); |
261 | 207k | if (prev_offset != 0) |
262 | 7.01k | offset = prev_offset; |
263 | | |
264 | 207k | SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); |
265 | | |
266 | 207k | if (depth > buffer_len) |
267 | 3.26k | depth = buffer_len; |
268 | | |
269 | | /* if offset is bigger than depth we can never match on a pattern. |
270 | | * We can however, "match" on a negated pattern. */ |
271 | 207k | if (offset > depth || depth == 0) { |
272 | 3.44k | if (cd->flags & DETECT_CONTENT_NEGATED) { |
273 | 2.28k | goto match; |
274 | 2.28k | } else { |
275 | 1.16k | goto no_match; |
276 | 1.16k | } |
277 | 3.44k | } |
278 | | |
279 | 204k | const uint8_t *sbuffer = buffer + offset; |
280 | 204k | uint32_t sbuffer_len = depth - offset; |
281 | 204k | uint32_t match_offset = 0; |
282 | 204k | SCLogDebug("sbuffer_len %" PRIu32 " depth: %" PRIu32 ", buffer_len: %" PRIu32, |
283 | 204k | sbuffer_len, depth, buffer_len); |
284 | | #ifdef DEBUG |
285 | | BUG_ON(sbuffer_len > buffer_len); |
286 | | #endif |
287 | 204k | if (cd->flags & DETECT_CONTENT_ENDS_WITH && depth < buffer_len) { |
288 | 20 | SCLogDebug("depth < buffer_len while DETECT_CONTENT_ENDS_WITH is set. Can't possibly match."); |
289 | 20 | found = NULL; |
290 | 204k | } else if (cd->content_len > sbuffer_len) { |
291 | 42.3k | found = NULL; |
292 | 161k | } else { |
293 | | /* do the actual search */ |
294 | 161k | found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, |
295 | 161k | sbuffer_len); |
296 | 161k | } |
297 | | |
298 | | /* next we evaluate the result in combination with the |
299 | | * negation flag. */ |
300 | 204k | SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); |
301 | | |
302 | 204k | if (found == NULL) { |
303 | 178k | if (!(cd->flags & DETECT_CONTENT_NEGATED)) { |
304 | 9.10k | if ((cd->flags & (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN)) == 0) { |
305 | | /* independent match from previous matches, so failure is fatal */ |
306 | 8.82k | det_ctx->discontinue_matching = 1; |
307 | 8.82k | } |
308 | | |
309 | 9.10k | goto no_match; |
310 | 168k | } else { |
311 | 168k | goto match; |
312 | 168k | } |
313 | 178k | } else { |
314 | 26.2k | match_offset = (uint32_t)((found - buffer) + cd->content_len); |
315 | 26.2k | if (cd->flags & DETECT_CONTENT_NEGATED) { |
316 | 2.45k | SCLogDebug("content %" PRIu32 " matched at offset %" PRIu32 |
317 | 2.45k | ", but negated so no match", |
318 | 2.45k | cd->id, match_offset); |
319 | | /* don't bother carrying recursive matches now, for preceding |
320 | | * relative keywords */ |
321 | | |
322 | | /* found a match but not at the end of the buffer */ |
323 | 2.45k | if (cd->flags & DETECT_CONTENT_ENDS_WITH) { |
324 | 0 | if (sbuffer_len != match_offset) { |
325 | 0 | SCLogDebug("content \"%s\" %" PRIu32 " matched at offset %" PRIu32 |
326 | 0 | ", but not at end of buffer so match", |
327 | 0 | cd->content, cd->id, match_offset); |
328 | 0 | goto match; |
329 | 0 | } |
330 | 0 | } |
331 | 2.45k | if (DETECT_CONTENT_IS_SINGLE(cd)) |
332 | 2.22k | det_ctx->discontinue_matching = 1; |
333 | 2.45k | goto no_match; |
334 | 23.7k | } else { |
335 | 23.7k | SCLogDebug("content %" PRIu32 " matched at offset %" PRIu32 "", cd->id, |
336 | 23.7k | match_offset); |
337 | 23.7k | det_ctx->buffer_offset = match_offset; |
338 | | |
339 | 23.7k | if ((cd->flags & DETECT_CONTENT_ENDS_WITH) == 0 || match_offset == buffer_len) { |
340 | | /* Match branch, add replace to the list if needed */ |
341 | 23.0k | if (cd->flags & DETECT_CONTENT_REPLACE) { |
342 | 0 | if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) { |
343 | | /* we will need to replace content if match is confirmed |
344 | | * cast to non-const as replace writes to it. */ |
345 | 0 | det_ctx->replist = DetectReplaceAddToList( |
346 | 0 | det_ctx->replist, (uint8_t *)found, cd); |
347 | 0 | } else { |
348 | 0 | SCLogWarning("Can't modify payload without packet"); |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | /* if this is the last match we're done */ |
353 | 23.0k | if (smd->is_last) { |
354 | 12.7k | goto match; |
355 | 12.7k | } |
356 | | |
357 | 10.2k | SCLogDebug("content %" PRIu32, cd->id); |
358 | 10.2k | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
359 | | |
360 | | /* see if the next buffer keywords match. If not, we will |
361 | | * search for another occurrence of this content and see |
362 | | * if the others match then until we run out of matches */ |
363 | 10.2k | uint8_t r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd + 1, p, f, |
364 | 10.2k | buffer, buffer_len, stream_start_offset, flags, inspection_mode); |
365 | 10.2k | if (r == 1) { |
366 | 2.64k | SCReturnInt(1); |
367 | 2.64k | } |
368 | 7.64k | SCLogDebug("no match for 'next sm'"); |
369 | | |
370 | 7.64k | if (det_ctx->discontinue_matching) { |
371 | 841 | SCLogDebug("'next sm' said to discontinue this right now"); |
372 | 841 | goto no_match; |
373 | 841 | } |
374 | | |
375 | | /* no match and no reason to look for another instance */ |
376 | 6.80k | if ((cd->flags & DETECT_CONTENT_WITHIN_NEXT) == 0) { |
377 | 535 | SCLogDebug("'next sm' does not depend on me, so we can give up"); |
378 | 535 | det_ctx->discontinue_matching = 1; |
379 | 535 | goto no_match; |
380 | 535 | } |
381 | | |
382 | 6.26k | SCLogDebug("'next sm' depends on me %p, lets see what we can do (flags %u)", |
383 | 6.26k | cd, cd->flags); |
384 | 6.26k | } |
385 | | /* set the previous match offset to the start of this match + 1 */ |
386 | 7.01k | prev_offset = (match_offset - (cd->content_len - 1)); |
387 | 7.01k | SCLogDebug("trying to see if there is another match after prev_offset %" PRIu32, |
388 | 7.01k | prev_offset); |
389 | 7.01k | } |
390 | 26.2k | } |
391 | | |
392 | 204k | } while(1); |
393 | | |
394 | 620k | } else if (smd->type == DETECT_ISDATAAT) { |
395 | 11.1k | SCLogDebug("inspecting isdataat"); |
396 | | |
397 | 11.1k | const DetectIsdataatData *id = (DetectIsdataatData *)smd->ctx; |
398 | 11.1k | uint32_t dataat = id->dataat; |
399 | 11.1k | if (id->flags & ISDATAAT_OFFSET_VAR) { |
400 | 0 | uint64_t be_value = det_ctx->byte_values[dataat]; |
401 | 0 | if (be_value >= 100000000) { |
402 | 0 | if ((id->flags & ISDATAAT_NEGATED) == 0) { |
403 | 0 | SCLogDebug("extracted value %"PRIu64" very big: no match", be_value); |
404 | 0 | goto no_match; |
405 | 0 | } |
406 | 0 | SCLogDebug("extracted value way %"PRIu64" very big: match", be_value); |
407 | 0 | goto match; |
408 | 0 | } |
409 | 0 | dataat = (uint32_t)be_value; |
410 | 0 | SCLogDebug("isdataat: using value %u from byte_extract local_id %u", dataat, id->dataat); |
411 | 0 | } |
412 | | |
413 | 11.1k | if (id->flags & ISDATAAT_RELATIVE) { |
414 | 10.3k | if (det_ctx->buffer_offset + dataat > buffer_len) { |
415 | 49 | SCLogDebug("det_ctx->buffer_offset + dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + dataat, buffer_len); |
416 | 49 | if (id->flags & ISDATAAT_NEGATED) |
417 | 0 | goto match; |
418 | 49 | goto no_match; |
419 | 10.3k | } else { |
420 | 10.3k | SCLogDebug("relative isdataat match"); |
421 | 10.3k | if (id->flags & ISDATAAT_NEGATED) |
422 | 0 | goto no_match; |
423 | 10.3k | goto match; |
424 | 10.3k | } |
425 | 10.3k | } else { |
426 | 761 | if (dataat < buffer_len) { |
427 | 350 | SCLogDebug("absolute isdataat match"); |
428 | 350 | if (id->flags & ISDATAAT_NEGATED) |
429 | 0 | goto no_match; |
430 | 350 | goto match; |
431 | 411 | } else { |
432 | 411 | SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", dataat, buffer_len); |
433 | 411 | if (id->flags & ISDATAAT_NEGATED) |
434 | 0 | goto match; |
435 | 411 | goto no_match; |
436 | 411 | } |
437 | 761 | } |
438 | | |
439 | 609k | } else if (smd->type == DETECT_PCRE) { |
440 | 394k | SCLogDebug("inspecting pcre"); |
441 | 394k | DetectPcreData *pe = (DetectPcreData *)smd->ctx; |
442 | 394k | uint32_t prev_buffer_offset = det_ctx->buffer_offset; |
443 | 394k | uint32_t prev_offset = 0; |
444 | 394k | int r = 0; |
445 | | |
446 | 394k | det_ctx->pcre_match_start_offset = 0; |
447 | 396k | do { |
448 | 396k | r = DetectPcrePayloadMatch(det_ctx, s, smd, p, f, |
449 | 396k | buffer, buffer_len); |
450 | 396k | if (r == 0) { |
451 | 123k | goto no_match; |
452 | 123k | } |
453 | 273k | if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { |
454 | 271k | SCLogDebug("no relative match coming up, so this is a match"); |
455 | 271k | goto match; |
456 | 271k | } |
457 | 2.01k | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
458 | | |
459 | | /* save it, in case we need to do a pcre match once again */ |
460 | 2.01k | prev_offset = det_ctx->pcre_match_start_offset; |
461 | | |
462 | | /* see if the next payload keywords match. If not, we will |
463 | | * search for another occurrence of this pcre and see |
464 | | * if the others match, until we run out of matches */ |
465 | 2.01k | r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, |
466 | 2.01k | p, f, buffer, buffer_len, stream_start_offset, flags, |
467 | 2.01k | inspection_mode); |
468 | 2.01k | if (r == 1) { |
469 | 44 | SCReturnInt(1); |
470 | 44 | } |
471 | | |
472 | 1.96k | if (det_ctx->discontinue_matching) |
473 | 0 | goto no_match; |
474 | | |
475 | 1.96k | if (prev_offset == 0) { |
476 | | // This happens for negated PCRE |
477 | | // We do not search for another occurrence of this pcre |
478 | 15 | SCReturnInt(0); |
479 | 15 | } |
480 | 1.95k | det_ctx->buffer_offset = prev_buffer_offset; |
481 | 1.95k | det_ctx->pcre_match_start_offset = prev_offset; |
482 | 1.95k | } while (1); |
483 | | |
484 | 394k | } else if (smd->type == DETECT_BYTETEST) { |
485 | 42.5k | DetectBytetestData *btd = (DetectBytetestData *)smd->ctx; |
486 | 42.5k | uint16_t btflags = btd->flags; |
487 | 42.5k | int32_t offset = btd->offset; |
488 | 42.5k | uint64_t value = btd->value; |
489 | 42.5k | int32_t nbytes = btd->nbytes; |
490 | 42.5k | if (btflags & DETECT_BYTETEST_OFFSET_VAR) { |
491 | 0 | offset = det_ctx->byte_values[offset]; |
492 | 0 | } |
493 | 42.5k | if (btflags & DETECT_BYTETEST_VALUE_VAR) { |
494 | 3.68k | value = det_ctx->byte_values[value]; |
495 | 3.68k | } |
496 | 42.5k | if (btflags & DETECT_BYTETEST_NBYTES_VAR) { |
497 | 2.06k | nbytes = det_ctx->byte_values[nbytes]; |
498 | 2.06k | } |
499 | | |
500 | | /* if we have dce enabled we will have to use the endianness |
501 | | * specified by the dce header */ |
502 | 42.5k | if (btflags & DETECT_BYTETEST_DCE) { |
503 | | /* enable the endianness flag temporarily. once we are done |
504 | | * processing we reset the flags to the original value*/ |
505 | 0 | btflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? |
506 | 0 | DETECT_BYTETEST_LITTLE: 0); |
507 | 0 | } |
508 | | |
509 | 42.5k | if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, btflags, offset, nbytes, |
510 | 42.5k | value) != 1) { |
511 | 33.3k | goto no_match; |
512 | 33.3k | } |
513 | | |
514 | 9.13k | goto match; |
515 | | |
516 | 172k | } else if (smd->type == DETECT_BYTEJUMP) { |
517 | 30.3k | DetectBytejumpData *bjd = (DetectBytejumpData *)smd->ctx; |
518 | 30.3k | uint16_t bjflags = bjd->flags; |
519 | 30.3k | int32_t offset = bjd->offset; |
520 | 30.3k | int32_t nbytes; |
521 | | |
522 | 30.3k | if (bjflags & DETECT_BYTEJUMP_OFFSET_VAR) { |
523 | 0 | offset = det_ctx->byte_values[offset]; |
524 | 0 | } |
525 | | |
526 | 30.3k | if (bjflags & DETECT_BYTEJUMP_NBYTES_VAR) { |
527 | 26.6k | nbytes = det_ctx->byte_values[bjd->nbytes]; |
528 | 26.6k | } else { |
529 | 3.67k | nbytes = bjd->nbytes; |
530 | 3.67k | } |
531 | | |
532 | | /* if we have dce enabled we will have to use the endianness |
533 | | * specified by the dce header */ |
534 | 30.3k | if (bjflags & DETECT_BYTEJUMP_DCE) { |
535 | | /* enable the endianness flag temporarily. once we are done |
536 | | * processing we reset the flags to the original value*/ |
537 | 0 | bjflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? |
538 | 0 | DETECT_BYTEJUMP_LITTLE: 0); |
539 | 0 | } |
540 | | |
541 | 30.3k | if (!DetectBytejumpDoMatch( |
542 | 30.3k | det_ctx, s, smd->ctx, buffer, buffer_len, bjflags, nbytes, offset)) { |
543 | 19.9k | goto no_match; |
544 | 19.9k | } |
545 | | |
546 | 10.3k | goto match; |
547 | | |
548 | 141k | } else if (smd->type == DETECT_BYTE_EXTRACT) { |
549 | | |
550 | 64.7k | DetectByteExtractData *bed = (DetectByteExtractData *)smd->ctx; |
551 | 64.7k | uint8_t endian = bed->endian; |
552 | | |
553 | | /* if we have dce enabled we will have to use the endianness |
554 | | * specified by the dce header */ |
555 | 64.7k | if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && |
556 | 577 | endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && |
557 | 577 | flags & (DETECT_CI_FLAGS_DCE_LE|DETECT_CI_FLAGS_DCE_BE)) { |
558 | | |
559 | | /* enable the endianness flag temporarily. once we are done |
560 | | * processing we reset the flags to the original value*/ |
561 | 0 | endian |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? |
562 | 0 | DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); |
563 | 0 | } |
564 | | |
565 | 64.7k | if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len, |
566 | 64.7k | &det_ctx->byte_values[bed->local_id], endian) != 1) { |
567 | 13.6k | goto no_match; |
568 | 13.6k | } |
569 | | |
570 | 51.1k | SCLogDebug("[BE] Fetched value for index %d: %"PRIu64, |
571 | 51.1k | bed->local_id, det_ctx->byte_values[bed->local_id]); |
572 | 51.1k | goto match; |
573 | | |
574 | 76.9k | } else if (smd->type == DETECT_BYTEMATH) { |
575 | | |
576 | 5.57k | DetectByteMathData *bmd = (DetectByteMathData *)smd->ctx; |
577 | 5.57k | uint8_t endian = bmd->endian; |
578 | | |
579 | | /* if we have dce enabled we will have to use the endianness |
580 | | * specified by the dce header */ |
581 | 5.57k | if ((bmd->flags & DETECT_BYTEMATH_FLAG_ENDIAN) && endian == (int)EndianDCE && |
582 | 0 | flags & (DETECT_CI_FLAGS_DCE_LE | DETECT_CI_FLAGS_DCE_BE)) { |
583 | | |
584 | | /* enable the endianness flag temporarily. once we are done |
585 | | * processing we reset the flags to the original value*/ |
586 | 0 | endian |= (uint8_t)((flags & DETECT_CI_FLAGS_DCE_LE) ? LittleEndian : BigEndian); |
587 | 0 | } |
588 | 5.57k | uint64_t rvalue; |
589 | 5.57k | if (bmd->flags & DETECT_BYTEMATH_FLAG_RVALUE_VAR) { |
590 | 4.92k | rvalue = det_ctx->byte_values[bmd->rvalue]; |
591 | 4.92k | } else { |
592 | 641 | rvalue = bmd->rvalue; |
593 | 641 | } |
594 | | |
595 | 5.57k | uint8_t nbytes; |
596 | 5.57k | if (bmd->flags & DETECT_BYTEMATH_FLAG_NBYTES_VAR) { |
597 | 0 | nbytes = (uint8_t)det_ctx->byte_values[bmd->nbytes]; |
598 | 5.57k | } else { |
599 | 5.57k | nbytes = bmd->nbytes; |
600 | 5.57k | } |
601 | | |
602 | 5.57k | DEBUG_VALIDATE_BUG_ON(buffer_len > UINT16_MAX); |
603 | 5.57k | if (DetectByteMathDoMatch(det_ctx, smd, s, buffer, (uint16_t)buffer_len, nbytes, rvalue, |
604 | 5.57k | &det_ctx->byte_values[bmd->local_id], endian) != 1) { |
605 | 2.94k | goto no_match; |
606 | 2.94k | } |
607 | | |
608 | 2.63k | SCLogDebug("[BM] Fetched value for index %d: %"PRIu64, |
609 | 2.63k | bmd->local_id, det_ctx->byte_values[bmd->local_id]); |
610 | 2.63k | goto match; |
611 | | |
612 | 71.4k | } else if (smd->type == DETECT_BSIZE) { |
613 | | |
614 | 2.08k | bool eof = (flags & DETECT_CI_FLAGS_END); |
615 | 2.08k | const uint64_t data_size = buffer_len + stream_start_offset; |
616 | 2.08k | int r = DetectBsizeMatch(smd->ctx, data_size, eof); |
617 | 2.08k | if (r < 0) { |
618 | 1.62k | det_ctx->discontinue_matching = 1; |
619 | 1.62k | goto no_match; |
620 | | |
621 | 1.62k | } else if (r == 0) { |
622 | 10 | goto no_match; |
623 | 10 | } |
624 | 450 | goto match; |
625 | | |
626 | 69.3k | } else if (smd->type == DETECT_DATASET) { |
627 | | |
628 | | //PrintRawDataFp(stdout, buffer, buffer_len); |
629 | 59.2k | const DetectDatasetData *sd = (const DetectDatasetData *) smd->ctx; |
630 | 59.2k | int r = DetectDatasetBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset? |
631 | 59.2k | if (r == 1) { |
632 | 382 | goto match; |
633 | 382 | } |
634 | 58.8k | det_ctx->discontinue_matching = 1; |
635 | 58.8k | goto no_match; |
636 | | |
637 | 59.2k | } else if (smd->type == DETECT_DATAREP) { |
638 | | |
639 | | //PrintRawDataFp(stdout, buffer, buffer_len); |
640 | 203 | const DetectDatarepData *sd = (const DetectDatarepData *) smd->ctx; |
641 | 203 | int r = DetectDatarepBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset? |
642 | 203 | if (r == 1) { |
643 | 0 | goto match; |
644 | 0 | } |
645 | 203 | det_ctx->discontinue_matching = 1; |
646 | 203 | goto no_match; |
647 | | |
648 | 9.85k | } else if (smd->type == DETECT_AL_URILEN) { |
649 | 2 | SCLogDebug("inspecting uri len"); |
650 | | |
651 | 2 | int r = 0; |
652 | 2 | DetectUrilenData *urilend = (DetectUrilenData *) smd->ctx; |
653 | 2 | if (buffer_len > UINT16_MAX) { |
654 | 0 | r = DetectU16Match(UINT16_MAX, &urilend->du16); |
655 | 2 | } else { |
656 | 2 | r = DetectU16Match((uint16_t)buffer_len, &urilend->du16); |
657 | 2 | } |
658 | | |
659 | 2 | if (r == 1) { |
660 | 2 | goto match; |
661 | 2 | } |
662 | | |
663 | 0 | det_ctx->discontinue_matching = 1; |
664 | |
|
665 | 0 | goto no_match; |
666 | | #ifdef HAVE_LUA |
667 | | } |
668 | | else if (smd->type == DETECT_LUA) { |
669 | | SCLogDebug("lua starting"); |
670 | | |
671 | | if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, |
672 | | det_ctx->buffer_offset, f) != 1) |
673 | | { |
674 | | SCLogDebug("lua no_match"); |
675 | | goto no_match; |
676 | | } |
677 | | SCLogDebug("lua match"); |
678 | | goto match; |
679 | | #endif /* HAVE_LUA */ |
680 | 9.85k | } else if (smd->type == DETECT_BASE64_DECODE) { |
681 | 9.85k | if (DetectBase64DecodeDoMatch(det_ctx, s, smd, buffer, buffer_len)) { |
682 | 3.87k | if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { |
683 | 162 | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
684 | 162 | if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { |
685 | | /* Base64 is a terminal list. */ |
686 | 0 | goto final_match; |
687 | 0 | } |
688 | 162 | } |
689 | 3.87k | } |
690 | 9.85k | } else { |
691 | 0 | SCLogDebug("sm->type %u", smd->type); |
692 | | #ifdef DEBUG |
693 | | BUG_ON(1); |
694 | | #endif |
695 | 0 | } |
696 | | |
697 | 278k | no_match: |
698 | 278k | KEYWORD_PROFILING_END(det_ctx, smd->type, 0); |
699 | 278k | SCReturnInt(0); |
700 | | |
701 | 539k | match: |
702 | | /* this sigmatch matched, inspect the next one. If it was the last, |
703 | | * the buffer portion of the signature matched. */ |
704 | 539k | if (!smd->is_last) { |
705 | 111k | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
706 | 111k | uint8_t r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd + 1, p, f, buffer, |
707 | 111k | buffer_len, stream_start_offset, flags, inspection_mode); |
708 | 111k | SCReturnInt(r); |
709 | 111k | } |
710 | 428k | final_match: |
711 | 428k | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
712 | 428k | SCReturnInt(1); |
713 | 539k | } |
714 | | |
715 | | #ifdef UNITTESTS |
716 | | #include "tests/detect-engine-content-inspection.c" |
717 | | #endif |