• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.61
/src/detect-bytejump.c
1
/* Copyright (C) 2007-2020 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 Brian Rectanus <brectanu@gmail.com>
22
 *
23
 * Implements byte_jump keyword.
24
 */
25

26
#include "suricata-common.h"
27
#include "decode.h"
28
#include "detect.h"
29
#include "detect-parse.h"
30
#include "detect-engine.h"
31
#include "detect-engine-buffer.h"
32
#include "app-layer.h"
33

34
#include "detect-byte.h"
35
#include "detect-byte-extract.h"
36
#include "detect-bytejump.h"
37
#include "detect-content.h"
38
#include "detect-uricontent.h"
39

40
#include "util-byte.h"
41
#include "util-unittest.h"
42
#include "util-debug.h"
43
#include "util-validate.h"
44
#include "detect-pcre.h"
45
#include "detect-engine-build.h"
46

47
/**
48
 * \brief Regex for parsing our options
49
 */
50
#define PARSE_REGEX                                                                                \
51
    "^\\s*"                                                                                        \
3✔
52
    "([^\\s,]+\\s*,\\s*[^\\s,]+)"                                                                  \
3✔
53
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
54
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
55
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
56
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
57
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
58
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
59
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
60
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
61
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
62
    "(?:\\s*,\\s*((?:multiplier|post_offset|bitmask)\\s+[^\\s,]+|[^\\s,]+))?"                      \
3✔
63
    "\\s*$"
3✔
64

65
static DetectParseRegex parse_regex;
66

67
static DetectBytejumpData *DetectBytejumpParse(
68
        DetectEngineCtx *de_ctx, const char *optstr, char **nbytes, char **offset);
69
static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr);
70
static void DetectBytejumpFree(DetectEngineCtx*, void *ptr);
71
#ifdef UNITTESTS
72
static void DetectBytejumpRegisterTests(void);
73
#endif
74

75
void DetectBytejumpRegister (void)
76
{
3✔
77
    sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump";
3✔
78
    sigmatch_table[DETECT_BYTEJUMP].desc = "allow the ability to select a <num of bytes> from an <offset> and move the detection pointer to that position";
3✔
79
    sigmatch_table[DETECT_BYTEJUMP].url = "/rules/payload-keywords.html#byte-jump";
3✔
80
    sigmatch_table[DETECT_BYTEJUMP].Match = NULL;
3✔
81
    sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup;
3✔
82
    sigmatch_table[DETECT_BYTEJUMP].Free  = DetectBytejumpFree;
3✔
83
#ifdef UNITTESTS
84
    sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests;
85
#endif
86
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
3✔
87
}
3✔
88

89
/* 23 - This is the largest string (octal, with a zero prefix) that
90
 *      will not overflow uint64_t.  The only way this length
91
 *      could be over 23 and still not overflow is if it were zero
92
 *      prefixed and we only support 1 byte of zero prefix for octal.
93
 *
94
 * "01777777777777777777777" = 0xffffffffffffffff
95
 *
96
 * 8 - Without string, the maximum byte extract count is 8.
97
 */
98
static inline bool DetectBytejumpValidateNbytesOnly(const DetectBytejumpData *data, int32_t nbytes)
99
{
18,692✔
100
    return (data->flags & DETECT_BYTEJUMP_STRING && nbytes <= 23) || (nbytes <= 8);
18,692✔
101
}
18,692✔
102

103
static bool DetectBytejumpValidateNbytes(const DetectBytejumpData *data, int32_t nbytes)
104
{
18,690✔
105
    if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
18,690✔
106
        if (data->flags & DETECT_BYTEJUMP_STRING) {
175✔
107
            /* 23 - This is the largest string (octal, with a zero prefix) that
108
             *      will not overflow uint64_t.  The only way this length
109
             *      could be over 23 and still not overflow is if it were zero
110
             *      prefixed and we only support 1 byte of zero prefix for octal.
111
             *
112
             * "01777777777777777777777" = 0xffffffffffffffff
113
             */
114
            if (nbytes > 23) {
136✔
115
                SCLogError("Cannot test more than 23 bytes "
136✔
116
                           "with \"string\"");
136✔
117
            }
136✔
118
        } else {
136✔
119
            if (nbytes > 8) {
39✔
120
                SCLogError("Cannot test more than 8 bytes "
39✔
121
                           "without \"string\"");
39✔
122
            }
39✔
123
        }
39✔
124
        return false;
175✔
125
    }
175✔
126

127
    return true;
18,515✔
128
}
18,690✔
129

130
/** \brief Byte jump match function
131
 *  \param det_ctx thread detect engine ctx
132
 *  \param s signature
133
 *  \param m byte jump sigmatch
134
 *  \param payload ptr to the payload
135
 *  \param payload_len length of the payload
136
 *  \retval true match
137
 *  \retval false no match
138
 */
139
bool DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
140
        const SigMatchCtx *ctx, const uint8_t *payload, uint32_t payload_len, uint16_t flags,
141
        int32_t nbytes, int32_t offset)
142
{
3,203✔
143
    SCEnter();
3,203✔
144

145
    const DetectBytejumpData *data = (const DetectBytejumpData *)ctx;
3,203✔
146
    const uint8_t *ptr = NULL;
3,203✔
147
    int32_t len = 0;
3,203✔
148
    uint64_t val = 0;
3,203✔
149
    int extbytes;
3,203✔
150

151
    if (payload_len == 0) {
3,203✔
152
        SCReturnBool(false);
305✔
153
    }
305✔
154

155
    /* Validate the number of bytes we are testing
156
     * If the validation is successful, we know that
157
     * it contains a value <= 23. Thus, we can
158
     * safely cast it when extracting bytes
159
     */
160
    if (data->flags & DETECT_BYTEJUMP_NBYTES_VAR) {
2,898✔
161
        if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
2✔
162
            SCLogDebug("Invalid byte_jump nbytes "
1✔
163
                       "seen in byte_jump - %d",
1✔
164
                    nbytes);
1✔
165
            SCReturnBool(false);
1✔
166
        }
1✔
167
    }
2✔
168

169
    /* Calculate the ptr value for the bytejump and length remaining in
170
     * the packet from that point.
171
     */
172
    ptr = payload + offset;
2,897✔
173
    len = payload_len - offset;
2,897✔
174
    if (flags & DETECT_BYTEJUMP_RELATIVE) {
2,897✔
175
        ptr += det_ctx->buffer_offset;
15✔
176
        len -= det_ctx->buffer_offset;
15✔
177

178
        SCLogDebug("[relative] after: ptr %p [len %d]", ptr, len);
15✔
179

180
        /* No match if there is no relative base */
181
        if (ptr == NULL || (nbytes && len <= 0)) {
15✔
182
            SCReturnBool(false);
×
183
        }
×
184
    }
