Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-bytejump.c
Line
Count
Source
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
12
#define PARSE_REGEX  "^\\s*" \
51
12
                     "([^\\s,]+\\s*,\\s*[^\\s,]+)" \
52
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
53
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
54
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
55
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
56
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
57
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
58
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
59
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
60
12
                     "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
61
12
                     "\\s*$"
62
63
static DetectParseRegex parse_regex;
64
65
static DetectBytejumpData *DetectBytejumpParse(
66
        DetectEngineCtx *de_ctx, const char *optstr, char **nbytes, char **offset);
67
static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr);
68
static void DetectBytejumpFree(DetectEngineCtx*, void *ptr);
69
#ifdef UNITTESTS
70
static void DetectBytejumpRegisterTests(void);
71
#endif
72
73
void DetectBytejumpRegister (void)
74
12
{
75
12
    sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump";
76
12
    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";
77
12
    sigmatch_table[DETECT_BYTEJUMP].url = "/rules/payload-keywords.html#byte-jump";
78
12
    sigmatch_table[DETECT_BYTEJUMP].Match = NULL;
79
12
    sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup;
80
12
    sigmatch_table[DETECT_BYTEJUMP].Free  = DetectBytejumpFree;
81
#ifdef UNITTESTS
82
    sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests;
83
#endif
84
12
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
85
12
}
86
87
/* 23 - This is the largest string (octal, with a zero prefix) that
88
 *      will not overflow uint64_t.  The only way this length
89
 *      could be over 23 and still not overflow is if it were zero
90
 *      prefixed and we only support 1 byte of zero prefix for octal.
91
 *
92
 * "01777777777777777777777" = 0xffffffffffffffff
93
 *
94
 * 8 - Without string, the maximum byte extract count is 8.
95
 */
96
static inline bool DetectBytejumpValidateNbytesOnly(const DetectBytejumpData *data, int32_t nbytes)
97
65.0k
{
98
65.0k
    return nbytes >= 0 && ((data->flags & DETECT_BYTEJUMP_STRING && nbytes <= 23) || (nbytes <= 8));
99
65.0k
}
100
101
static bool DetectBytejumpValidateNbytes(const DetectBytejumpData *data, int32_t nbytes)
102
30.7k
{
103
30.7k
    if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
104
128
        if (data->flags & DETECT_BYTEJUMP_STRING) {
105
            /* 23 - This is the largest string (octal, with a zero prefix) that
106
             *      will not overflow uint64_t.  The only way this length
107
             *      could be over 23 and still not overflow is if it were zero
108
             *      prefixed and we only support 1 byte of zero prefix for octal.
109
             *
110
             * "01777777777777777777777" = 0xffffffffffffffff
111
             */
112
20
            if (nbytes > 23) {
113
19
                SCLogError("Cannot test more than 23 bytes "
114
19
                           "with \"string\"");
115
19
            }
116
108
        } else {
117
108
            if (nbytes > 8) {
118
104
                SCLogError("Cannot test more than 8 bytes "
119
104
                           "without \"string\"");
120
104
            }
121
108
        }
122
128
        return false;
123
128
    }
124
125
30.6k
    return true;
126
30.7k
}
127
128
/** \brief Byte jump match function
129
 *  \param det_ctx thread detect engine ctx
130
 *  \param s signature
131
 *  \param m byte jump sigmatch
132
 *  \param payload ptr to the payload
133
 *  \param payload_len length of the payload
134
 *  \retval true match
135
 *  \retval false no match
136
 */
137
bool DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
138
        const SigMatchCtx *ctx, const uint8_t *payload, uint32_t payload_len, uint16_t flags,
139
        int32_t nbytes, int32_t offset)
140
1.08k
{
141
1.08k
    SCEnter();
142
143
1.08k
    const DetectBytejumpData *data = (const DetectBytejumpData *)ctx;
144
1.08k
    const uint8_t *ptr = NULL;
145
1.08k
    int32_t len = 0;
146
1.08k
    uint64_t val = 0;
147
1.08k
    int extbytes;
148
149
1.08k
    if (payload_len == 0) {
150
44
        SCReturnBool(false);
151
44
    }
152
153
    /* Validate the number of bytes we are testing
154
     * If the validation is successful, we know that
155
     * it contains a value <= 23. Thus, we can
156
     * safely cast it when extracting bytes
157
     */
158
1.04k
    if (data->flags & DETECT_BYTEJUMP_NBYTES_VAR) {
159
644
        if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
160
278
            SCLogDebug("Invalid byte_jump nbytes "
161
278
                       "seen in byte_jump - %d",
162
278
                    nbytes);
163
278
            SCReturnBool(false);
164
278
        }
165
644
    }
166
167
    /* Calculate the ptr value for the bytejump and length remaining in
168
     * the packet from that point.
169
     */
170
765
    ptr = payload + offset;
171
765
    len = payload_len - offset;
172
765
    if (flags & DETECT_BYTEJUMP_RELATIVE) {
173
366
        ptr += det_ctx->buffer_offset;
174
366
        len -= det_ctx->buffer_offset;
175
176
366
        SCLogDebug("[relative] after: ptr %p [len %d]", ptr, len);
177
178
        /* No match if there is no relative base */
179
366
        if (ptr == NULL || (nbytes && len <= 0)) {
180
3
            SCReturnBool(false);
181
3
        }
182
366
    }
183
184
    /* Verify the to-be-extracted data is within the packet */
185
762
    if (ptr < payload || nbytes > len) {
186
141
        SCLogDebug("Data not within payload "
187
141
                   "pkt=%p, ptr=%p, len=%" PRIi32 ", nbytes=%" PRIi32,
188
141
                payload, ptr, len, nbytes);
189
141
        SCReturnBool(false);
190
141
    }
