Coverage Report

Created: 2026-05-16 07:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
580k
{
110
580k
    SCEnter();
111
580k
    KEYWORD_PROFILING_START;
112
113
580k
    det_ctx->inspection_recursion_counter++;
114
115
580k
    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
580k
    if (smd == NULL || buffer == NULL) {
123
5.72k
        KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
124
5.72k
        SCReturnInt(0);
125
5.72k
    }
126
127
    /* \todo unify this which is phase 2 of payload inspection unification */
128
575k
    if (smd->type == DETECT_CONTENT) {
129
130
149k
        DetectContentData *cd = (DetectContentData *)smd->ctx;
131
149k
        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
149k
        const uint8_t *found = NULL;
148
149k
        uint32_t offset = 0;
149
149k
        uint32_t depth = buffer_len;
150
149k
        uint32_t prev_offset = 0; /**< used in recursive searching */
151
149k
        uint32_t prev_buffer_offset = det_ctx->buffer_offset;
152
153
152k
        do {
154
152k
            if ((cd->flags & DETECT_CONTENT_DISTANCE) ||
155
151k
                (cd->flags & DETECT_CONTENT_WITHIN)) {
156
867
                SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset);
157
158
867
                offset = prev_buffer_offset;
159
867
                depth = buffer_len;
160
161
867
                int distance = cd->distance;
162
867
                if (cd->flags & DETECT_CONTENT_DISTANCE) {
163
699
                    if (cd->flags & DETECT_CONTENT_DISTANCE_VAR) {
164
27
                        distance = det_ctx->byte_values[cd->distance];
165
27
                    }
166
699
                    if (distance < 0 && (uint32_t)(abs(distance)) > offset)
167
0
                        offset = 0;
168
699
                    else
169
699
                        offset += distance;
170
171
699
                    SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32,
172
699
                               distance, offset, depth);
173
699
                }
174
175
867
                if (cd->flags & DETECT_CONTENT_WITHIN) {
176
633
                    if (cd->flags & DETECT_CONTENT_WITHIN_VAR) {
177
18
                        if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->byte_values[cd->within] + distance)) {
178
18
                            depth = prev_buffer_offset + det_ctx->byte_values[cd->within] + distance;
179
18
                        }
180
615
                    } else {
181
615
                        if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) {
182
534
                            depth = prev_buffer_offset + cd->within + distance;
183
534
                        }
184
185
615
                        SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32,
186
615
                                   cd->within, prev_buffer_offset, depth);
187
615
                    }
188
189
633
                    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
633
                }
199
200
867
                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
867
                } else {
205
867
                    if (cd->depth != 0) {
206
364
                        if ((cd->depth + prev_buffer_offset) < depth) {
207
0
                            depth = prev_buffer_offset + cd->depth;
208
0
                        }
209
210
364
                        SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth);
211
364
                    }
212
867
                }
213
214
867
                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
867
                } else {
218
867
                    if (cd->offset > offset) {
219
0
                        offset = cd->offset;
220
0
                        SCLogDebug("setting offset %"PRIu32, offset);
221
0
                    }
222
867
                }
223
151k
            } else { /* implied no relative matches */
224
                /* set depth */
225
151k
                if (cd->flags & DETECT_CONTENT_DEPTH_VAR) {
226
413
                    depth = det_ctx->byte_values[cd->depth];
227
151k
                } else {
228
151k
                    if (cd->depth != 0) {
229
13.4k
                        depth = cd->depth;
230
13.4k
                    }
231
151k
                }
232
233
151k
                if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) {
234
12
                    if (depth <= stream_start_offset) {
235
12
                        goto no_match;
236
12
                    } else if (depth >= (stream_start_offset + buffer_len)) {
237
0
                        ;
238
0
                    } else {
239
0
                        depth = depth - stream_start_offset;
240
0
                    }
241
12
                }
242
243
                /* set offset */
244
151k
                if (cd->flags & DETECT_CONTENT_OFFSET_VAR)
245
525
                    offset = det_ctx->byte_values[cd->offset];
246
151k
                else
247
151k
                    offset = cd->offset;
248
151k
                prev_buffer_offset = 0;