15✔
185

186
    /* Verify the to-be-extracted data is within the packet */
187
    if (ptr < payload || nbytes > len) {
2,897✔
188
        SCLogDebug("Data not within payload "
1,644✔
189
                   "pkt=%p, ptr=%p, len=%" PRIi32 ", nbytes=%" PRIi32,
1,644✔
190
                payload, ptr, len, nbytes);
1,644✔
191
        SCReturnBool(false);
1,644✔
192
    }
1,644✔
193

194
    /* Extract the byte data */
195
    if (flags & DETECT_BYTEJUMP_STRING) {
1,253✔
196
        extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr);
1,251✔
197
        if(extbytes <= 0) {
1,251✔
198
            SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes);
1,162✔
199
            SCReturnBool(false);
1,162✔
200
        }
1,162✔
201
    }
1,251✔
202
    else {
2✔
203
        int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN;
2✔
204
        extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr);
2✔
205
        if (extbytes != nbytes) {
2✔
206
            SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes);
×
207
            SCReturnBool(false);
×
208
        }
×
209
    }
2✔
210

211
    SCLogDebug("VAL: (%" PRIu64 " x %" PRIu32 ") + %" PRIi32 " + %" PRId32, val, data->multiplier,
91✔
212
            extbytes, data->post_offset);
91✔
213

214
    /* Apply the bitmask value and bitmask shift count; note, the bitmask is applied
215
     * before the multiplier per snort */
216
    if (data->flags & DETECT_BYTEJUMP_BITMASK) {
91✔
UNCOV
217
        SCLogDebug("[before bitmask] val: %" PRIi64 " bitmask_value: %" PRIx32, val,
×
UNCOV
218
                data->bitmask_value);
×
UNCOV
219
        val &= data->bitmask_value;
×
UNCOV
220
        if (val && data->bitmask_shift_count) {
×
UNCOV
221
            val = val >> data->bitmask_shift_count;
×
UNCOV
222
        }
×
UNCOV
223
        SCLogDebug("[after bitmask] val: %" PRIi64 " bitmask_value: %" PRIx32, val,
×
UNCOV
224
                data->bitmask_value);
×
UNCOV
225
    }
×
226

227
    /* Adjust the jump value based on flags */
228
    val *= data->multiplier;
91✔
229
    if (flags & DETECT_BYTEJUMP_ALIGN) {
91✔
230
        if ((val % 4) != 0) {
×
231
            val += 4 - (val % 4);
×
232
        }
×
233
    }
×
234

235
    val += data->post_offset;
91✔
236
    SCLogDebug("val: %" PRIi64 " post_offset: %" PRIi32, val, data->post_offset);
91✔
237

238
    const uint8_t *jumpptr;
91✔
239
    /* Calculate the jump location */
240
    if (flags & DETECT_BYTEJUMP_BEGIN) {
91✔
UNCOV
241
        jumpptr = payload + (int64_t)val;
×
UNCOV
242
        SCLogDebug("NEWVAL: payload %p + %" PRIi64 " = %p", payload, (int64_t)val, jumpptr + val);
×
243
    } else if (flags & DETECT_BYTEJUMP_END) {
91✔
244
        jumpptr = payload + payload_len + (int64_t)val;
10✔
245
        SCLogDebug(
10✔
246
                "NEWVAL: payload %p + %" PRIu32 " + %" PRIi64, payload, payload_len, (int64_t)val);
10✔
247
    } else {
81✔
248
        jumpptr = ptr + (int64_t)val + extbytes;
81✔
249
        SCLogDebug("NEWVAL: ptr %p + %" PRIi64 " = %p", ptr, val, jumpptr);
81✔
250
    }
81✔
251

252
    /* Validate that the jump location is still in the packet
253
     * \todo Should this validate it is still in the *payload*?
254
     */
255
    if (jumpptr < payload) {
91✔
256
        jumpptr = payload;
2✔
257
        SCLogDebug("jump location is before buffer start; resetting to buffer start");
2✔
258
    } else if (jumpptr > (payload + payload_len)) {
89✔
259
        SCLogDebug("Jump location (%" PRIu64 ") is not within payload (%" PRIu32 ")",
17✔
260
                payload_len + val, payload_len);
17✔
261
        SCReturnBool(false);
17✔
262
    }
17✔
263

264
#ifdef DEBUG
265
    if (SCLogDebugEnabled()) {
266
        const uint8_t *sptr = (flags & DETECT_BYTEJUMP_BEGIN) ? payload : ptr;
267
        SCLogDebug("jumping %" PRId64 " bytes from %p (%08x)", val, sptr, (int)(sptr - payload));
268
    }
269
#endif /* DEBUG */
270

271
    /* Adjust the detection context to the jump location. */
272
    DEBUG_VALIDATE_BUG_ON(jumpptr < payload);
74✔
273
    det_ctx->buffer_offset = (uint32_t)(jumpptr - payload);
74✔
274

275
    SCReturnBool(true);
74✔
276
}
91✔
277

278
static DetectBytejumpData *DetectBytejumpParse(
279
        DetectEngineCtx *de_ctx, const char *optstr, char **nbytes_str, char **offset)
280
{
27,974✔
281
    DetectBytejumpData *data = NULL;
27,974✔
282
    char args[11][64];
27,974✔
283
    int res = 0;
27,974✔
284
    size_t pcre2len;
27,974✔
285
    int numargs = 0;
27,974✔
286
    int i = 0;
27,974✔
287
    uint32_t nbytes = 0;
27,974✔
288
    char *str_ptr;
27,974✔
289
    char *end_ptr;
27,974✔
290
    pcre2_match_data *match = NULL;
27,974✔
291

292
    memset(args, 0x00, sizeof(args));
27,974✔
293

294
    /* Execute the regex and populate args with captures. */
295
    int ret = DetectParsePcreExec(&parse_regex, &match, optstr, 0, 0);
27,974✔
296
    if (ret < 2 || ret > 11) {
27,974✔
297
        SCLogError("parse error, ret %" PRId32 ", string \"%s\"", ret, optstr);
1,959✔
298
        goto error;
1,959✔
299
    }
1,959✔
300

301
    /* The first two arguments are stashed in the first PCRE substring.
302
     * This is because byte_jump can take 10 arguments, but PCRE only
303
     * supports 9 substrings, sigh.
304
     */
305
    char str[512] = "";
26,015✔
306
    pcre2len = sizeof(str);
26,015✔
307
    res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str, &pcre2len);