191
192
    /* Extract the byte data */
193
621
    if (flags & DETECT_BYTEJUMP_STRING) {
194
258
        extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr);
195
258
        if(extbytes <= 0) {
196
165
            SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes);
197
165
            SCReturnBool(false);
198
165
        }
199
258
    }
200
363
    else {
201
363
        int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN;
202
363
        extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr);
203
363
        if (extbytes != nbytes) {
204
0
            SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes);
205
0
            SCReturnBool(false);
206
0
        }
207
363
    }
208
209
456
    SCLogDebug("VAL: (%" PRIu64 " x %" PRIu32 ") + %" PRIi32 " + %" PRId32, val, data->multiplier,
210
456
            extbytes, data->post_offset);
211
212
    /* Adjust the jump value based on flags */
213
456
    val *= data->multiplier;
214
456
    if (flags & DETECT_BYTEJUMP_ALIGN) {
215
0
        if ((val % 4) != 0) {
216
0
            val += 4 - (val % 4);
217
0
        }
218
0
    }
219
456
    val += data->post_offset;
220
456
    SCLogDebug("val: %" PRIi64 " post_offset: %" PRIi32, val, data->post_offset);
221
222
456
    const uint8_t *jumpptr;
223
    /* Calculate the jump location */
224
456
    if (flags & DETECT_BYTEJUMP_BEGIN) {
225
0
        jumpptr = payload + (int64_t)val;
226
0
        SCLogDebug("NEWVAL: payload %p + %" PRIi64 " = %p", payload, (int64_t)val, jumpptr + val);
227
456
    } else if (flags & DETECT_BYTEJUMP_END) {
228
0
        jumpptr = payload + payload_len + (int64_t)val;
229
0
        SCLogDebug(
230
0
                "NEWVAL: payload %p + %" PRIu32 " + %" PRIi64, payload, payload_len, (int64_t)val);
231
456
    } else {
232
456
        jumpptr = ptr + (int64_t)val + extbytes;
233
456
        SCLogDebug("NEWVAL: ptr %p + %" PRIi64 " = %p", ptr, val, jumpptr);
234
456
    }
235
236
    /* Validate that the jump location is still in the packet
237
     * \todo Should this validate it is still in the *payload*?
238
     */
239
456
    if (jumpptr < payload) {
240
0
        jumpptr = payload;
241
0
        SCLogDebug("jump location is before buffer start; resetting to buffer start");
242
456
    } else if (jumpptr > (payload + payload_len)) {
243
20
        SCLogDebug("Jump location (%" PRIu64 ") is not within payload (%" PRIu32 ")",
244
20
                payload_len + val, payload_len);
245
20
        SCReturnBool(false);
246
20
    }
247
248
#ifdef DEBUG
249
    if (SCLogDebugEnabled()) {
250
        const uint8_t *sptr = (flags & DETECT_BYTEJUMP_BEGIN) ? payload : ptr;
251
        SCLogDebug("jumping %" PRId64 " bytes from %p (%08x)", val, sptr, (int)(sptr - payload));
252
    }
253
#endif /* DEBUG */
254
255
    /* Adjust the detection context to the jump location. */
256
436
    DEBUG_VALIDATE_BUG_ON(jumpptr < payload);
257
436
    det_ctx->buffer_offset = (uint32_t)(jumpptr - payload);
258
259
436
    SCReturnBool(true);
260
436
}
261
262
static DetectBytejumpData *DetectBytejumpParse(
263
        DetectEngineCtx *de_ctx, const char *optstr, char **nbytes_str, char **offset)
264
13.4k
{
265
13.4k
    DetectBytejumpData *data = NULL;
266
13.4k
    char args[10][64];
267
13.4k
    int res = 0;
268
13.4k
    size_t pcre2len;
269
13.4k
    int numargs = 0;
270
13.4k
    int i = 0;
271
13.4k
    uint32_t nbytes = 0;
272
13.4k
    char *str_ptr;
273
13.4k
    char *end_ptr;
274
13.4k
    pcre2_match_data *match = NULL;
275
276
13.4k
    memset(args, 0x00, sizeof(args));
277
278
    /* Execute the regex and populate args with captures. */
279
13.4k
    int ret = DetectParsePcreExec(&parse_regex, &match, optstr, 0, 0);
280
13.4k
    if (ret < 2 || ret > 10) {
281
771
        SCLogError("parse error, ret %" PRId32 ", string \"%s\"", ret, optstr);
282
771
        goto error;
283
771
    }
284
285
    /* The first two arguments are stashed in the first PCRE substring.
286
     * This is because byte_jump can take 10 arguments, but PCRE only
287
     * supports 9 substrings, sigh.
288
     */
289
12.6k
    char str[512] = "";
290
12.6k
    pcre2len = sizeof(str);
291
12.6k
    res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str, &pcre2len);
292
12.6k
    if (res < 0) {
293
20
        SCLogError("pcre2_substring_copy_bynumber failed "
294
20
                   "for arg 1");
295
20
        goto error;
296
20
    }
297
298
    /* Break up first substring into two parameters
299
     *
300
     * NOTE: Because of this, we cannot free args[1] as it is part of args[0],
301
     * and *yes* this *is* ugly.
302
     */
303
12.6k
    end_ptr = str;
304
30.8k
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++;
305
12.6k
    *(end_ptr++) = '\0';
306
12.6k
    strlcpy(args[0], str, sizeof(args[0]));
307
12.6k
    numargs++;
308
309
12.6k
    str_ptr = end_ptr;
