Coverage Report

Created: 2026-08-14 07:34

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
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