26,015✔
308
    if (res < 0) {
26,015✔
309
        SCLogError("pcre2_substring_copy_bynumber failed "
19✔
310
                   "for arg 1");
19✔
311
        goto error;
19✔
312
    }
19✔
313

314
    /* Break up first substring into two parameters
315
     *
316
     * NOTE: Because of this, we cannot free args[1] as it is part of args[0],
317
     * and *yes* this *is* ugly.
318
     */
319
    end_ptr = str;
25,996✔
320
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++;
58,822✔
321
    *(end_ptr++) = '\0';
25,996✔
322
    strlcpy(args[0], str, sizeof(args[0]));
25,996✔
323
    numargs++;
25,996✔
324

325
    str_ptr = end_ptr;
25,996✔
326
    while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++;
27,332✔
327
    end_ptr = str_ptr;
25,996✔
328
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0'))
172,455✔
329
        end_ptr++;
146,459✔
330
    *(end_ptr++) = '\0';
25,996✔
331
    strlcpy(args[1], str_ptr, sizeof(args[1]));
25,996✔
332
    numargs++;
25,996✔
333

334
    /* The remaining args are directly from PCRE substrings */
335
    for (i = 1; i < (ret - 1); i++) {
95,624✔
336
        pcre2len = sizeof(args[0]);
69,644✔
337
        res = pcre2_substring_copy_bynumber(match, i + 1, (PCRE2_UCHAR8 *)args[i + 1], &pcre2len);
69,644✔
338
        if (res < 0) {
69,644✔
339
            SCLogError("pcre2_substring_copy_bynumber failed for arg %d", i + 1);
16✔
340
            goto error;
16✔
341
        }
16✔
342
        numargs++;
69,628✔
343
    }
69,628✔
344

345
    /* Initialize the data */
346
    data = SCMalloc(sizeof(DetectBytejumpData));
25,980✔
347
    if (unlikely(data == NULL))
25,980✔
348
        goto error;
×
349
    data->base = DETECT_BYTEJUMP_BASE_UNSET;
25,980✔
350
    data->flags = 0;
25,980✔
351
    data->multiplier = 1;
25,980✔
352
    data->post_offset = 0;
25,980✔
353

354
    /*
355
     * The first two options are required and positional.  The
356
     * remaining arguments are flags and are not positional.
357
     */
358

359
    /* Number of bytes */
360
    if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) {
25,980✔
361
        if (nbytes_str == NULL) {
361✔
362
            SCLogError("byte_jump supplied with "
×
363
                       "var name for nbytes.  \"value\" argument supplied to "
×
364
                       "this function has to be non-NULL");
×
365
            goto error;
×
366
        }
×
367
        *nbytes_str = SCStrdup(args[0]);
361✔
368
        if (*nbytes_str == NULL)
361✔
369
            goto error;
×
370
        data->flags |= DETECT_BYTEJUMP_NBYTES_VAR;
361✔
371
    } else {
25,619✔
372
        if (StringParseUint32(&nbytes, 10, (uint16_t)strlen(args[0]), args[0]) <= 0) {
25,619✔
373
            SCLogError("Malformed number of bytes: %s", optstr);
900✔
374
            goto error;
900✔
375
        }
900✔
376
    }
25,619✔
377

378
    /* Offset */
379
    if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) {
25,080✔
380
        if (offset == NULL) {
1,809✔
381
            SCLogError("byte_jump supplied with "
×
382
                       "var name for offset.  \"value\" argument supplied to "
×
383
                       "this function has to be non-NULL");
×
384
            goto error;
×
385
        }
×
386
        *offset = SCStrdup(args[1]);
1,809✔
387
        if (*offset == NULL)
1,809✔
388
            goto error;
×
389
    } else {
23,271✔
390
        if (StringParseI32RangeCheck(
23,271✔
391
                    &data->offset, 10, (uint16_t)strlen(args[1]), args[1], -65535, 65535) <= 0) {
23,271✔
392
            SCLogError("Malformed offset: %s", optstr);
2,477✔
393
            goto error;
2,477✔
394
        }
2,477✔
395
    }
23,271✔
396

397
    /* The remaining options are flags. */
398
    /** \todo Error on dups? */
399
    for (i = 2; i < numargs; i++) {
76,677✔
400
        if (strcmp("relative", args[i]) == 0) {
57,690✔
401
            data->flags |= DETECT_BYTEJUMP_RELATIVE;
11,923✔
402
        } else if (strcasecmp("string", args[i]) == 0) {
45,767✔
403
            data->flags |= DETECT_BYTEJUMP_STRING;
16,568✔
404
        } else if (strcasecmp("dec", args[i]) == 0) {
29,199✔
405
            data->base |= DETECT_BYTEJUMP_BASE_DEC;
7,249✔
406
        } else if (strcasecmp("hex", args[i]) == 0) {
21,950✔
407
            data->base |= DETECT_BYTEJUMP_BASE_HEX;
20✔
408
        } else if (strcasecmp("oct", args[i]) == 0) {
21,930✔
409
            data->base |= DETECT_BYTEJUMP_BASE_OCT;
16✔
410
        } else if (strcasecmp("big", args[i]) == 0) {
21,914✔
411
            if (data->flags & DETECT_BYTEJUMP_LITTLE) {
48✔
412
                data->flags ^= DETECT_BYTEJUMP_LITTLE;
1✔
413
            }
1✔
414
            data->flags |= DETECT_BYTEJUMP_BIG;
48✔
415
        } else if (strcasecmp("little", args[i]) == 0) {
21,866✔
416
            data->flags |= DETECT_BYTEJUMP_LITTLE;
1,688✔
417
        } else if (strcasecmp("from_beginning", args[i]) == 0) {
20,178✔
418
            data->flags |= DETECT_BYTEJUMP_BEGIN;
86✔
419
        } else if (strcasecmp("from_end", args[i]) == 0) {
20,092✔
420
            data->flags |= DETECT_BYTEJUMP_END;
7,880✔
421
        } else if (strcasecmp("align", args[i]) == 0) {
12,212✔
422
            data->flags |= DETECT_BYTEJUMP_ALIGN;
11✔
423
        } else if (strncasecmp("multiplier ", args[i], 11) == 0) {
12,201✔
424
            if (StringParseU16RangeCheck(&data->multiplier, 10, (uint16_t)strlen(args[i]) - 11,
337✔
425
                        args[i] + 11, 1, 65535) <= 0) {
337✔
426
                SCLogError("Malformed multiplier: %s", optstr);
75✔
427
                goto error;
75✔
428
            }
75✔
429
        } else if (strncasecmp("post_offset ", args[i], 12) == 0) {
11,864✔
430
            if (StringParseI32RangeCheck(&data->post_offset, 10, (uint16_t)strlen(args[i]) - 12,
7,577✔
431
                        args[i] + 12, -65535, 65535) <= 0) {
7,577✔
432
                SCLogError("Malformed post_offset: %s", optstr);
347✔
433
                goto error;
347✔
434
            }
347✔
435
            SCLogDebug("post_offset: %s [%d]", optstr, data->post_offset);
7,230✔
436
        } else if (strncasecmp("bitmask ", args[i], 8) == 0) {
7,230✔
UNCOV
437
            data->flags |= DETECT_BYTEJUMP_BITMASK;
×
UNCOV
438
            if (ByteExtractStringUint32(&data->bitmask_value, 0, 0, args[i] + strlen("bitmask ")) <=
×
UNCOV
439
                    0) {
×
440
                SCLogError("Malformed bitmask: %s", optstr);
×
441
                goto error;
×
442
            }
×
UNCOV
443
            if (data->bitmask_value == 0) {
×
UNCOV
444
                SCLogError("Invalid bitmask value: %d", data->bitmask_value);
×
UNCOV
445
                goto error;
×
UNCOV
446
            }
×
447
        } else if (strcasecmp("dce", args[i]) == 0) {
4,287✔
448
            data->flags |= DETECT_BYTEJUMP_DCE;
1,093✔
449
        } else {
3,194✔
450
            SCLogError("Unknown option: \"%s\"", args[i]);
3,194✔
451
            goto error;
3,194✔
452
        }
3,194✔
453
    }