249
151k
            }
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
152k
            if (cd->flags & (DETECT_CONTENT_OFFSET_VAR | DETECT_CONTENT_DEPTH_VAR)) {
255
530
                depth += offset;
256
530
            }
257
258
            /* update offset with prev_offset if we're searching for
259
             * matches after the first occurrence. */
260
152k
            SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset);
261
152k
            if (prev_offset != 0)
262
2.76k
                offset = prev_offset;
263
264
152k
            SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth);
265
266
152k
            if (depth > buffer_len)
267
1.65k
                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
152k
            if (offset > depth || depth == 0) {
272
2.84k
                if (cd->flags & DETECT_CONTENT_NEGATED) {
273
2.49k
                    goto match;
274
2.49k
                } else {
275
345
                    goto no_match;
276
345
                }
277
2.84k
            }
278
279
149k
            const uint8_t *sbuffer = buffer + offset;
280
149k
            uint32_t sbuffer_len = depth - offset;
281
149k
            uint32_t match_offset = 0;
282
149k
            SCLogDebug("sbuffer_len %" PRIu32 " depth: %" PRIu32 ", buffer_len: %" PRIu32,
283
149k
                    sbuffer_len, depth, buffer_len);
284
#ifdef DEBUG
285
            BUG_ON(sbuffer_len > buffer_len);
286
#endif
287
149k
            if (cd->flags & DETECT_CONTENT_ENDS_WITH && depth < buffer_len) {
288
9
                SCLogDebug("depth < buffer_len while DETECT_CONTENT_ENDS_WITH is set. Can't possibly match.");
289
9
                found = NULL;
290
149k
            } else if (cd->content_len > sbuffer_len) {
291
30.0k
                found = NULL;
292
119k
            } else {
293
                /* do the actual search */
294
119k
                found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer,
295
119k
                        sbuffer_len);
296
119k
            }
297
298
            /* next we evaluate the result in combination with the
299
             * negation flag. */
300
149k
            SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false");
301
302
149k
            if (found == NULL) {
303
134k
                if (!(cd->flags & DETECT_CONTENT_NEGATED)) {
304
7.98k
                    if ((cd->flags & (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN)) == 0) {
305
                        /* independent match from previous matches, so failure is fatal */
306
7.82k
                        det_ctx->discontinue_matching = 1;
307
7.82k
                    }
308
309
7.98k
                    goto no_match;
310
126k
                } else {
311
126k
                    goto match;
312
126k
                }
313
134k
            } else {
314
15.1k
                match_offset = (uint32_t)((found - buffer) + cd->content_len);
315
15.1k
                if (cd->flags & DETECT_CONTENT_NEGATED) {
316
1.96k
                    SCLogDebug("content %" PRIu32 " matched at offset %" PRIu32
317
1.96k
                               ", but negated so no match",
318
1.96k
                            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
1.96k
                    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
1.96k
                    if (DETECT_CONTENT_IS_SINGLE(cd))
332
1.90k
                        det_ctx->discontinue_matching = 1;
333
1.96k
                    goto no_match;
334
13.2k
                } else {
335
13.2k
                    SCLogDebug("content %" PRIu32 " matched at offset %" PRIu32 "", cd->id,
336
13.2k
                            match_offset);
337
13.2k
                    det_ctx->buffer_offset = match_offset;
338
339
13.2k
                    if ((cd->flags & DETECT_CONTENT_ENDS_WITH) == 0 || match_offset == buffer_len) {
340
                        /* Match branch, add replace to the list if needed */
341
12.7k
                        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
12.7k
                        if (smd->is_last) {
354
9.04k
                            goto match;
355
9.04k
                        }
356
357
3.65k
                        SCLogDebug("content %" PRIu32, cd->id);
358
3.65k
                        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
3.65k
                        uint8_t r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd + 1, p, f,
364
3.65k
                                buffer, buffer_len, stream_start_offset, flags, inspection_mode);
365
3.65k
                        if (r == 1) {
366
961
                            SCReturnInt(1);
367
961
                        }
368
2.69k
                        SCLogDebug("no match for 'next sm'");
369
370
2.69k
                        if (det_ctx->discontinue_matching) {
371
45
                            SCLogDebug("'next sm' said to discontinue this right now");
372
45
                            goto no_match;
373
45
                        }
374
375
                        /* no match and no reason to look for another instance */
376
2.65k
                        if ((cd->flags & DETECT_CONTENT_WITHIN_NEXT) == 0) {
377
390
                            SCLogDebug("'next sm' does not depend on me, so we can give up");
378
390
                            det_ctx->discontinue_matching = 1;
379
390
                            goto no_match;
380
390
                        }
381
382
2.26k
                        SCLogDebug("'next sm' depends on me %p, lets see what we can do (flags %u)",
383
2.26k
                                cd, cd->flags);
384
2.26k
                    }
385
                    /* set the previous match offset to the start of this match + 1 */
386
2.76k
                    prev_offset = (match_offset - (cd->content_len - 1));
387
2.76k
                    SCLogDebug("trying to see if there is another match after prev_offset %" PRIu32,
388
2.76k
                            prev_offset);
389
2.76k
                }
390
15.1k
            }