310
13.5k
    while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++;
311
12.6k
    end_ptr = str_ptr;
312
35.1k
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0'))
313
22.4k
        end_ptr++;
314
12.6k
    *(end_ptr++) = '\0';
315
12.6k
    strlcpy(args[1], str_ptr, sizeof(args[1]));
316
12.6k
    numargs++;
317
318
    /* The remaining args are directly from PCRE substrings */
319
38.1k
    for (i = 1; i < (ret - 1); i++) {
320
25.6k
        pcre2len = sizeof(args[0]);
321
25.6k
        res = pcre2_substring_copy_bynumber(match, i + 1, (PCRE2_UCHAR8 *)args[i + 1], &pcre2len);
322
25.6k
        if (res < 0) {
323
126
            SCLogError("pcre2_substring_copy_bynumber failed for arg %d", i + 1);
324
126
            goto error;
325
126
        }
326
25.4k
        numargs++;
327
25.4k
    }
328
329
    /* Initialize the data */
330
12.5k
    data = SCMalloc(sizeof(DetectBytejumpData));
331
12.5k
    if (unlikely(data == NULL))
332
0
        goto error;
333
12.5k
    data->base = DETECT_BYTEJUMP_BASE_UNSET;
334
12.5k
    data->flags = 0;
335
12.5k
    data->multiplier = 1;
336
12.5k
    data->post_offset = 0;
337
338
    /*
339
     * The first two options are required and positional.  The
340
     * remaining arguments are flags and are not positional.
341
     */
342
343
    /* Number of bytes */
344
12.5k
    if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) {
345
430
        if (nbytes_str == NULL) {
346
0
            SCLogError("byte_jump supplied with "
347
0
                       "var name for nbytes.  \"value\" argument supplied to "
348
0
                       "this function has to be non-NULL");
349
0
            goto error;
350
0
        }
351
430
        *nbytes_str = SCStrdup(args[0]);
352
430
        if (*nbytes_str == NULL)
353
0
            goto error;
354
430
        data->flags |= DETECT_BYTEJUMP_NBYTES_VAR;
355
12.1k
    } else {
356
12.1k
        if (StringParseUint32(&nbytes, 10, (uint16_t)strlen(args[0]), args[0]) <= 0) {
357
264
            SCLogError("Malformed number of bytes: %s", optstr);
358
264
            goto error;
359
264
        }
360
12.1k
    }
361
362
    /* Offset */
363
12.2k
    if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) {
364
381
        if (offset == NULL) {
365
0
            SCLogError("byte_jump supplied with "
366
0
                       "var name for offset.  \"value\" argument supplied to "
367
0
                       "this function has to be non-NULL");
368
0
            goto error;
369
0
        }
370
381
        *offset = SCStrdup(args[1]);
371
381
        if (*offset == NULL)
372
0
            goto error;
373
11.8k
    } else {
374
11.8k
        if (StringParseI32RangeCheck(
375
11.8k
                    &data->offset, 10, (uint16_t)strlen(args[1]), args[1], -65535, 65535) <= 0) {
376
448
            SCLogError("Malformed offset: %s", optstr);
377
448
            goto error;
378
448
        }
379
11.8k
    }
380
381
    /* The remaining options are flags. */
382
    /** \todo Error on dups? */
383
33.2k
    for (i = 2; i < numargs; i++) {
384
22.9k
        if (strcmp("relative", args[i]) == 0) {
385
6.82k
            data->flags |= DETECT_BYTEJUMP_RELATIVE;
386
16.1k
        } else if (strcasecmp("string", args[i]) == 0) {
387
2.49k
            data->flags |= DETECT_BYTEJUMP_STRING;
388
13.6k
        } else if (strcasecmp("dec", args[i]) == 0) {
389
307
            data->base |= DETECT_BYTEJUMP_BASE_DEC;
390
13.3k
        } else if (strcasecmp("hex", args[i]) == 0) {
391
0
            data->base |= DETECT_BYTEJUMP_BASE_HEX;
392
13.3k
        } else if (strcasecmp("oct", args[i]) == 0) {
393
0
            data->base |= DETECT_BYTEJUMP_BASE_OCT;
394
13.3k
        } else if (strcasecmp("big", args[i]) == 0) {
395
4
            if (data->flags & DETECT_BYTEJUMP_LITTLE) {
396
0
                data->flags ^= DETECT_BYTEJUMP_LITTLE;
397
0
            }
398
4
            data->flags |= DETECT_BYTEJUMP_BIG;
399
13.3k
        } else if (strcasecmp("little", args[i]) == 0) {
400
2.80k
            data->flags |= DETECT_BYTEJUMP_LITTLE;
401
10.5k
        } else if (strcasecmp("from_beginning", args[i]) == 0) {
402
33
            data->flags |= DETECT_BYTEJUMP_BEGIN;
403
10.4k
        } else if (strcasecmp("from_end", args[i]) == 0) {
404
2.03k
            data->flags |= DETECT_BYTEJUMP_END;
405
8.44k
        } else if (strcasecmp("align", args[i]) == 0) {
406
1.80k
            data->flags |= DETECT_BYTEJUMP_ALIGN;
407
6.64k
        } else if (strncasecmp("multiplier ", args[i], 11) == 0) {
408
38
            if (StringParseU16RangeCheck(&data->multiplier, 10, (uint16_t)strlen(args[i]) - 11,
409
38
                        args[i] + 11, 1, 65535) <= 0) {
410
13
                SCLogError("Malformed multiplier: %s", optstr);
411
13
                goto error;
412
13
            }
413
6.60k
        } else if (strncasecmp("post_offset ", args[i], 12) == 0) {
414
5.31k
            if (StringParseI32RangeCheck(&data->post_offset, 10, (uint16_t)strlen(args[i]) - 12,
415
5.31k
                        args[i] + 12, -65535, 65535) <= 0) {
416
296
                SCLogError("Malformed post_offset: %s", optstr);
417
296
                goto error;
418
296
            }
419
5.02k
            SCLogDebug("post_offset: %s [%d]", optstr, data->post_offset);
420
5.02k
        } else if (strcasecmp("dce", args[i]) == 0) {
421
60
            data->flags |= DETECT_BYTEJUMP_DCE;
422
1.22k
        } else {
423
1.22k
            SCLogError("Unknown option: \"%s\"", args[i]);
424
1.22k
            goto error;
425
1.22k
        }
426
22.9k
    }