57,690✔
454

455
    if ((data->flags & DETECT_BYTEJUMP_END) && (data->flags & DETECT_BYTEJUMP_BEGIN)) {
18,987✔
456
        SCLogError("'from_end' and 'from_beginning' "
83✔
457
                   "cannot be used in the same byte_jump statement");
83✔
458
        goto error;
83✔
459
    }
83✔
460

461
    if (!(data->flags & DETECT_BYTEJUMP_NBYTES_VAR)) {
18,904✔
462
        if (!DetectBytejumpValidateNbytes(data, nbytes)) {
18,690✔
463
            goto error;
175✔
464
        }
175✔
465

466
        /* This is max 23 so it will fit in a byte (see validation function) */
467
        data->nbytes = (uint8_t)nbytes;
18,515✔
468
    }
18,515✔
469
    if (!(data->flags & DETECT_BYTEJUMP_STRING)) {
18,729✔
470
        if (data->base != DETECT_BYTEJUMP_BASE_UNSET) {
3,878✔
471
            SCLogError("Cannot use a base "
35✔
472
                       "without \"string\": %s",
35✔
473
                    optstr);
35✔
474
            goto error;
35✔
475
        }
35✔
476
    }
3,878✔
477

478
    data->bitmask_shift_count = 0;
18,694✔
479
    if (data->flags & DETECT_BYTEJUMP_BITMASK) {
18,694✔
UNCOV
480
        uint32_t bmask = data->bitmask_value;
×
UNCOV
481
        while (!(bmask & 0x1)) {
×
UNCOV
482
            bmask = bmask >> 1;
×
UNCOV
483
            data->bitmask_shift_count++;
×
UNCOV
484
        }
×
UNCOV
485
        SCLogDebug("bitmask value 0x%x -> shift value %d", data->bitmask_value,
×
UNCOV
486
                data->bitmask_shift_count);
×
UNCOV
487
    }
×
488

489
    pcre2_match_data_free(match);
18,694✔
490
    return data;
18,694✔
491

492
error:
9,280✔
493
    if (offset != NULL && *offset != NULL) {
9,280✔
494
        SCFree(*offset);
557✔
495
        *offset = NULL;
557✔
496
    }
557✔
497
    if (nbytes_str != NULL && *nbytes_str != NULL) {
9,280✔
498
        SCFree(*nbytes_str);
148✔
499
        *nbytes_str = NULL;
148✔
500
    }
148✔
501
    if (data != NULL)
9,280✔
502
        DetectBytejumpFree(de_ctx, data);
7,286✔
503
    if (match) {
9,280✔
504
        pcre2_match_data_free(match);
9,280✔
505
    }
9,280✔
506
    return NULL;
9,280✔
507
}
18,729✔
508

509
static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
510
{
27,974✔
511
    SigMatch *prev_pm = NULL;
27,974✔
512
    DetectBytejumpData *data = NULL;
27,974✔
513
    char *offset = NULL;
27,974✔
514
    char *nbytes = NULL;
27,974✔
515
    int ret = -1;
27,974✔
516

517
    data = DetectBytejumpParse(de_ctx, optstr, &nbytes, &offset);
27,974✔
518
    if (data == NULL)
27,974✔
519
        goto error;
9,280✔
520

521
    int sm_list;
18,694✔
522
    if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
18,694✔
523
        if (DetectBufferGetActiveList(de_ctx, s) == -1)
1,908✔
524
            goto error;
1✔
525

526
        sm_list = s->init_data->list;
1,907✔
527

528
        if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
1,907✔
529
            prev_pm = SCDetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1);
1,072✔
530
        }
1,072✔
531
    } else if (data->flags & DETECT_BYTEJUMP_DCE) {
16,786✔
532
        if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
455✔
533
            prev_pm = SCDetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST,
123✔
534
                    DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1);
123✔
535
            if (prev_pm == NULL) {
123✔
536
                sm_list = DETECT_SM_LIST_PMATCH;
88✔
537
            } else {
88✔
538
                sm_list = SigMatchListSMBelongsTo(s, prev_pm);
35✔
539
                if (sm_list < 0)
35✔
540
                    goto error;
×
541
            }
35✔
542
        } else {
332✔
543
            sm_list = DETECT_SM_LIST_PMATCH;
332✔
544
        }
332✔
545

546
        if (SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0)
455✔
547
            goto error;
329✔
548

549
    } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
16,331✔
550
        prev_pm = SCDetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST,
8,470✔
551
                DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1);
8,470✔
552
        if (prev_pm == NULL) {
8,470✔
553
            sm_list = DETECT_SM_LIST_PMATCH;
3,164✔
554
        } else {
5,306✔
555
            sm_list = SigMatchListSMBelongsTo(s, prev_pm);
5,306✔
556
            if (sm_list < 0)
5,306✔
557
                goto error;
×
558
        }