391
392
149k
        } while(1);
393
394
425k
    } else if (smd->type == DETECT_ISDATAAT) {
395
9.31k
        SCLogDebug("inspecting isdataat");
396
397
9.31k
        const DetectIsdataatData *id = (DetectIsdataatData *)smd->ctx;
398
9.31k
        uint32_t dataat = id->dataat;
399
9.31k
        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
9.31k
        if (id->flags & ISDATAAT_RELATIVE) {
414
8.60k
            if (det_ctx->buffer_offset + dataat > buffer_len) {
415
58
                SCLogDebug("det_ctx->buffer_offset + dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + dataat, buffer_len);
416
58
                if (id->flags & ISDATAAT_NEGATED)
417
0
                    goto match;
418
58
                goto no_match;
419
8.54k
            } else {
420
8.54k
                SCLogDebug("relative isdataat match");
421
8.54k
                if (id->flags & ISDATAAT_NEGATED)
422
0
                    goto no_match;
423
8.54k
                goto match;
424
8.54k
            }
425
8.60k
        } else {
426
713
            if (dataat < buffer_len) {
427
440
                SCLogDebug("absolute isdataat match");
428
440
                if (id->flags & ISDATAAT_NEGATED)
429
0
                    goto no_match;
430
440
                goto match;
431
440
            } else {
432
273
                SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", dataat, buffer_len);
433
273
                if (id->flags & ISDATAAT_NEGATED)
434
0
                    goto match;
435
273
                goto no_match;
436
273
            }
437
713
        }
438
439
416k
    } else if (smd->type == DETECT_PCRE) {
440
270k
        SCLogDebug("inspecting pcre");
441
270k
        DetectPcreData *pe = (DetectPcreData *)smd->ctx;
442
270k
        uint32_t prev_buffer_offset = det_ctx->buffer_offset;
443
270k
        uint32_t prev_offset = 0;
444
270k
        int r = 0;
445
446
270k
        det_ctx->pcre_match_start_offset = 0;
447
272k
        do {
448
272k
            r = DetectPcrePayloadMatch(det_ctx, s, smd, p, f,
449
272k
                                       buffer, buffer_len);
450
272k
            if (r == 0) {
451
63.7k
                goto no_match;
452
63.7k
            }
453
208k
            if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) {
454
206k
                SCLogDebug("no relative match coming up, so this is a match");
455
206k
                goto match;
456
206k
            }
457
2.19k
            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.19k
            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.19k
            r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1,
466
2.19k
                    p, f, buffer, buffer_len, stream_start_offset, flags,
467
2.19k
                    inspection_mode);
468
2.19k
            if (r == 1) {
469
47
                SCReturnInt(1);
470
47
            }
471
472
2.14k
            if (det_ctx->discontinue_matching)
473
0
                goto no_match;
474
475
2.14k
            if (prev_offset == 0) {
476
                // This happens for negated PCRE
477
                // We do not search for another occurrence of this pcre
478
334
                SCReturnInt(0);
479
334
            }
480
1.81k
            det_ctx->buffer_offset = prev_buffer_offset;
481
1.81k
            det_ctx->pcre_match_start_offset = prev_offset;
482
1.81k
        } while (1);