427
428
10.2k
    if ((data->flags & DETECT_BYTEJUMP_END) && (data->flags & DETECT_BYTEJUMP_BEGIN)) {
429
1
        SCLogError("'from_end' and 'from_beginning' "
430
1
                   "cannot be used in the same byte_jump statement");
431
1
        goto error;
432
1
    }
433
434
10.2k
    if (!(data->flags & DETECT_BYTEJUMP_NBYTES_VAR)) {
435
10.0k
        if (!DetectBytejumpValidateNbytes(data, nbytes)) {
436
88
            goto error;
437
88
        }
438
439
        /* This is max 23 so it will fit in a byte (see validation function) */
440
10.0k
        data->nbytes = (uint8_t)nbytes;
441
10.0k
    }
442
10.1k
    if (!(data->flags & DETECT_BYTEJUMP_STRING)) {
443
7.95k
        if (data->base != DETECT_BYTEJUMP_BASE_UNSET) {
444
11
            SCLogError("Cannot use a base "
445
11
                       "without \"string\": %s",
446
11
                    optstr);
447
11
            goto error;
448
11
        }
449
7.95k
    }
450
451
10.1k
    pcre2_match_data_free(match);
452
10.1k
    return data;
453
454
3.26k
error:
455
3.26k
    if (offset != NULL && *offset != NULL) {
456
243
        SCFree(*offset);
457
243
        *offset = NULL;
458
243
    }
459
3.26k
    if (nbytes_str != NULL && *nbytes_str != NULL) {
460
238
        SCFree(*nbytes_str);
461
238
        *nbytes_str = NULL;
462
238
    }
463
3.26k
    if (data != NULL)
464
2.34k
        DetectBytejumpFree(de_ctx, data);
465
3.26k
    if (match) {
466
3.26k
        pcre2_match_data_free(match);
467
3.26k
    }
468
3.26k
    return NULL;
469
10.1k
}
470
471
static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
472
42.4k
{
473
42.4k
    SigMatch *prev_pm = NULL;
474
42.4k
    DetectBytejumpData *data = NULL;
475
42.4k
    char *offset = NULL;
476
42.4k
    char *nbytes = NULL;
477
42.4k
    int ret = -1;
478
479
42.4k
    data = DetectBytejumpParse(de_ctx, optstr, &nbytes, &offset);
480
42.4k
    if (data == NULL)
481
11.3k
        goto error;
482
483
31.0k
    int sm_list;
484
31.0k
    if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
485
5.26k
        if (DetectBufferGetActiveList(de_ctx, s) == -1)
486
1
            goto error;
487
488
5.26k
        sm_list = s->init_data->list;
489
490
5.26k
        if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
491
1.84k
            prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1);
492
1.84k
        }
493
25.8k
    } else if (data->flags & DETECT_BYTEJUMP_DCE) {
494
487
        if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
495
135
            prev_pm = DetectGetLastSMFromLists(s,
496
135
                    DETECT_CONTENT, DETECT_PCRE,
497
135
                    DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT,
498
135
                    DETECT_ISDATAAT, DETECT_BYTEMATH, -1);
499
135
            if (prev_pm == NULL) {
500
66
                sm_list = DETECT_SM_LIST_PMATCH;
501
69
            } else {
502
69
                sm_list = SigMatchListSMBelongsTo(s, prev_pm);
503
69
                if (sm_list < 0)
504
0
                    goto error;
505
69
            }
506
352
        } else {
507
352
            sm_list = DETECT_SM_LIST_PMATCH;
508
352
        }
509
510
487
        if (SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0)
511
267
            goto error;
512
513
25.3k
    } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
514
13.8k
        prev_pm = DetectGetLastSMFromLists(s,
515
13.8k
                DETECT_CONTENT, DETECT_PCRE,
516
13.8k
                DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT,
517
13.8k
                DETECT_ISDATAAT, DETECT_BYTEMATH, -1);
518
13.8k
        if (prev_pm == NULL) {
519
3.16k
            sm_list = DETECT_SM_LIST_PMATCH;
520
10.6k
        } else {
521
10.6k
            sm_list = SigMatchListSMBelongsTo(s, prev_pm);
522
10.6k
            if (sm_list < 0)
523
0
                goto error;
524
10.6k
        }
525
526
13.8k
    } else {
527
11.4k
        sm_list = DETECT_SM_LIST_PMATCH;
528
11.4k
    }