5,306✔
559

560
    } else {
8,470✔
561
        sm_list = DETECT_SM_LIST_PMATCH;
7,861✔
562
    }
7,861✔
563

564
    if (data->flags & DETECT_BYTEJUMP_DCE) {
18,364✔
565
        if ((data->flags & DETECT_BYTEJUMP_STRING) ||
339✔
566
            (data->flags & DETECT_BYTEJUMP_LITTLE) ||
339✔
567
            (data->flags & DETECT_BYTEJUMP_BIG) ||
339✔
568
            (data->flags & DETECT_BYTEJUMP_BEGIN) ||
339✔
569
            (data->flags & DETECT_BYTEJUMP_END) ||
339✔
570
            (data->base == DETECT_BYTEJUMP_BASE_DEC) ||
339✔
571
            (data->base == DETECT_BYTEJUMP_BASE_HEX) ||
339✔
572
            (data->base == DETECT_BYTEJUMP_BASE_OCT) ) {
339✔
573
            SCLogError("Invalid option. "
59✔
574
                       "A byte_jump keyword with dce holds other invalid modifiers.");
59✔
575
            goto error;
59✔
576
        }
59✔
577
    }
339✔
578

579
    if (nbytes != NULL) {
18,305✔
580
        DetectByteIndexType index;
212✔
581
        if (!DetectByteRetrieveSMVar(nbytes, s, sm_list, &index)) {
212✔
582
            SCLogError("Unknown byte_extract var "
50✔
583
                       "seen in byte_jump - %s",
50✔
584
                    nbytes);
50✔
585
            goto error;
50✔
586
        }
50✔
587
        data->nbytes = index;
162✔
588
        SCFree(nbytes);
162✔
589
        nbytes = NULL;
162✔
590
    }
162✔
591

592
    if (offset != NULL) {
18,255✔
593
        DetectByteIndexType index;
1,213✔
594
        if (!DetectByteRetrieveSMVar(offset, s, sm_list, &index)) {
1,213✔
595
            SCLogError("Unknown byte_extract var "
231✔
596
                       "seen in byte_jump - %s",
231✔
597
                    offset);
231✔
598
            goto error;
231✔
599
        }
231✔
600
        data->offset = index;
982✔
601
        data->flags |= DETECT_BYTEJUMP_OFFSET_VAR;
982✔
602
        SCFree(offset);
982✔
603
        offset = NULL;
982✔
604
    }
982✔
605

606
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_BYTEJUMP, (SigMatchCtx *)data, sm_list) ==
18,024✔
607
            NULL) {
18,024✔
608
        goto error;
×
609
    }
×
610

611
    if (!(data->flags & DETECT_BYTEJUMP_RELATIVE))
18,024✔
612
        goto okay;
8,454✔
613

614
    if (prev_pm == NULL)
9,570✔
615
        goto okay;
3,787✔
616

617
    if (prev_pm->type == DETECT_CONTENT) {
5,783✔
618
        DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
3,889✔
619
        cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
3,889✔
620
    } else if (prev_pm->type == DETECT_PCRE) {
3,889✔
621
        DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
525✔
622
        pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
525✔
623
    }
525✔
624

625
 okay:
18,024✔
626
    ret = 0;
18,024✔
627
    return ret;
18,024✔
628

629
 error:
9,950✔
630
     if (nbytes != NULL) {
9,950✔
631
         SCFree(nbytes);
51✔
632
     }
51✔
633
    if (offset != NULL) {
9,950✔
634
        SCFree(offset);
270✔
635
    }
270✔
636
    DetectBytejumpFree(de_ctx, data);
9,950✔
637
    return ret;
9,950✔
638
}
5,783✔
639

640
/**
641
 * \brief this function will free memory associated with DetectBytejumpData
642
 *
643
 * \param data pointer to DetectBytejumpData
644
 */
645
static void DetectBytejumpFree(DetectEngineCtx *de_ctx, void *ptr)
646
{
35,260✔
647
    if (ptr == NULL)
35,260✔
648
        return;
9,280✔
649

650
    DetectBytejumpData *data = (DetectBytejumpData *)ptr;
25,980✔
651
    SCFree(data);
25,980✔
652
}
25,980✔
653

654

655
/* UNITTESTS */
656
#ifdef UNITTESTS
657
#include "util-unittest-helper.h"
658
static int g_file_data_buffer_id = 0;
659
static int g_dce_stub_data_buffer_id = 0;
660

661
/**
662
 * \test DetectBytejumpTestParse01 is a test to make sure that we return
663
 * "something" when given valid bytejump opt
664
 */
665
static int DetectBytejumpTestParse01(void)
666
{
667
    DetectBytejumpData *data = NULL;
668
    data = DetectBytejumpParse(NULL, "4,0", NULL, NULL);
669
    FAIL_IF_NULL(data);
670

671
    DetectBytejumpFree(NULL, data);
672
    PASS;
673
}
674

675
/**
676
 * \test DetectBytejumpTestParse02 is a test for setting the required opts
677
 */
678
static int DetectBytejumpTestParse02(void)
679
{
680
    DetectBytejumpData *data = NULL;
681
    data = DetectBytejumpParse(NULL, "4, 0", NULL, NULL);
682
    FAIL_IF_NULL(data);
683
    FAIL_IF_NOT(data->nbytes == 4);
684
    FAIL_IF_NOT(data->offset == 0);
685
    FAIL_IF_NOT(data->multiplier == 1);
686
    FAIL_IF_NOT(data->post_offset == 0);
687
    FAIL_IF_NOT(data->flags == 0);
688
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_UNSET);
689

690
    DetectBytejumpFree(NULL, data);
691
    PASS;
692
}
693

694
/**
695
 * \test DetectBytejumpTestParse03 is a test for setting the optional flags
696
 */
697
static int DetectBytejumpTestParse03(void)
698
{
699
    DetectBytejumpData *data = NULL;
700
    data = DetectBytejumpParse(NULL,
701
            " 4,0 , relative , little, string, "
702
            "dec, align, from_beginning",
703
            NULL, NULL);
704
    FAIL_IF_NULL(data);
705
    FAIL_IF_NOT(data->nbytes == 4);
706
    FAIL_IF_NOT(data->offset == 0);
707
    FAIL_IF_NOT(data->multiplier == 1);
708
    FAIL_IF_NOT(data->post_offset == 0);
709
    FAIL_IF_NOT(data->flags ==
710
                (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_STRING |
711
                        DETECT_BYTEJUMP_ALIGN | DETECT_BYTEJUMP_BEGIN));
712
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC);
713