483
484
270k
    } else if (smd->type == DETECT_BYTETEST) {
485
42.8k
        DetectBytetestData *btd = (DetectBytetestData *)smd->ctx;
486
42.8k
        uint16_t btflags = btd->flags;
487
42.8k
        int32_t offset = btd->offset;
488
42.8k
        uint64_t value = btd->value;
489
42.8k
        int32_t nbytes = btd->nbytes;
490
42.8k
        if (btflags & DETECT_BYTETEST_OFFSET_VAR) {
491
0
            offset = det_ctx->byte_values[offset];
492
0
        }
493
42.8k
        if (btflags & DETECT_BYTETEST_VALUE_VAR) {
494
9.70k
            value = det_ctx->byte_values[value];
495
9.70k
        }
496
42.8k
        if (btflags & DETECT_BYTETEST_NBYTES_VAR) {
497
966
            nbytes = det_ctx->byte_values[nbytes];
498
966
        }
499
500
        /* if we have dce enabled we will have to use the endianness
501
         * specified by the dce header */
502
42.8k
        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.8k
        if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, btflags, offset, nbytes,
510
42.8k
                    value) != 1) {
511
28.4k
            goto no_match;
512
28.4k
        }
513
514
14.3k
        goto match;
515
516
102k
    } else if (smd->type == DETECT_BYTEJUMP) {
517
21.9k
        DetectBytejumpData *bjd = (DetectBytejumpData *)smd->ctx;
518
21.9k
        uint16_t bjflags = bjd->flags;
519
21.9k
        int32_t offset = bjd->offset;
520
21.9k
        int32_t nbytes;
521
522
21.9k
        if (bjflags & DETECT_BYTEJUMP_OFFSET_VAR) {
523
0
            offset = det_ctx->byte_values[offset];
524
0
        }
525
526
21.9k
        if (bjflags & DETECT_BYTEJUMP_NBYTES_VAR) {
527
20.2k
            nbytes = det_ctx->byte_values[bjd->nbytes];
528
20.2k
        } else {
529
1.78k
            nbytes = bjd->nbytes;
530
1.78k
        }
531
532
        /* if we have dce enabled we will have to use the endianness
533
         * specified by the dce header */
534
21.9k
        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
21.9k
        if (!DetectBytejumpDoMatch(
542
21.9k
                    det_ctx, s, smd->ctx, buffer, buffer_len, bjflags, nbytes, offset)) {
543
13.4k
            goto no_match;
544
13.4k
        }
545
546
8.55k
        goto match;
547
548
80.7k
    } else if (smd->type == DETECT_BYTE_EXTRACT) {
549
550
47.5k
        DetectByteExtractData *bed = (DetectByteExtractData *)smd->ctx;
551
47.5k
        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
47.5k
        if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) &&
556
1.84k
            endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE &&
557
1.84k
            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
47.5k
        if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len,
566
47.5k
                    &det_ctx->byte_values[bed->local_id], endian) != 1) {
567
9.09k
            goto no_match;
568
9.09k
        }
569
570
38.4k
        SCLogDebug("[BE] Fetched value for index %d: %"PRIu64,
571
38.4k
                   bed->local_id, det_ctx->byte_values[bed->local_id]);
572
38.4k
        goto match;