529
530
30.8k
    if (data->flags & DETECT_BYTEJUMP_DCE) {
531
490
        if ((data->flags & DETECT_BYTEJUMP_STRING) ||
532
426
            (data->flags & DETECT_BYTEJUMP_LITTLE) ||
533
426
            (data->flags & DETECT_BYTEJUMP_BIG) ||
534
424
            (data->flags & DETECT_BYTEJUMP_BEGIN) ||
535
424
            (data->flags & DETECT_BYTEJUMP_END) ||
536
380
            (data->base == DETECT_BYTEJUMP_BASE_DEC) ||
537
380
            (data->base == DETECT_BYTEJUMP_BASE_HEX) ||
538
380
            (data->base == DETECT_BYTEJUMP_BASE_OCT) ) {
539
110
            SCLogError("Invalid option. "
540
110
                       "A byte_jump keyword with dce holds other invalid modifiers.");
541
110
            goto error;
542
110
        }
543
490
    }
544
545
30.7k
    if (nbytes != NULL) {
546
547
        DetectByteIndexType index;
547
547
        if (!DetectByteRetrieveSMVar(nbytes, s, sm_list, &index)) {
548
167
            SCLogError("Unknown byte_extract var "
549
167
                       "seen in byte_jump - %s",
550
167
                    nbytes);
551
167
            goto error;
552
167
        }
553
380
        data->nbytes = index;
554
380
        SCFree(nbytes);
555
380
        nbytes = NULL;
556
380
    }
557
558
30.5k
    if (offset != NULL) {
559
1.84k
        DetectByteIndexType index;
560
1.84k
        if (!DetectByteRetrieveSMVar(offset, s, sm_list, &index)) {
561
350
            SCLogError("Unknown byte_extract var "
562
350
                       "seen in byte_jump - %s",
563
350
                    offset);
564
350
            goto error;
565
350
        }
566
1.49k
        data->offset = index;
567
1.49k
        data->flags |= DETECT_BYTEJUMP_OFFSET_VAR;
568
1.49k
        SCFree(offset);
569
1.49k
        offset = NULL;
570
1.49k
    }
571
572
30.1k
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_BYTEJUMP, (SigMatchCtx *)data, sm_list) ==
573
30.1k
            NULL) {
574
0
        goto error;
575
0
    }
576
577
30.1k
    if (!(data->flags & DETECT_BYTEJUMP_RELATIVE))
578
14.4k
        goto okay;
579
580
15.7k
    if (prev_pm == NULL)
581
4.16k
        goto okay;
582
583
11.5k
    if (prev_pm->type == DETECT_CONTENT) {
584
7.89k
        DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
585
7.89k
        cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
586
7.89k
    } else if (prev_pm->type == DETECT_PCRE) {
587
824
        DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
588
824
        pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
589
824
    }
590
591
30.1k
 okay:
592
30.1k
    ret = 0;
593
30.1k
    return ret;
594
595
12.2k
 error:
596
12.2k
     if (nbytes != NULL) {
597
168
         SCFree(nbytes);
598
168
     }
599
12.2k
    if (offset != NULL) {
600
484
        SCFree(offset);
601
484
    }
602
12.2k
    DetectBytejumpFree(de_ctx, data);
603
12.2k
    return ret;
604
11.5k
}
605
606
/**
607
 * \brief this function will free memory associated with DetectBytejumpData
608
 *
609
 * \param data pointer to DetectBytejumpData
610
 */
611
static void DetectBytejumpFree(DetectEngineCtx *de_ctx, void *ptr)
612
51.5k
{
613
51.5k
    if (ptr == NULL)
614
11.3k
        return;
615
616
40.2k
    DetectBytejumpData *data = (DetectBytejumpData *)ptr;
617
40.2k
    SCFree(data);
618
40.2k
}
619
620
621
/* UNITTESTS */
622
#ifdef UNITTESTS
623
#include "util-unittest-helper.h"
624
static int g_file_data_buffer_id = 0;
625
static int g_dce_stub_data_buffer_id = 0;
626
627
/**
628
 * \test DetectBytejumpTestParse01 is a test to make sure that we return
629
 * "something" when given valid bytejump opt
630
 */
631
static int DetectBytejumpTestParse01(void)
632
{
633
    DetectBytejumpData *data = NULL;
634
    data = DetectBytejumpParse(NULL, "4,0", NULL, NULL);
635
    FAIL_IF_NULL(data);
636
637
    DetectBytejumpFree(NULL, data);
638
    PASS;
639
}
640
641
/**
642
 * \test DetectBytejumpTestParse02 is a test for setting the required opts
643
 */
644
static int DetectBytejumpTestParse02(void)
645
{
646
    DetectBytejumpData *data = NULL;
647
    data = DetectBytejumpParse(NULL, "4, 0", NULL, NULL);
648
    FAIL_IF_NULL(data);
649
    FAIL_IF_NOT(data->nbytes == 4);
650
    FAIL_IF_NOT(data->offset == 0);
651
    FAIL_IF_NOT(data->multiplier == 1);
652
    FAIL_IF_NOT(data->post_offset == 0);
653
    FAIL_IF_NOT(data->flags == 0);
654
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_UNSET);
655
656
    DetectBytejumpFree(NULL, data);
657
    PASS;
658
}
659
660
/**
661
 * \test DetectBytejumpTestParse03 is a test for setting the optional flags
662
 */
663
static int DetectBytejumpTestParse03(void)
664
{
665
    DetectBytejumpData *data = NULL;
666
    data = DetectBytejumpParse(NULL,
667
            " 4,0 , relative , little, string, "
668
            "dec, align, from_beginning",
669
            NULL, NULL);
670
    FAIL_IF_NULL(data);
671
    FAIL_IF_NOT(data->nbytes == 4);
672
    FAIL_IF_NOT(data->offset == 0);
673
    FAIL_IF_NOT(data->multiplier == 1);
674
    FAIL_IF_NOT(data->post_offset == 0);
675
    FAIL_IF_NOT(data->flags ==
676
                (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_STRING |
677
                        DETECT_BYTEJUMP_ALIGN | DETECT_BYTEJUMP_BEGIN));
678
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC);
679
680
    DetectBytejumpFree(NULL, data);