714
    DetectBytejumpFree(NULL, data);
715
    PASS;
716
}
717

718
/**
719
 * \test DetectBytejumpTestParse04 is a test for setting the optional flags
720
 *       with parameters
721
 *
722
 * \todo This fails because we can only have 9 captures and there are 10.
723
 */
724
static int DetectBytejumpTestParse04(void)
725
{
726
    DetectBytejumpData *data = NULL;
727
    data = DetectBytejumpParse(NULL,
728
            " 4,0 , relative , little, string, "
729
            "dec, align, from_beginning , "
730
            "multiplier 2 , post_offset -16 ",
731
            NULL, NULL);
732
    FAIL_IF_NULL(data);
733
    FAIL_IF_NOT(data->nbytes == 4);
734
    FAIL_IF_NOT(data->offset == 0);
735
    FAIL_IF_NOT(data->multiplier == 2);
736
    FAIL_IF_NOT(data->post_offset == -16);
737
    FAIL_IF_NOT(data->flags ==
738
                (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_ALIGN |
739
                        DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BEGIN));
740
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC);
741

742
    DetectBytejumpFree(NULL, data);
743
    PASS;
744
}
745

746
/**
747
 * \test DetectBytejumpTestParse05 is a test for setting base without string
748
 */
749
static int DetectBytejumpTestParse05(void)
750
{
751
    DetectBytejumpData *data = NULL;
752
    data = DetectBytejumpParse(NULL,
753
            " 4,0 , relative , little, dec, "
754
            "align, from_beginning",
755
            NULL, NULL);
756
    FAIL_IF_NOT_NULL(data);
757

758
    PASS;
759
}
760

761
/**
762
 * \test DetectBytejumpTestParse06 is a test for too many bytes to extract
763
 */
764
static int DetectBytejumpTestParse06(void)
765
{
766
    DetectBytejumpData *data = NULL;
767
    data = DetectBytejumpParse(NULL, "9, 0", NULL, NULL);
768
    FAIL_IF_NOT_NULL(data);
769

770
    PASS;
771
}
772

773
/**
774
 * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract
775
 */
776
static int DetectBytejumpTestParse07(void)
777
{
778
    DetectBytejumpData *data = NULL;
779
    data = DetectBytejumpParse(NULL, "24, 0, string, dec", NULL, NULL);
780
    FAIL_IF_NOT_NULL(data);
781

782
    PASS;
783
}
784

785
/**
786
 * \test DetectBytejumpTestParse08 is a test for offset too big
787
 */
788
static int DetectBytejumpTestParse08(void)
789
{
790
    DetectBytejumpData *data = NULL;
791
    data = DetectBytejumpParse(NULL, "4, 0xffffffffffffffff", NULL, NULL);
792
    FAIL_IF_NOT_NULL(data);
793

794
    PASS;
795
}
796

797
/**
798
 * \test Test dce option.
799
 */
800
static int DetectBytejumpTestParse09(void)
801
{
802
    Signature *s = SigAlloc();
803
    FAIL_IF_NULL(s);
804

805
    FAIL_IF(SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0);
806

807
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
808
                        "4,0, align, multiplier 2, "
809
                        "post_offset -16,dce") == 0);
810
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
811
                        "4,0, multiplier 2, "
812
                        "post_offset -16,dce") == 0);
813
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,post_offset -16,dce") == 0);
814
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
815
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
816
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dce") == -1);
817
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, big, dce") == -1);
818
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, little, dce") == -1);
819
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dec, dce") == -1);
820
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1);
821
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1);
822
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1);
823

824
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
825
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
826
    FAIL_IF_NOT_NULL(sm);
827

828
    SigFree(NULL, s);
829
    PASS;
830
}
831

832
/**
833
 * \test Test dce option.
834
 */
835
static int DetectBytejumpTestParse10(void)
836
{
837
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
838
    FAIL_IF_NULL(de_ctx);
839
    de_ctx->flags |= DE_QUIET;
840

841
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
842
                                                 "(msg:\"Testing bytejump_body\"; "
843
                                                 "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
844
                                                 "dce_stub_data; "
845
                                                 "content:\"one\"; distance:0; "
846
                                                 "byte_jump:4,0,align,multiplier 2, "
847
                                                 "post_offset -16,relative,dce; sid:1;)");
848
    FAIL_IF_NULL(s);
849
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
850
    FAIL_IF_NULL(sm);
851
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
852
    FAIL_IF_NULL(sm->next);
853
    sm = sm->next;
854
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
855

856
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
857
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
858
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
859
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
860
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
861
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
862

863
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
864
                                      "(msg:\"Testing bytejump_body\"; "
865
                                      "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
866
                                      "dce_stub_data; "
867
                                      "content:\"one\"; distance:0; "
868
                                      "byte_jump:4,0,align,multiplier 2, "
869
                                      "post_offset -16,relative,dce; sid:2;)");
870
    FAIL_IF_NULL(s);
871
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
872
    FAIL_IF_NULL(sm);
873

874
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
875
    FAIL_IF_NULL(sm->next);
876
    sm = sm->next;
877
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
878

879
    bd = (DetectBytejumpData *)sm->ctx;
880
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
881
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
882
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
883
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
884
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
885

886
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
887
                                      "(msg:\"Testing bytejump_body\"; "
888
                                      "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
889
                                      "dce_stub_data; "
890
                                      "content:\"one\"; distance:0; "
891
                                      "byte_jump:4,0,align,multiplier 2, "
892
                                      "post_offset -16,relative; sid:3;)");
893
    FAIL_IF_NULL(s);
894
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
895
    FAIL_IF_NULL(sm);
896

897
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
898
    FAIL_IF_NULL(sm->next);
899
    sm = sm->next;
900
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
901

902
    bd = (DetectBytejumpData *)sm->ctx;
903
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE);
904
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
905
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
906
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
907
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
908

909
    DetectEngineCtxFree(de_ctx);
910
    PASS;
911
}
912

913
/**
914
 * \test Test dce option.
915
 */