573
574
47.5k
    } else if (smd->type == DETECT_BYTEMATH) {
575
576
6.07k
        DetectByteMathData *bmd = (DetectByteMathData *)smd->ctx;
577
6.07k
        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
6.07k
        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
6.07k
        uint64_t rvalue;
589
6.07k
        if (bmd->flags & DETECT_BYTEMATH_FLAG_RVALUE_VAR) {
590
6.07k
            rvalue = det_ctx->byte_values[bmd->rvalue];
591
6.07k
        } else {
592
1
            rvalue = bmd->rvalue;
593
1
        }
594
595
6.07k
        uint8_t nbytes;
596
6.07k
        if (bmd->flags & DETECT_BYTEMATH_FLAG_NBYTES_VAR) {
597
0
            nbytes = (uint8_t)det_ctx->byte_values[bmd->nbytes];
598
6.07k
        } else {
599
6.07k
            nbytes = bmd->nbytes;
600
6.07k
        }
601
602
6.07k
        DEBUG_VALIDATE_BUG_ON(buffer_len > UINT16_MAX);
603
6.07k
        if (DetectByteMathDoMatch(det_ctx, smd, s, buffer, (uint16_t)buffer_len, nbytes, rvalue,
604
6.07k
                    &det_ctx->byte_values[bmd->local_id], endian) != 1) {
605
195
            goto no_match;
606
195
        }
607
608
5.88k
        SCLogDebug("[BM] Fetched value for index %d: %"PRIu64,
609
5.88k
                   bmd->local_id, det_ctx->byte_values[bmd->local_id]);
610
5.88k
        goto match;
611
612
27.1k
    } else if (smd->type == DETECT_BSIZE) {
613
614
513
        bool eof = (flags & DETECT_CI_FLAGS_END);
615
513
        const uint64_t data_size = buffer_len + stream_start_offset;
616
513
        int r = DetectBsizeMatch(smd->ctx, data_size, eof);
617
513
        if (r < 0) {
618
338
            det_ctx->discontinue_matching = 1;
619
338
            goto no_match;
620
621
338
        } else if (r == 0) {
622
1
            goto no_match;
623
1
        }
624
174
        goto match;
625
626
26.6k
    } else if (smd->type == DETECT_DATASET) {
627
628
        //PrintRawDataFp(stdout, buffer, buffer_len);
629
15.4k
        const DetectDatasetData *sd = (const DetectDatasetData *) smd->ctx;
630
15.4k
        int r = DetectDatasetBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset?
631
15.4k
        if (r == 1) {
632
236
            goto match;
633
236
        }
634
15.1k
        det_ctx->discontinue_matching = 1;
635
15.1k
        goto no_match;
636
637
15.4k
    } else if (smd->type == DETECT_DATAREP) {
638
639
        //PrintRawDataFp(stdout, buffer, buffer_len);
640
206
        const DetectDatarepData *sd = (const DetectDatarepData *) smd->ctx;
641
206
        int r = DetectDatarepBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset?
642
206
        if (r == 1) {
643
0
            goto match;
644
0
        }
645
206
        det_ctx->discontinue_matching = 1;
646
206
        goto no_match;
647
648
11.0k
    } else if (smd->type == DETECT_AL_URILEN) {
649
38
        SCLogDebug("inspecting uri len");
650
651
38
        int r = 0;
652
38
        DetectUrilenData *urilend = (DetectUrilenData *) smd->ctx;
653
38
        if (buffer_len > UINT16_MAX) {
654
0
            r = DetectU16Match(UINT16_MAX, &urilend->du16);
655
38
        } else {
656
38
            r = DetectU16Match((uint16_t)buffer_len, &urilend->du16);
657
38
        }
658
659
38
        if (r == 1) {
660
2
            goto match;
661
2
        }
662
663
36
        det_ctx->discontinue_matching = 1;
664
665
36
        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
11.0k
    } else if (smd->type == DETECT_BASE64_DECODE) {
681
11.0k
        if (DetectBase64DecodeDoMatch(det_ctx, s, smd, buffer, buffer_len)) {
682
4.95k
            if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) {
683
110
                KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
684
110
                if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) {
685
                    /* Base64 is a terminal list. */
686
4
                    goto final_match;
687
4
                }
688
110
            }
689
4.95k
        }
690
11.0k
    } else {
691
0
        SCLogDebug("sm->type %u", smd->type);
692
#ifdef DEBUG
693
        BUG_ON(1);
694
#endif
695
0
    }
696
697
152k
no_match:
698
152k
    KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
699
152k
    SCReturnInt(0);
700
701
421k
match:
702
    /* this sigmatch matched, inspect the next one. If it was the last,
703
     * the buffer portion of the signature matched. */
704
421k
    if (!smd->is_last) {
705
83.4k
        KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
706
83.4k
        uint8_t r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd + 1, p, f, buffer,
707
83.4k
                buffer_len, stream_start_offset, flags, inspection_mode);
708
83.4k
        SCReturnInt(r);
709
83.4k
    }
710
337k
final_match:
711
337k
    KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
712
337k
    SCReturnInt(1);
713
421k
}
714
715
#ifdef UNITTESTS
716
#include "tests/detect-engine-content-inspection.c"
717
#endif