681
    PASS;
682
}
683
684
/**
685
 * \test DetectBytejumpTestParse04 is a test for setting the optional flags
686
 *       with parameters
687
 *
688
 * \todo This fails because we can only have 9 captures and there are 10.
689
 */
690
static int DetectBytejumpTestParse04(void)
691
{
692
    DetectBytejumpData *data = NULL;
693
    data = DetectBytejumpParse(NULL,
694
            " 4,0 , relative , little, string, "
695
            "dec, align, from_beginning , "
696
            "multiplier 2 , post_offset -16 ",
697
            NULL, NULL);
698
    FAIL_IF_NULL(data);
699
    FAIL_IF_NOT(data->nbytes == 4);
700
    FAIL_IF_NOT(data->offset == 0);
701
    FAIL_IF_NOT(data->multiplier == 2);
702
    FAIL_IF_NOT(data->post_offset == -16);
703
    FAIL_IF_NOT(data->flags ==
704
                (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_ALIGN |
705
                        DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BEGIN));
706
    FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC);
707
708
    DetectBytejumpFree(NULL, data);
709
    PASS;
710
}
711
712
/**
713
 * \test DetectBytejumpTestParse05 is a test for setting base without string
714
 */
715
static int DetectBytejumpTestParse05(void)
716
{
717
    DetectBytejumpData *data = NULL;
718
    data = DetectBytejumpParse(NULL,
719
            " 4,0 , relative , little, dec, "
720
            "align, from_beginning",
721
            NULL, NULL);
722
    FAIL_IF_NOT_NULL(data);
723
724
    PASS;
725
}
726
727
/**
728
 * \test DetectBytejumpTestParse06 is a test for too many bytes to extract
729
 */
730
static int DetectBytejumpTestParse06(void)
731
{
732
    DetectBytejumpData *data = NULL;
733
    data = DetectBytejumpParse(NULL, "9, 0", NULL, NULL);
734
    FAIL_IF_NOT_NULL(data);
735
736
    PASS;
737
}
738
739
/**
740
 * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract
741
 */
742
static int DetectBytejumpTestParse07(void)
743
{
744
    DetectBytejumpData *data = NULL;
745
    data = DetectBytejumpParse(NULL, "24, 0, string, dec", NULL, NULL);
746
    FAIL_IF_NOT_NULL(data);
747
748
    PASS;
749
}
750
751
/**
752
 * \test DetectBytejumpTestParse08 is a test for offset too big
753
 */
754
static int DetectBytejumpTestParse08(void)
755
{
756
    DetectBytejumpData *data = NULL;
757
    data = DetectBytejumpParse(NULL, "4, 0xffffffffffffffff", NULL, NULL);
758
    FAIL_IF_NOT_NULL(data);
759
760
    PASS;
761
}
762
763
/**
764
 * \test Test dce option.
765
 */
766
static int DetectBytejumpTestParse09(void)
767
{
768
    Signature *s = SigAlloc();
769
    FAIL_IF_NULL(s);
770
771
    FAIL_IF(SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0);
772
773
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
774
                        "4,0, align, multiplier 2, "
775
                        "post_offset -16,dce") == 0);
776
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
777
                        "4,0, multiplier 2, "
778
                        "post_offset -16,dce") == 0);
779
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,post_offset -16,dce") == 0);
780
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
781
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
782
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dce") == -1);
783
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, big, dce") == -1);
784
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, little, dce") == -1);
785
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dec, dce") == -1);
786
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1);
787
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1);
788
    FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1);
789
790
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
791
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
792
    FAIL_IF_NOT_NULL(sm);
793
794
    SigFree(NULL, s);
795
    PASS;
796
}
797
798
/**
799
 * \test Test dce option.
800
 */
801
static int DetectBytejumpTestParse10(void)
802
{
803
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
804
    FAIL_IF_NULL(de_ctx);
805
    de_ctx->flags |= DE_QUIET;
806
807
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
808
                                                 "(msg:\"Testing bytejump_body\"; "
809
                                                 "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
810
                                                 "dce_stub_data; "
811
                                                 "content:\"one\"; distance:0; "
812
                                                 "byte_jump:4,0,align,multiplier 2, "
813
                                                 "post_offset -16,relative,dce; sid:1;)");
814
    FAIL_IF_NULL(s);
815
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
816
    FAIL_IF_NULL(sm);
817
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
818
    FAIL_IF_NULL(sm->next);
819
    sm = sm->next;
820
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
821
822
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
823
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
824
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
825
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
826
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
827
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
828
829
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
830
                                      "(msg:\"Testing bytejump_body\"; "
831
                                      "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
832
                                      "dce_stub_data; "
833
                                      "content:\"one\"; distance:0; "
834
                                      "byte_jump:4,0,align,multiplier 2, "
835
                                      "post_offset -16,relative,dce; sid:2;)");
836
    FAIL_IF_NULL(s);
837
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
838
    FAIL_IF_NULL(sm);
839
840
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
841
    FAIL_IF_NULL(sm->next);
842
    sm = sm->next;
843
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
844
845
    bd = (DetectBytejumpData *)sm->ctx;
846
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE);
847
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
848
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
849
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
850
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
851
852
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
853
                                      "(msg:\"Testing bytejump_body\"; "
854
                                      "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
855
                                      "dce_stub_data; "
856
                                      "content:\"one\"; distance:0; "
857
                                      "byte_jump:4,0,align,multiplier 2, "
858
                                      "post_offset -16,relative; sid:3;)");
859
    FAIL_IF_NULL(s);
860
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
861
    FAIL_IF_NULL(sm);
862
863
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
864
    FAIL_IF_NULL(sm->next);
865
    sm = sm->next;
866
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
867
868
    bd = (DetectBytejumpData *)sm->ctx;
869
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE);
870
    FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE);
871
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING);
872
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG);
873
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE);
874
875
    DetectEngineCtxFree(de_ctx);
876
    PASS;
877
}
878
879
/**
880
 * \test Test dce option.
881
 */
882
static int DetectBytejumpTestParse11(void)
883
{
884
    DetectEngineCtx *de_ctx = NULL;
885
    Signature *s = NULL;
886
887
    de_ctx = DetectEngineCtxInit();
888
    FAIL_IF_NULL(de_ctx);
889
890
    de_ctx->flags |= DE_QUIET;
891
    s = SigInit(de_ctx, "alert tcp any any -> any any "
892
                "(msg:\"Testing bytejump_body\"; "
893
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
894
                "dce_stub_data; "
895
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
896
                "post_offset -16,string,dce; sid:1;)");
897
    FAIL_IF_NOT_NULL(s);
898
899
    s = SigInit(de_ctx, "alert tcp any any -> any any "
900
                "(msg:\"Testing bytejump_body\"; "
901
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
902
                "dce_sub_data; "
903
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
904
                "post_offset -16,big,dce; sid:1;)");
905
    FAIL_IF_NOT_NULL(s);
906
907
    s = SigInit(de_ctx, "alert tcp any any -> any any "
908
                "(msg:\"Testing bytejump_body\"; "
909
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
910
                "dce_stub_data; "
911
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
912
                "post_offset -16,little,dce; sid:1;)");
913
    FAIL_IF_NOT_NULL(s);
914
915
    s = SigInit(de_ctx, "alert tcp any any -> any any "
916
                "(msg:\"Testing bytejump_body\"; "
917
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
918
                "dce_stub_data; "
919
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
920
                "post_offset -16,string,hex,dce; sid:1;)");
921
    FAIL_IF_NOT_NULL(s);
922
923
    s = SigInit(de_ctx, "alert tcp any any -> any any "
924
                "(msg:\"Testing bytejump_body\"; "
925
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
926
                "dce_stub_data; "
927
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
928
                "post_offset -16,string,dec,dce; sid:1;)");
929
    FAIL_IF_NOT_NULL(s);
930
931
    s = SigInit(de_ctx, "alert tcp any any -> any any "
932
                "(msg:\"Testing bytejump_body\"; "
933
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
934
                "dce_stub_data; "
935
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
936
                "post_offset -16,string,oct,dce; sid:1;)");
937
    FAIL_IF_NOT_NULL(s);
938
939
    s = SigInit(de_ctx, "alert tcp any any -> any any "
940
                "(msg:\"Testing bytejump_body\"; "
941
                "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
942
                "dce_stub_data; "
943
                "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
944
                "post_offset -16,from_beginning,dce; sid:1;)");
945
    FAIL_IF_NOT_NULL(s);
946
947
    SigGroupCleanup(de_ctx);
948
    SigCleanSignatures(de_ctx);
949
    DetectEngineCtxFree(de_ctx);
950
    PASS;
951
}
952
953
/**
954
 * \test Test file_data
955
 */
956
static int DetectBytejumpTestParse12(void)
957
{
958
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
959
    FAIL_IF_NULL(de_ctx);
960
    de_ctx->flags |= DE_QUIET;
961
962
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
963
                                                 "(file_data; byte_jump:4,0,align,multiplier 2, "
964
                                                 "post_offset -16,relative; sid:1;)");
965
    FAIL_IF_NULL(s);
966
967
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_file_data_buffer_id);
968
    FAIL_IF_NULL(sm);
969
    FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP);
970
971
    DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx;
972
    FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE);
973
    FAIL_IF((bd->flags &
974
                    (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG)) ==
975
            (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG));
976
977
    DetectEngineCtxFree(de_ctx);
978
    PASS;
979
}
980
981
static int DetectBytejumpTestParse13(void)
982
{
983
    DetectBytejumpData *data = DetectBytejumpParse(NULL,
984
            " 4,0 , relative , little, string, dec, "
985
            "align, from_end",
986
            NULL, NULL);
987
    FAIL_IF_NULL(data);
988
    FAIL_IF_NOT(data->flags & DETECT_BYTEJUMP_END);
989
990
    DetectBytejumpFree(NULL, data);
991
992
    PASS;
993
}
994
995
static int DetectBytejumpTestParse14(void)
996
{
997
    DetectBytejumpData *data = DetectBytejumpParse(NULL,
998
            " 4,0 , relative , little, string, dec, "
999
            "align, from_beginning, from_end",
1000
            NULL, NULL);
1001
1002
    FAIL_IF_NOT_NULL(data);
1003
1004
    PASS;
1005
}
1006
1007
/**
1008
 * \test DetectByteJumpTestPacket01 is a test to check matches of
1009
 * byte_jump and byte_jump relative works if the previous keyword is pcre
1010
 * (bug 142)
1011
 */
1012
static int DetectByteJumpTestPacket01 (void)
1013
{
1014
    uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0"
1015
                    "User-Agent: Wget/1.11.4"
1016
                    "Accept: */*"
1017
                    "Host: www.google.com"
1018
                    "Connection: Keep-Alive"
1019
                    "Date: Mon, 04 Jan 2010 17:29:39 GMT";
1020
    uint16_t buflen = strlen((char *)buf);
1021
    Packet *p;
1022
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1023
1024
    FAIL_IF_NULL(p);
1025
1026
    char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + "
1027
    "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6,"
1028
    "relative,string,dec; content:\"0\"; sid:134; rev:1;)";
1029
1030
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1031
1032
    UTHFreePacket(p);
1033
    PASS;
1034
}
1035
1036
/**
1037
 * \test DetectByteJumpTestPacket02 is a test to check matches of
1038
 * byte_jump and byte_jump relative works if the previous keyword is byte_jump
1039
 * (bug 165)
1040
 */
1041
static int DetectByteJumpTestPacket02 (void)
1042
{
1043
    uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53,
1044
                    0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18,
1045
                    0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1046
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1047
                    0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff,
1048
                    0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00,
1049
                    0x00, 0xff };
1050
    uint16_t buflen = sizeof(buf);
1051
    Packet *p;
1052
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1053
1054
    FAIL_IF_NULL(p);
1055
1056
    char sig[] = "alert tcp any any -> any any (msg:\"byte_jump with byte_jump"
1057
                 " + relative\"; byte_jump:1,13; byte_jump:4,0,relative; "
1058
                 "content:\"|48 00 00|\"; within:3; sid:144; rev:1;)";
1059
1060
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1061
1062
    UTHFreePacket(p);
1063
    PASS;
1064
}
1065
1066
static int DetectByteJumpTestPacket03(void)
1067
{
1068
    uint8_t *buf = NULL;
1069
    uint16_t buflen = 0;
1070
    buf = SCMalloc(4);
1071
    if (unlikely(buf == NULL)) {
1072
        printf("malloc failed\n");
1073
        exit(EXIT_FAILURE);
1074
    }
1075
    memcpy(buf, "boom", 4);
1076
    buflen = 4;
1077
1078
    Packet *p;
1079
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1080
1081
    FAIL_IF_NULL(p);
1082
1083
    char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; "
1084
        "byte_jump:1,214748364; sid:1; rev:1;)";
1085
1086
    FAIL_IF(UTHPacketMatchSig(p, sig));
1087
1088
    UTHFreePacket(p);
1089
    FAIL_IF_NULL(buf);
1090
1091
    SCFree(buf);
1092
    PASS;
1093
}
1094
1095
/**
1096
 * \test check matches of with from_beginning (bug 626/627)
1097
 */
1098
static int DetectByteJumpTestPacket04 (void)
1099
{
1100
    uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1101
    uint16_t buflen = strlen((char *)buf);
1102
    Packet *p;
1103
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1104
1105
    FAIL_IF_NULL(p);
1106
1107
    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;)";
1108
1109
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1110
1111
    UTHFreePacket(p);
1112
    PASS;
1113
}
1114
1115
/**
1116
 * \test check matches of with from_beginning (bug 626/627)
1117
 */
1118
static int DetectByteJumpTestPacket05 (void)
1119
{
1120
    uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1121
    uint16_t buflen = strlen((char *)buf);
1122
    Packet *p;
1123
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1124
1125
    FAIL_IF_NULL(p);
1126
1127
    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;)";
1128
1129
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 0 : 1);
1130
1131
    UTHFreePacket(p);
1132
    PASS;
1133
}
1134
1135
/**
1136
 * \test check matches of with from_beginning (bug 626/627)
1137
 */
1138
static int DetectByteJumpTestPacket06 (void)
1139
{
1140
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1141
    uint16_t buflen = strlen((char *)buf);
1142
    Packet *p;
1143
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1144
1145
    FAIL_IF_NULL(p);
1146
1147
    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;)";
1148
1149
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1150
1151
    UTHFreePacket(p);
1152
    PASS;
1153
}
1154
1155
/**
1156
 * \test check matches of with from_beginning (bug 626/627)
1157
 */
1158
static int DetectByteJumpTestPacket07 (void)
1159
{
1160
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1161
    uint16_t buflen = strlen((char *)buf);
1162
    Packet *p;
1163
    p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1164
1165
    FAIL_IF_NULL(p);
1166
1167
    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;)";
1168
1169
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 1 : 0);
1170
1171
    UTHFreePacket(p);
1172
    PASS;
1173
}
1174
1175
/**
1176
 * \test check matches of with from_end
1177
 */
1178
static int DetectByteJumpTestPacket08 (void)
1179
{
1180
    uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1181
    uint16_t buflen = strlen((char *)buf);
1182
    Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1183
1184
    FAIL_IF_NULL(p);
1185
1186
    char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,"
1187
        "relative,string,dec,from_end, post_offset -8; content:\"ABCD\";  sid:1; rev:1;)";
1188
1189
    FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1190
1191
    UTHFreePacket(p);
1192
1193
    PASS;
1194
}
1195
1196
/**
1197
 * \brief this function registers unit tests for DetectBytejump
1198
 */
1199
static void DetectBytejumpRegisterTests(void)
1200
{
1201
    g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
1202
    g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
1203
1204
    UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01);
1205
    UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02);
1206
    UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03);
1207
    UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04);
1208
    UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05);
1209
    UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06);
1210
    UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07);
1211
    UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08);
1212
    UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09);
1213
    UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10);
1214
    UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11);
1215
    UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12);
1216
    UtRegisterTest("DetectBytejumpTestParse13", DetectBytejumpTestParse13);
1217
    UtRegisterTest("DetectBytejumpTestParse14", DetectBytejumpTestParse14);
1218
1219
    UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01);
1220
    UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02);
1221
    UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03);
1222
    UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04);
1223
    UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05);
1224
    UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06);
1225
    UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07);
1226
    UtRegisterTest("DetectByteJumpTestPacket08", DetectByteJumpTestPacket08);
1227
}
1228
#endif /* UNITTESTS */