916
static int DetectBytejumpTestParse11(void)
917
{
918
    DetectEngineCtx *de_ctx = NULL;
919
    Signature *s = NULL;
920

921
    de_ctx = DetectEngineCtxInit();
922
    FAIL_IF_NULL(de_ctx);
923

924
    de_ctx->flags |= DE_QUIET;
925
    s = SigInit(de_ctx, "alert tcp any any -> any any "
926
                "(msg:\"Testing bytejump_body\"; "
927
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
928
                "dce_stub_data; "
929
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
930
                "post_offset -16,string,dce; sid:1;)");
931
    FAIL_IF_NOT_NULL(s);
932

933
    s = SigInit(de_ctx, "alert tcp any any -> any any "
934
                "(msg:\"Testing bytejump_body\"; "
935
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
936
                "dce_sub_data; "
937
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
938
                "post_offset -16,big,dce; sid:1;)");
939
    FAIL_IF_NOT_NULL(s);
940

941
    s = SigInit(de_ctx, "alert tcp any any -> any any "
942
                "(msg:\"Testing bytejump_body\"; "
943
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
944
                "dce_stub_data; "
945
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
946
                "post_offset -16,little,dce; sid:1;)");
947
    FAIL_IF_NOT_NULL(s);
948

949
    s = SigInit(de_ctx, "alert tcp any any -> any any "
950
                "(msg:\"Testing bytejump_body\"; "
951
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
952
                "dce_stub_data; "
953
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
954
                "post_offset -16,string,hex,dce; sid:1;)");
955
    FAIL_IF_NOT_NULL(s);
956

957
    s = SigInit(de_ctx, "alert tcp any any -> any any "
958
                "(msg:\"Testing bytejump_body\"; "
959
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
960
                "dce_stub_data; "
961
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
962
                "post_offset -16,string,dec,dce; sid:1;)");
963
    FAIL_IF_NOT_NULL(s);
964

965
    s = SigInit(de_ctx, "alert tcp any any -> any any "
966
                "(msg:\"Testing bytejump_body\"; "
967
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
968
                "dce_stub_data; "
969
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
970
                "post_offset -16,string,oct,dce; sid:1;)");
971
    FAIL_IF_NOT_NULL(s);
972

973
    s = SigInit(de_ctx, "alert tcp any any -> any any "
974
                "(msg:\"Testing bytejump_body\"; "
975
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
976
                "dce_stub_data; "
977
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
978
                "post_offset -16,from_beginning,dce; sid:1;)");
979
    FAIL_IF_NOT_NULL(s);
980

981
    SigGroupCleanup(de_ctx);
982
    SigCleanSignatures(de_ctx);
983
    DetectEngineCtxFree(de_ctx);
984
    PASS;
985
}
986

987
/**
988
 * \test Test file_data
989
 */
990
static int DetectBytejumpTestParse12(void)
991
{
992
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
993
    FAIL_IF_NULL(de_ctx);
994
    de_ctx->flags |= DE_QUIET;
995

996
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
997
                                                 "(file_data; byte_jump:4,0,align,multiplier 2, "
998
                                                 "post_offset -16,relative; sid:1;)");
999
    FAIL_IF_NULL(s);
1000

1001
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_file_data_buffer_id);
1002
    FAIL_IF_NULL(sm);
1003
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
1004

1005
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
1006
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE);
1007
    FAIL_IF((bd->flags &
1008
                    (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG)) ==
1009
            (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG));
1010

1011
    DetectEngineCtxFree(de_ctx);
1012
    PASS;
1013
}
1014

1015
static int DetectBytejumpTestParse13(void)
1016
{
1017
    DetectBytejumpData *data = DetectBytejumpParse(NULL,
1018
            " 4,0 , relative , little, string, dec, "
1019
            "align, from_end",
1020
            NULL, NULL);
1021
    FAIL_IF_NULL(data);
1022
    FAIL_IF_NOT(data->flags & DETECT_BYTEJUMP_END);
1023

1024
    DetectBytejumpFree(NULL, data);
1025

1026
    PASS;
1027
}
1028

1029
static int DetectBytejumpTestParse14(void)
1030
{
1031
    DetectBytejumpData *data = DetectBytejumpParse(NULL,
1032
            " 4,0 , relative , little, string, dec, "
1033
            "align, from_beginning, from_end",
1034
            NULL, NULL);
1035

1036
    FAIL_IF_NOT_NULL(data);
1037

1038
    PASS;
1039
}
1040

1041
static int DetectBytejumpTestParse15(void)
1042
{
1043
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1044
    FAIL_IF_NULL(de_ctx);
1045
    de_ctx->flags |= DE_QUIET;
1046

1047
    Signature *s =
1048
            DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1049
                                          "(msg:\"Testing bytejump_body\"; "
1050
                                          "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1051
                                          "dce_stub_data; "
1052
                                          "content:\"one\"; distance:0; "
1053
                                          "byte_jump:4,0,align,multiplier 2, "
1054
                                          "post_offset -16,relative,bitmask 0x8f40,dce; sid:1;)");
1055
    FAIL_IF_NULL(s);
1056
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1057
    FAIL_IF_NULL(sm);
1058
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1059
    FAIL_IF_NULL(sm->next);
1060
    sm = sm->next;
1061
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
1062

1063
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
1064
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
1065
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
1066
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
1067
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
1068
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
1069

1070
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_BITMASK);
1071
    FAIL_IF_NOT(bd->bitmask_value == 0x8f40);
1072
    FAIL_IF_NOT(bd->bitmask_shift_count == 6);
1073

1074
    DetectEngineCtxFree(de_ctx);
1075
    PASS;
1076
}
1077

1078
static int DetectBytejumpTestParse16(void)
1079
{
1080
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1081
    FAIL_IF_NULL(de_ctx);
1082
    de_ctx->flags |= DE_QUIET;
1083

1084
    Signature *s =
1085
            DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1086
                                          "(msg:\"Testing bytejump_body\"; "
1087
                                          "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1088
                                          "dce_stub_data; "
1089
                                          "content:\"one\"; distance:0; "
1090
                                          "byte_jump:4,0,align,multiplier 2, "
1091
                                          "post_offset -16,relative,bitmask 5304,dce; sid:1;)");
1092
    FAIL_IF_NULL(s);
1093
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1094
    FAIL_IF_NULL(sm);
1095
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1096
    FAIL_IF_NULL(sm->next);
1097
    sm = sm->next;
1098
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
1099

1100
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
1101
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
1102
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
1103
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
1104
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
1105
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
1106

1107
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_BITMASK);
1108
    FAIL_IF_NOT(bd->bitmask_value == 5304);
1109
    FAIL_IF_NOT(bd->bitmask_shift_count == 3);
1110

1111
    DetectEngineCtxFree(de_ctx);
1112
    PASS;
1113
}
1114

1115
/**
1116
 * \test DetectByteJumpTestPacket01 is a test to check matches of
1117
 * byte_jump and byte_jump relative works if the previous keyword is pcre
1118
 * (bug 142)
1119
 */
1120
static int DetectByteJumpTestPacket01 (void)
1121
{
1122
    uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0"
1123
                    "User-Agent: Wget/1.11.4"
1124
                    "Accept: */*"
1125
                    "Host: www.google.com"
1126
                    "Connection: Keep-Alive"
1127
                    "Date: Mon, 04 Jan 2010 17:29:39 GMT";
1128
    uint16_t buflen = strlen((char *)buf);
1129
    Packet *p;
1130
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1131

1132
    FAIL_IF_NULL(p);
1133

1134
    char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + "
1135
    "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6,"
1136
    "relative,string,dec; content:\"0\"; sid:134; rev:1;)";
1137

1138
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1139

1140
    UTHFreePacket(p);
1141
    PASS;
1142
}
1143

1144
/**
1145
 * \test DetectByteJumpTestPacket02 is a test to check matches of
1146
 * byte_jump and byte_jump relative works if the previous keyword is byte_jump
1147
 * (bug 165)
1148
 */
1149
static int DetectByteJumpTestPacket02 (void)
1150
{
1151
    uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53,
1152
                    0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18,
1153
                    0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1154
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1155
                    0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff,
1156
                    0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00,
1157
                    0x00, 0xff };
1158
    uint16_t buflen = sizeof(buf);
1159
    Packet *p;
1160
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1161

1162
    FAIL_IF_NULL(p);
1163

1164
    char sig[] = "alert tcp any any -> any any (msg:\"byte_jump with byte_jump"
1165
                 " + relative\"; byte_jump:1,13; byte_jump:4,0,relative; "
1166
                 "content:\"|48 00 00|\"; within:3; sid:144; rev:1;)";
1167

1168
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1169

1170
    UTHFreePacket(p);
1171
    PASS;
1172
}
1173

1174
static int DetectByteJumpTestPacket03(void)
1175
{
1176
    uint8_t *buf = NULL;
1177
    uint16_t buflen = 0;
1178
    buf = SCMalloc(4);
1179
    if (unlikely(buf == NULL)) {
1180
        printf("malloc failed\n");
1181
        exit(EXIT_FAILURE);
1182
    }
1183
    memcpy(buf, "boom", 4);
1184
    buflen = 4;
1185

1186
    Packet *p;
1187
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1188

1189
    FAIL_IF_NULL(p);
1190

1191
    char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; "
1192
        "byte_jump:1,214748364; sid:1; rev:1;)";
1193

1194
    FAIL_IF(UTHPacketMatchSig(p, sig));
1195

1196
    UTHFreePacket(p);
1197
    FAIL_IF_NULL(buf);
1198

1199
    SCFree(buf);
1200
    PASS;
1201
}
1202

1203
/**
1204
 * \test check matches of with from_beginning (bug 626/627)
1205
 */
1206
static int DetectByteJumpTestPacket04 (void)
1207
{
1208
    uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1209
    uint16_t buflen = strlen((char *)buf);
1210
    Packet *p;
1211
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1212

1213
    FAIL_IF_NULL(p);
1214

1215
    char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"ABCD\"; distance:0; within:4; sid:1; rev:1;)";
1216

1217
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1218

1219
    UTHFreePacket(p);
1220
    PASS;
1221
}
1222

1223
/**
1224
 * \test check matches of with from_beginning (bug 626/627)
1225
 */
1226
static int DetectByteJumpTestPacket05 (void)
1227
{
1228
    uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1229
    uint16_t buflen = strlen((char *)buf);
1230
    Packet *p;
1231
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1232

1233
    FAIL_IF_NULL(p);
1234

1235
    char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"cdABCD\"; within:6; sid:1; rev:1;)";
1236

1237
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 0 : 1);
1238

1239
    UTHFreePacket(p);
1240
    PASS;
1241
}
1242

1243
/**
1244
 * \test check matches of with from_beginning (bug 626/627)
1245
 */
1246
static int DetectByteJumpTestPacket06 (void)
1247
{
1248
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1249
    uint16_t buflen = strlen((char *)buf);
1250
    Packet *p;
1251
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1252

1253
    FAIL_IF_NULL(p);
1254

1255
    char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"ABCD\"; distance:4; within:4; sid:1; rev:1;)";
1256

1257
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1258

1259
    UTHFreePacket(p);
1260
    PASS;
1261
}
1262

1263
/**
1264
 * \test check matches of with from_beginning (bug 626/627)
1265
 */
1266
static int DetectByteJumpTestPacket07 (void)
1267
{
1268
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1269
    uint16_t buflen = strlen((char *)buf);
1270
    Packet *p;
1271
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1272

1273
    FAIL_IF_NULL(p);
1274

1275
    char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"abcdABCD\"; distance:0; within:8; sid:1; rev:1;)";
1276

1277
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 1 : 0);
1278

1279
    UTHFreePacket(p);
1280
    PASS;
1281
}
1282

1283
/**
1284
 * \test check matches of with from_end
1285
 */
1286
static int DetectByteJumpTestPacket08 (void)
1287
{
1288
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1289
    uint16_t buflen = strlen((char *)buf);
1290
    Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1291

1292
    FAIL_IF_NULL(p);
1293

1294
    char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,"
1295
        "relative,string,dec,from_end, post_offset -8; content:\"ABCD\";  sid:1; rev:1;)";
1296

1297
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1298

1299
    UTHFreePacket(p);
1300

1301
    PASS;
1302
}
1303

1304
/**
1305
 * \brief this function registers unit tests for DetectBytejump
1306
 */
1307
static void DetectBytejumpRegisterTests(void)
1308
{
1309
    g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
1310
    g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
1311

1312
    UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01);
1313
    UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02);
1314
    UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03);
1315
    UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04);
1316
    UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05);
1317
    UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06);
1318
    UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07);
1319
    UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08);
1320
    UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09);
1321
    UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10);
1322
    UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11);
1323
    UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12);
1324
    UtRegisterTest("DetectBytejumpTestParse13", DetectBytejumpTestParse13);
1325
    UtRegisterTest("DetectBytejumpTestParse14", DetectBytejumpTestParse14);
1326
    UtRegisterTest("DetectBytejumpTestParse15", DetectBytejumpTestParse15);
1327
    UtRegisterTest("DetectBytejumpTestParse16", DetectBytejumpTestParse16);
1328

1329
    UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01);
1330
    UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02);
1331
    UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03);
1332
    UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04);
1333
    UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05);
1334
    UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06);
1335
    UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07);
1336
    UtRegisterTest("DetectByteJumpTestPacket08", DetectByteJumpTestPacket08);
1337
}
1338
#endif /* UNITTESTS */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc