suricata
detect-bytejump.c
Go to the documentation of this file.
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 "app-layer.h"
32 
33 #include "detect-byte.h"
34 #include "detect-byte-extract.h"
35 #include "detect-bytejump.h"
36 #include "detect-content.h"
37 #include "detect-uricontent.h"
38 
39 #include "util-byte.h"
40 #include "util-unittest.h"
41 #include "util-debug.h"
42 #include "util-validate.h"
43 #include "detect-pcre.h"
44 #include "detect-engine-build.h"
45 
46 /**
47  * \brief Regex for parsing our options
48  */
49 #define PARSE_REGEX "^\\s*" \
50  "([^\\s,]+\\s*,\\s*[^\\s,]+)" \
51  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
52  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
53  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
54  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
55  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
56  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
57  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
58  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
59  "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \
60  "\\s*$"
61 
62 static DetectParseRegex parse_regex;
63 
64 static int DetectBytejumpMatch(DetectEngineThreadCtx *det_ctx,
65  Packet *p, const Signature *s, const SigMatchCtx *ctx);
66 static DetectBytejumpData *DetectBytejumpParse(
67  DetectEngineCtx *de_ctx, const char *optstr, char **nbytes, char **offset);
68 static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr);
69 static void DetectBytejumpFree(DetectEngineCtx*, void *ptr);
70 #ifdef UNITTESTS
71 static void DetectBytejumpRegisterTests(void);
72 #endif
73 
75 {
76  sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump";
77  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";
78  sigmatch_table[DETECT_BYTEJUMP].url = "/rules/payload-keywords.html#byte-jump";
79  sigmatch_table[DETECT_BYTEJUMP].Match = DetectBytejumpMatch;
80  sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup;
81  sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree;
82 #ifdef UNITTESTS
83  sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests;
84 #endif
85  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
86 }
87 
88 /* 23 - This is the largest string (octal, with a zero prefix) that
89  * will not overflow uint64_t. The only way this length
90  * could be over 23 and still not overflow is if it were zero
91  * prefixed and we only support 1 byte of zero prefix for octal.
92  *
93  * "01777777777777777777777" = 0xffffffffffffffff
94  *
95  * 8 - Without string, the maximum byte extract count is 8.
96  */
97 static inline bool DetectBytejumpValidateNbytesOnly(const DetectBytejumpData *data, int32_t nbytes)
98 {
99  return (data->flags & DETECT_BYTEJUMP_STRING && nbytes <= 23) || (nbytes <= 8);
100 }
101 
102 static bool DetectBytejumpValidateNbytes(const DetectBytejumpData *data, int32_t nbytes)
103 {
104  if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
105  if (data->flags & DETECT_BYTEJUMP_STRING) {
106  /* 23 - This is the largest string (octal, with a zero prefix) that
107  * will not overflow uint64_t. The only way this length
108  * could be over 23 and still not overflow is if it were zero
109  * prefixed and we only support 1 byte of zero prefix for octal.
110  *
111  * "01777777777777777777777" = 0xffffffffffffffff
112  */
113  if (nbytes > 23) {
114  SCLogError("Cannot test more than 23 bytes "
115  "with \"string\"");
116  }
117  } else {
118  if (nbytes > 8) {
119  SCLogError("Cannot test more than 8 bytes "
120  "without \"string\"");
121  }
122  }
123  return false;
124  }
125 
126  return true;
127 }
128 
129 /** \brief Byte jump match function
130  * \param det_ctx thread detect engine ctx
131  * \param s signature
132  * \param m byte jump sigmatch
133  * \param payload ptr to the payload
134  * \param payload_len length of the payload
135  * \retval 1 match
136  * \retval 0 no match
137  */
139  const SigMatchCtx *ctx, const uint8_t *payload, uint32_t payload_len, uint16_t flags,
140  int32_t nbytes, int32_t offset)
141 {
142  SCEnter();
143 
144  const DetectBytejumpData *data = (const DetectBytejumpData *)ctx;
145  const uint8_t *ptr = NULL;
146  int32_t len = 0;
147  uint64_t val = 0;
148  int extbytes;
149 
150  if (payload_len == 0) {
151  SCReturnInt(0);
152  }
153 
154  /* Validate the number of bytes we are testing
155  * If the validation is successful, we know that
156  * it contains a value <= 23. Thus, we can
157  * safely cast it when extracting bytes
158  */
159  if (data->flags & DETECT_BYTEJUMP_NBYTES_VAR) {
160  if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) {
161  SCLogDebug("Invalid byte_jump nbytes "
162  "seen in byte_jump - %d",
163  nbytes);
164  SCReturnInt(0);
165  }
166  }
167 
168  /* Calculate the ptr value for the bytejump and length remaining in
169  * the packet from that point.
170  */
172  ptr = payload + det_ctx->buffer_offset;
173  len = payload_len - det_ctx->buffer_offset;
174 
175  ptr += offset;
176  len -= offset;
177 
178  /* No match if there is no relative base */
179  if (ptr == NULL || len <= 0) {
180  SCReturnInt(0);
181  }
182  }
183  else {
184  ptr = payload + offset;
185  len = payload_len - offset;
186  }
187 
188  /* Verify the to-be-extracted data is within the packet */
189  if (ptr < payload || nbytes > len) {
190  SCLogDebug("Data not within payload "
191  "pkt=%p, ptr=%p, len=%d, nbytes=%d",
192  payload, ptr, len, nbytes);
193  SCReturnInt(0);
194  }
195 
196  /* Extract the byte data */
198  extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr);
199  if(extbytes <= 0) {
200  SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes);
201  SCReturnInt(0);
202  }
203  }
204  else {
206  extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr);
207  if (extbytes != nbytes) {
208  SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes);
209  SCReturnInt(0);
210  }
211  }
212 
213  SCLogDebug("VAL: (%" PRIu64 " x %" PRIu32 ") + %d + %" PRId32, val, data->multiplier, extbytes, data->post_offset);
214 
215  /* Adjust the jump value based on flags */
216  val *= data->multiplier;
218  if ((val % 4) != 0) {
219  val += 4 - (val % 4);
220  }
221  }
222  val += data->post_offset;
223 
224  /* Calculate the jump location */
226  SCLogDebug("NEWVAL: payload %p + %" PRIu64, payload, val);
227  } else if (flags & DETECT_BYTEJUMP_END) {
228  val = payload_len + val;
229  SCLogDebug("NEWVAL: payload %p + %" PRIu32 " - %" PRIu64, payload, payload_len, val);
230  } else {
231  val += (ptr - payload) + extbytes;
232  SCLogDebug("NEWVAL: ptr %p + %" PRIu64, ptr, val);
233  }
234 
235  /* Validate that the jump location is still in the packet
236  * \todo Should this validate it is still in the *payload*?
237  */
238  if (val >= payload_len) {
239  SCLogDebug("Jump location (%" PRIu64 ") is not within "
240  "payload (%" PRIu32 ")",
241  val, payload_len);
242  SCReturnInt(0);
243  }
244 
245 #ifdef DEBUG
246  if (SCLogDebugEnabled()) {
247  const uint8_t *sptr = (flags & DETECT_BYTEJUMP_BEGIN) ? payload : ptr;
248  SCLogDebug("jumping %" PRId64 " bytes from %p (%08x)", val, sptr, (int)(sptr - payload));
249  }
250 #endif /* DEBUG */
251 
252  /* Adjust the detection context to the jump location. */
253  det_ctx->buffer_offset = val;
254 
255  SCReturnInt(1);
256 }
257 
258 static int DetectBytejumpMatch(DetectEngineThreadCtx *det_ctx,
259  Packet *p, const Signature *s, const SigMatchCtx *ctx)
260 {
261  const DetectBytejumpData *data = (const DetectBytejumpData *)ctx;
262  const uint8_t *ptr = NULL;
263  const uint8_t *jumpptr = NULL;
264  uint16_t len = 0;
265  uint64_t val = 0;
266  int extbytes;
267 
268  if (p->payload_len == 0) {
269  return 0;
270  }
271 
272  /* Calculate the ptr value for the bytejump and length remaining in
273  * the packet from that point.
274  */
275  if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
276  ptr = p->payload + det_ctx->buffer_offset;
277  DEBUG_VALIDATE_BUG_ON(p->payload_len - det_ctx->buffer_offset > UINT16_MAX);
278  len = (uint16_t)(p->payload_len - det_ctx->buffer_offset);
279 
280  /* No match if there is no relative base */
281  if (ptr == NULL || len == 0) {
282  return 0;
283  }
284 
285  ptr += data->offset;
286  len -= data->offset;
287  }
288  else {
289  ptr = p->payload + data->offset;
290  DEBUG_VALIDATE_BUG_ON(p->payload_len - data->offset > UINT16_MAX);
291  len = (uint16_t)(p->payload_len - data->offset);
292  }
293 
294  /* Verify the to-be-extracted data is within the packet */
295  if (ptr < p->payload || data->nbytes > len) {
296  SCLogDebug("Data not within packet "
297  "payload=%p, ptr=%p, len=%d, nbytes=%d",
298  p->payload, ptr, len, data->nbytes);
299  return 0;
300  }
301 
302  /* Extract the byte data */
303  if (data->flags & DETECT_BYTEJUMP_STRING) {
304  extbytes = ByteExtractStringUint64(&val, data->base,
305  data->nbytes, (const char *)ptr);
306  if (extbytes <= 0) {
307  SCLogDebug("error extracting %d bytes of string data: %d",
308  data->nbytes, extbytes);
309  return -1;
310  }
311  }
312  else {
313  int endianness = (data->flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN;
314  extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr);
315  if (extbytes != data->nbytes) {
316  SCLogDebug("error extracting %d bytes of numeric data: %d",
317  data->nbytes, extbytes);
318  return -1;
319  }
320  }
321 
322  //printf("VAL: (%" PRIu64 " x %" PRIu32 ") + %d + %" PRId32 "\n", val, data->multiplier, extbytes, data->post_offset);
323 
324  /* Adjust the jump value based on flags */
325  val *= data->multiplier;
326  if (data->flags & DETECT_BYTEJUMP_ALIGN) {
327  if ((val % 4) != 0) {
328  val += 4 - (val % 4);
329  }
330  }
331  val += data->post_offset;
332 
333  /* Calculate the jump location */
334  if (data->flags & DETECT_BYTEJUMP_BEGIN) {
335  jumpptr = p->payload + val;
336  //printf("NEWVAL: payload %p + %ld = %p\n", p->payload, val, jumpptr);
337  }
338  else {
339  val += extbytes;
340  jumpptr = ptr + val;
341  //printf("NEWVAL: ptr %p + %ld = %p\n", ptr, val, jumpptr);
342  }
343 
344 
345  /* Validate that the jump location is still in the packet
346  * \todo Should this validate it is still in the *payload*?
347  */
348  if ((jumpptr < p->payload) || (jumpptr >= p->payload + p->payload_len)) {
349  SCLogDebug("Jump location (%p) is not within "
350  "packet (%p-%p)", jumpptr, p->payload, p->payload + p->payload_len - 1);
351  return 0;
352  }
353 
354 #ifdef DEBUG
355  if (SCLogDebugEnabled()) {
356  const uint8_t *sptr = (data->flags & DETECT_BYTEJUMP_BEGIN) ? p->payload
357  : ptr;
358  SCLogDebug("jumping %" PRId64 " bytes from %p (%08x) to %p (%08x)",
359  val, sptr, (int)(sptr - p->payload),
360  jumpptr, (int)(jumpptr - p->payload));
361  }
362 #endif /* DEBUG */
363 
364  /* Adjust the detection context to the jump location. */
365  det_ctx->buffer_offset = jumpptr - p->payload;
366 
367  return 1;
368 }
369 
370 static DetectBytejumpData *DetectBytejumpParse(
371  DetectEngineCtx *de_ctx, const char *optstr, char **nbytes_str, char **offset)
372 {
373  DetectBytejumpData *data = NULL;
374  char args[10][64];
375  int res = 0;
376  size_t pcre2len;
377  int numargs = 0;
378  int i = 0;
379  uint32_t nbytes = 0;
380  char *str_ptr;
381  char *end_ptr;
382  pcre2_match_data *match = NULL;
383 
384  memset(args, 0x00, sizeof(args));
385 
386  /* Execute the regex and populate args with captures. */
387  int ret = DetectParsePcreExec(&parse_regex, &match, optstr, 0, 0);
388  if (ret < 2 || ret > 10) {
389  SCLogError("parse error, ret %" PRId32 ", string \"%s\"", ret, optstr);
390  goto error;
391  }
392 
393  /* The first two arguments are stashed in the first PCRE substring.
394  * This is because byte_jump can take 10 arguments, but PCRE only
395  * supports 9 substrings, sigh.
396  */
397  char str[512] = "";
398  pcre2len = sizeof(str);
399  res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str, &pcre2len);
400  if (res < 0) {
401  SCLogError("pcre2_substring_copy_bynumber failed "
402  "for arg 1");
403  goto error;
404  }
405 
406  /* Break up first substring into two parameters
407  *
408  * NOTE: Because of this, we cannot free args[1] as it is part of args[0],
409  * and *yes* this *is* ugly.
410  */
411  end_ptr = str;
412  while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++;
413  *(end_ptr++) = '\0';
414  strlcpy(args[0], str, sizeof(args[0]));
415  numargs++;
416 
417  str_ptr = end_ptr;
418  while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++;
419  end_ptr = str_ptr;
420  while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0'))
421  end_ptr++;
422  *(end_ptr++) = '\0';
423  strlcpy(args[1], str_ptr, sizeof(args[1]));
424  numargs++;
425 
426  /* The remaining args are directly from PCRE substrings */
427  for (i = 1; i < (ret - 1); i++) {
428  pcre2len = sizeof(args[0]);
429  res = pcre2_substring_copy_bynumber(match, i + 1, (PCRE2_UCHAR8 *)args[i + 1], &pcre2len);
430  if (res < 0) {
431  SCLogError("pcre2_substring_copy_bynumber failed for arg %d", i + 1);
432  goto error;
433  }
434  numargs++;
435  }
436 
437  /* Initialize the data */
438  data = SCMalloc(sizeof(DetectBytejumpData));
439  if (unlikely(data == NULL))
440  goto error;
442  data->flags = 0;
443  data->multiplier = 1;
444  data->post_offset = 0;
445 
446  /*
447  * The first two options are required and positional. The
448  * remaining arguments are flags and are not positional.
449  */
450 
451  /* Number of bytes */
452  if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) {
453  if (nbytes_str == NULL) {
454  SCLogError("byte_jump supplied with "
455  "var name for nbytes. \"value\" argument supplied to "
456  "this function has to be non-NULL");
457  goto error;
458  }
459  *nbytes_str = SCStrdup(args[0]);
460  if (*nbytes_str == NULL)
461  goto error;
463  } else {
464  if (StringParseUint32(&nbytes, 10, (uint16_t)strlen(args[0]), args[0]) <= 0) {
465  SCLogError("Malformed number of bytes: %s", optstr);
466  goto error;
467  }
468  }
469 
470  /* Offset */
471  if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) {
472  if (offset == NULL) {
473  SCLogError("byte_jump supplied with "
474  "var name for offset. \"value\" argument supplied to "
475  "this function has to be non-NULL");
476  goto error;
477  }
478  *offset = SCStrdup(args[1]);
479  if (*offset == NULL)
480  goto error;
481  } else {
482  if (StringParseInt32(&data->offset, 0, (uint16_t)strlen(args[1]), args[1]) <= 0) {
483  SCLogError("Malformed offset: %s", optstr);
484  goto error;
485  }
486  }
487 
488  /* The remaining options are flags. */
489  /** \todo Error on dups? */
490  for (i = 2; i < numargs; i++) {
491  if (strcmp("relative", args[i]) == 0) {
493  } else if (strcasecmp("string", args[i]) == 0) {
494  data->flags |= DETECT_BYTEJUMP_STRING;
495  } else if (strcasecmp("dec", args[i]) == 0) {
497  } else if (strcasecmp("hex", args[i]) == 0) {
499  } else if (strcasecmp("oct", args[i]) == 0) {
501  } else if (strcasecmp("big", args[i]) == 0) {
502  if (data->flags & DETECT_BYTEJUMP_LITTLE) {
503  data->flags ^= DETECT_BYTEJUMP_LITTLE;
504  }
505  data->flags |= DETECT_BYTEJUMP_BIG;
506  } else if (strcasecmp("little", args[i]) == 0) {
507  data->flags |= DETECT_BYTEJUMP_LITTLE;
508  } else if (strcasecmp("from_beginning", args[i]) == 0) {
509  data->flags |= DETECT_BYTEJUMP_BEGIN;
510  } else if (strcasecmp("from_end", args[i]) == 0) {
511  data->flags |= DETECT_BYTEJUMP_END;
512  } else if (strcasecmp("align", args[i]) == 0) {
513  data->flags |= DETECT_BYTEJUMP_ALIGN;
514  } else if (strncasecmp("multiplier ", args[i], 11) == 0) {
515  if (StringParseU16RangeCheck(&data->multiplier, 10, (uint16_t)strlen(args[i]) - 11,
516  args[i] + 11, 1, 65535) <= 0) {
517  SCLogError("Malformed multiplier: %s", optstr);
518  goto error;
519  }
520  } else if (strncasecmp("post_offset ", args[i], 12) == 0) {
521  if (StringParseInt32(&data->post_offset, 10, (uint16_t)strlen(args[i]) - 12,
522  args[i] + 12) <= 0) {
523  SCLogError("Malformed post_offset: %s", optstr);
524  goto error;
525  }
526  } else if (strcasecmp("dce", args[i]) == 0) {
527  data->flags |= DETECT_BYTEJUMP_DCE;
528  } else {
529  SCLogError("Unknown option: \"%s\"", args[i]);
530  goto error;
531  }
532  }
533 
534  if ((data->flags & DETECT_BYTEJUMP_END) && (data->flags & DETECT_BYTEJUMP_BEGIN)) {
535  SCLogError("'from_end' and 'from_beginning' "
536  "cannot be used in the same byte_jump statement");
537  goto error;
538  }
539 
540  if (!(data->flags & DETECT_BYTEJUMP_NBYTES_VAR)) {
541  if (!DetectBytejumpValidateNbytes(data, nbytes)) {
542  goto error;
543  }
544 
545  /* This is max 23 so it will fit in a byte (see validation function) */
546  data->nbytes = (uint8_t)nbytes;
547  }
548  if (!(data->flags & DETECT_BYTEJUMP_STRING)) {
549  if (data->base != DETECT_BYTEJUMP_BASE_UNSET) {
550  SCLogError("Cannot use a base "
551  "without \"string\": %s",
552  optstr);
553  goto error;
554  }
555  }
556 
557  pcre2_match_data_free(match);
558  return data;
559 
560 error:
561  if (offset != NULL && *offset != NULL) {
562  SCFree(*offset);
563  *offset = NULL;
564  }
565  if (nbytes_str != NULL && *nbytes_str != NULL) {
566  SCFree(*nbytes_str);
567  *nbytes_str = NULL;
568  }
569  if (data != NULL)
570  DetectBytejumpFree(de_ctx, data);
571  if (match) {
572  pcre2_match_data_free(match);
573  }
574  return NULL;
575 }
576 
577 static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
578 {
579  SigMatch *sm = NULL;
580  SigMatch *prev_pm = NULL;
581  DetectBytejumpData *data = NULL;
582  char *offset = NULL;
583  char *nbytes = NULL;
584  int ret = -1;
585 
586  data = DetectBytejumpParse(de_ctx, optstr, &nbytes, &offset);
587  if (data == NULL)
588  goto error;
589 
590  int sm_list;
591  if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
592  if (DetectBufferGetActiveList(de_ctx, s) == -1)
593  goto error;
594 
595  sm_list = s->init_data->list;
596 
597  if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
599  }
600  } else if (data->flags & DETECT_BYTEJUMP_DCE) {
601  if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
602  prev_pm = DetectGetLastSMFromLists(s,
606  if (prev_pm == NULL) {
607  sm_list = DETECT_SM_LIST_PMATCH;
608  } else {
609  sm_list = SigMatchListSMBelongsTo(s, prev_pm);
610  if (sm_list < 0)
611  goto error;
612  }
613  } else {
614  sm_list = DETECT_SM_LIST_PMATCH;
615  }
616 
618  goto error;
619 
620  } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) {
621  prev_pm = DetectGetLastSMFromLists(s,
625  if (prev_pm == NULL) {
626  sm_list = DETECT_SM_LIST_PMATCH;
627  } else {
628  sm_list = SigMatchListSMBelongsTo(s, prev_pm);
629  if (sm_list < 0)
630  goto error;
631  }
632 
633  } else {
634  sm_list = DETECT_SM_LIST_PMATCH;
635  }
636 
637  if (data->flags & DETECT_BYTEJUMP_DCE) {
638  if ((data->flags & DETECT_BYTEJUMP_STRING) ||
639  (data->flags & DETECT_BYTEJUMP_LITTLE) ||
640  (data->flags & DETECT_BYTEJUMP_BIG) ||
641  (data->flags & DETECT_BYTEJUMP_BEGIN) ||
642  (data->flags & DETECT_BYTEJUMP_END) ||
643  (data->base == DETECT_BYTEJUMP_BASE_DEC) ||
644  (data->base == DETECT_BYTEJUMP_BASE_HEX) ||
645  (data->base == DETECT_BYTEJUMP_BASE_OCT) ) {
646  SCLogError("Invalid option. "
647  "A byte_jump keyword with dce holds other invalid modifiers.");
648  goto error;
649  }
650  }
651 
652  if (nbytes != NULL) {
653  DetectByteIndexType index;
654  if (!DetectByteRetrieveSMVar(nbytes, s, &index)) {
655  SCLogError("Unknown byte_extract var "
656  "seen in byte_jump - %s",
657  nbytes);
658  goto error;
659  }
660  data->nbytes = index;
661  SCFree(nbytes);
662  nbytes = NULL;
663  }
664 
665  if (offset != NULL) {
666  DetectByteIndexType index;
667  if (!DetectByteRetrieveSMVar(offset, s, &index)) {
668  SCLogError("Unknown byte_extract var "
669  "seen in byte_jump - %s",
670  offset);
671  goto error;
672  }
673  data->offset = index;
675  SCFree(offset);
676  offset = NULL;
677  }
678 
679  sm = SigMatchAlloc();
680  if (sm == NULL)
681  goto error;
682  sm->type = DETECT_BYTEJUMP;
683  sm->ctx = (SigMatchCtx *)data;
684  SigMatchAppendSMToList(s, sm, sm_list);
685 
686  if (!(data->flags & DETECT_BYTEJUMP_RELATIVE))
687  goto okay;
688 
689  if (prev_pm == NULL)
690  goto okay;
691 
692  if (prev_pm->type == DETECT_CONTENT) {
693  DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
695  } else if (prev_pm->type == DETECT_PCRE) {
696  DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
698  }
699 
700  okay:
701  ret = 0;
702  return ret;
703 
704  error:
705  if (nbytes != NULL) {
706  SCFree(nbytes);
707  }
708  if (offset != NULL) {
709  SCFree(offset);
710  }
711  DetectBytejumpFree(de_ctx, data);
712  return ret;
713 }
714 
715 /**
716  * \brief this function will free memory associated with DetectBytejumpData
717  *
718  * \param data pointer to DetectBytejumpData
719  */
720 static void DetectBytejumpFree(DetectEngineCtx *de_ctx, void *ptr)
721 {
722  if (ptr == NULL)
723  return;
724 
725  DetectBytejumpData *data = (DetectBytejumpData *)ptr;
726  SCFree(data);
727 }
728 
729 
730 /* UNITTESTS */
731 #ifdef UNITTESTS
732 #include "util-unittest-helper.h"
733 static int g_file_data_buffer_id = 0;
734 static int g_dce_stub_data_buffer_id = 0;
735 
736 /**
737  * \test DetectBytejumpTestParse01 is a test to make sure that we return
738  * "something" when given valid bytejump opt
739  */
740 static int DetectBytejumpTestParse01(void)
741 {
742  int result = 0;
743  DetectBytejumpData *data = NULL;
744  data = DetectBytejumpParse(NULL, "4,0", NULL, NULL);
745  if (data != NULL) {
746  DetectBytejumpFree(NULL, data);
747  result = 1;
748  }
749 
750  return result;
751 }
752 
753 /**
754  * \test DetectBytejumpTestParse02 is a test for setting the required opts
755  */
756 static int DetectBytejumpTestParse02(void)
757 {
758  int result = 0;
759  DetectBytejumpData *data = NULL;
760  data = DetectBytejumpParse(NULL, "4, 0", NULL, NULL);
761  if (data != NULL) {
762  if ( (data->nbytes == 4)
763  && (data->offset == 0)
764  && (data->multiplier == 1)
765  && (data->post_offset == 0)
766  && (data->flags == 0)
767  && (data->base == DETECT_BYTEJUMP_BASE_UNSET))
768  {
769  result = 1;
770  }
771  DetectBytejumpFree(NULL, data);
772  }
773 
774  return result;
775 }
776 
777 /**
778  * \test DetectBytejumpTestParse03 is a test for setting the optional flags
779  */
780 static int DetectBytejumpTestParse03(void)
781 {
782  int result = 0;
783  DetectBytejumpData *data = NULL;
784  data = DetectBytejumpParse(NULL,
785  " 4,0 , relative , little, string, "
786  "dec, align, from_beginning",
787  NULL, NULL);
788  if (data != NULL) {
789  if ( (data->nbytes == 4)
790  && (data->offset == 0)
791  && (data->multiplier == 1)
792  && (data->post_offset == 0)
793  && (data->flags == ( DETECT_BYTEJUMP_RELATIVE
798  && (data->base == DETECT_BYTEJUMP_BASE_DEC))
799  {
800  result = 1;
801  }
802  DetectBytejumpFree(NULL, data);
803  }
804 
805  return result;
806 }
807 
808 /**
809  * \test DetectBytejumpTestParse04 is a test for setting the optional flags
810  * with parameters
811  *
812  * \todo This fails because we can only have 9 captures and there are 10.
813  */
814 static int DetectBytejumpTestParse04(void)
815 {
816  int result = 0;
817  DetectBytejumpData *data = NULL;
818  data = DetectBytejumpParse(NULL,
819  " 4,0 , relative , little, string, "
820  "dec, align, from_beginning , "
821  "multiplier 2 , post_offset -16 ",
822  NULL, NULL);
823  if (data != NULL) {
824  if ( (data->nbytes == 4)
825  && (data->offset == 0)
826  && (data->multiplier == 2)
827  && (data->post_offset == -16)
828  && (data->flags == ( DETECT_BYTEJUMP_RELATIVE
833  && (data->base == DETECT_BYTEJUMP_BASE_DEC))
834  {
835  result = 1;
836  }
837  DetectBytejumpFree(NULL, data);
838  }
839 
840  return result;
841 }
842 
843 /**
844  * \test DetectBytejumpTestParse05 is a test for setting base without string
845  */
846 static int DetectBytejumpTestParse05(void)
847 {
848  int result = 0;
849  DetectBytejumpData *data = NULL;
850  data = DetectBytejumpParse(NULL,
851  " 4,0 , relative , little, dec, "
852  "align, from_beginning",
853  NULL, NULL);
854  if (data == NULL) {
855  result = 1;
856  }
857 
858  return result;
859 }
860 
861 /**
862  * \test DetectBytejumpTestParse06 is a test for too many bytes to extract
863  */
864 static int DetectBytejumpTestParse06(void)
865 {
866  int result = 0;
867  DetectBytejumpData *data = NULL;
868  data = DetectBytejumpParse(NULL, "9, 0", NULL, NULL);
869  if (data == NULL) {
870  result = 1;
871  }
872 
873  return result;
874 }
875 
876 /**
877  * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract
878  */
879 static int DetectBytejumpTestParse07(void)
880 {
881  int result = 0;
882  DetectBytejumpData *data = NULL;
883  data = DetectBytejumpParse(NULL, "24, 0, string, dec", NULL, NULL);
884  if (data == NULL) {
885  result = 1;
886  }
887 
888  return result;
889 }
890 
891 /**
892  * \test DetectBytejumpTestParse08 is a test for offset too big
893  */
894 static int DetectBytejumpTestParse08(void)
895 {
896  int result = 0;
897  DetectBytejumpData *data = NULL;
898  data = DetectBytejumpParse(NULL, "4, 0xffffffffffffffff", NULL, NULL);
899  if (data == NULL) {
900  result = 1;
901  }
902 
903  return result;
904 }
905 
906 /**
907  * \test Test dce option.
908  */
909 static int DetectBytejumpTestParse09(void)
910 {
911  Signature *s = SigAlloc();
912  FAIL_IF_NULL(s);
913 
915 
916  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
917  "4,0, align, multiplier 2, "
918  "post_offset -16,dce") == 0);
919  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s,
920  "4,0, multiplier 2, "
921  "post_offset -16,dce") == 0);
922  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,post_offset -16,dce") == 0);
923  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
924  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0);
925  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dce") == -1);
926  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, big, dce") == -1);
927  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, little, dce") == -1);
928  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dec, dce") == -1);
929  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1);
930  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1);
931  FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1);
932 
934  SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
935  FAIL_IF_NOT_NULL(sm);
936 
937  SigFree(NULL, s);
938  PASS;
939 }
940 
941 /**
942  * \test Test dce option.
943  */
944 static int DetectBytejumpTestParse10(void)
945 {
948  de_ctx->flags |= DE_QUIET;
949 
950  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
951  "(msg:\"Testing bytejump_body\"; "
952  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
953  "dce_stub_data; "
954  "content:\"one\"; distance:0; "
955  "byte_jump:4,0,align,multiplier 2, "
956  "post_offset -16,relative,dce; sid:1;)");
957  FAIL_IF_NULL(s);
958  SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
959  FAIL_IF_NULL(sm);
961  FAIL_IF_NULL(sm->next);
962  sm = sm->next;
964 
966  if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) &&
968  (bd->flags & DETECT_BYTEJUMP_LITTLE)) {
969  goto end;
970  }
971 
972  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
973  "(msg:\"Testing bytejump_body\"; "
974  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
975  "dce_stub_data; "
976  "content:\"one\"; distance:0; "
977  "byte_jump:4,0,align,multiplier 2, "
978  "post_offset -16,relative,dce; sid:2;)");
979  FAIL_IF_NULL(s);
980  sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
981  FAIL_IF_NULL(sm);
982 
984  FAIL_IF_NULL(sm->next);
985  sm = sm->next;
987 
988  bd = (DetectBytejumpData *)sm->ctx;
989  if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) &&
991  (bd->flags & DETECT_BYTEJUMP_LITTLE)) {
992  goto end;
993  }
994 
995  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
996  "(msg:\"Testing bytejump_body\"; "
997  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
998  "dce_stub_data; "
999  "content:\"one\"; distance:0; "
1000  "byte_jump:4,0,align,multiplier 2, "
1001  "post_offset -16,relative; sid:3;)");
1002  FAIL_IF_NULL(s);
1003  sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1004  FAIL_IF_NULL(sm);
1005 
1007  FAIL_IF_NULL(sm->next);
1008  sm = sm->next;
1010 
1011  bd = (DetectBytejumpData *)sm->ctx;
1012  if ((bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) &&
1014  (bd->flags & DETECT_BYTEJUMP_LITTLE)) {
1015  goto end;
1016  }
1017 
1018 end:
1020  PASS;
1021 }
1022 
1023 /**
1024  * \test Test dce option.
1025  */
1026 static int DetectBytejumpTestParse11(void)
1027 {
1028  DetectEngineCtx *de_ctx = NULL;
1029  int result = 1;
1030  Signature *s = NULL;
1031 
1033  if (de_ctx == NULL)
1034  goto end;
1035 
1036  de_ctx->flags |= DE_QUIET;
1037  s = SigInit(de_ctx, "alert tcp any any -> any any "
1038  "(msg:\"Testing bytejump_body\"; "
1039  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1040  "dce_stub_data; "
1041  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1042  "post_offset -16,string,dce; sid:1;)");
1043  if (s != NULL) {
1044  result = 0;
1045  goto end;
1046  }
1047 
1048  s = SigInit(de_ctx, "alert tcp any any -> any any "
1049  "(msg:\"Testing bytejump_body\"; "
1050  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1051  "dce_sub_data; "
1052  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1053  "post_offset -16,big,dce; sid:1;)");
1054  if (s != NULL) {
1055  result = 0;
1056  goto end;
1057  }
1058 
1059  s = SigInit(de_ctx, "alert tcp any any -> any any "
1060  "(msg:\"Testing bytejump_body\"; "
1061  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1062  "dce_stub_data; "
1063  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1064  "post_offset -16,little,dce; sid:1;)");
1065  if (s != NULL) {
1066  result = 0;
1067  goto end;
1068  }
1069 
1070  s = SigInit(de_ctx, "alert tcp any any -> any any "
1071  "(msg:\"Testing bytejump_body\"; "
1072  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1073  "dce_stub_data; "
1074  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1075  "post_offset -16,string,hex,dce; sid:1;)");
1076  if (s != NULL) {
1077  result = 0;
1078  goto end;
1079  }
1080 
1081  s = SigInit(de_ctx, "alert tcp any any -> any any "
1082  "(msg:\"Testing bytejump_body\"; "
1083  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1084  "dce_stub_data; "
1085  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1086  "post_offset -16,string,dec,dce; sid:1;)");
1087  if (s != NULL) {
1088  result = 0;
1089  goto end;
1090  }
1091 
1092  s = SigInit(de_ctx, "alert tcp any any -> any any "
1093  "(msg:\"Testing bytejump_body\"; "
1094  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1095  "dce_stub_data; "
1096  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1097  "post_offset -16,string,oct,dce; sid:1;)");
1098  if (s != NULL) {
1099  result = 0;
1100  goto end;
1101  }
1102 
1103  s = SigInit(de_ctx, "alert tcp any any -> any any "
1104  "(msg:\"Testing bytejump_body\"; "
1105  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1106  "dce_stub_data; "
1107  "content:\"one\"; byte_jump:4,0,align,multiplier 2, "
1108  "post_offset -16,from_beginning,dce; sid:1;)");
1109  if (s != NULL) {
1110  result = 0;
1111  goto end;
1112  }
1113 
1114  end:
1118 
1119  return result;
1120 }
1121 
1122 /**
1123  * \test Test file_data
1124  */
1125 static int DetectBytejumpTestParse12(void)
1126 {
1129  de_ctx->flags |= DE_QUIET;
1130 
1131  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1132  "(file_data; byte_jump:4,0,align,multiplier 2, "
1133  "post_offset -16,relative; sid:1;)");
1134  FAIL_IF_NULL(s);
1135 
1136  SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_file_data_buffer_id);
1137  FAIL_IF_NULL(sm);
1139 
1142  FAIL_IF((bd->flags &
1145 
1147  PASS;
1148 }
1149 
1150 static int DetectBytejumpTestParse13(void)
1151 {
1152  DetectBytejumpData *data = DetectBytejumpParse(NULL,
1153  " 4,0 , relative , little, string, dec, "
1154  "align, from_end",
1155  NULL, NULL);
1156  FAIL_IF_NULL(data);
1158 
1159  DetectBytejumpFree(NULL, data);
1160 
1161  PASS;
1162 }
1163 
1164 static int DetectBytejumpTestParse14(void)
1165 {
1166  DetectBytejumpData *data = DetectBytejumpParse(NULL,
1167  " 4,0 , relative , little, string, dec, "
1168  "align, from_beginning, from_end",
1169  NULL, NULL);
1170 
1171  FAIL_IF_NOT_NULL(data);
1172 
1173  PASS;
1174 }
1175 
1176 /**
1177  * \test DetectByteJumpTestPacket01 is a test to check matches of
1178  * byte_jump and byte_jump relative works if the previous keyword is pcre
1179  * (bug 142)
1180  */
1181 static int DetectByteJumpTestPacket01 (void)
1182 {
1183  int result = 0;
1184  uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0"
1185  "User-Agent: Wget/1.11.4"
1186  "Accept: */*"
1187  "Host: www.google.com"
1188  "Connection: Keep-Alive"
1189  "Date: Mon, 04 Jan 2010 17:29:39 GMT";
1190  uint16_t buflen = strlen((char *)buf);
1191  Packet *p;
1192  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1193 
1194  if (p == NULL)
1195  goto end;
1196 
1197  char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + "
1198  "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6,"
1199  "relative,string,dec; content:\"0\"; sid:134; rev:1;)";
1200 
1201  result = UTHPacketMatchSig(p, sig);
1202 
1203  UTHFreePacket(p);
1204 end:
1205  return result;
1206 }
1207 
1208 /**
1209  * \test DetectByteJumpTestPacket02 is a test to check matches of
1210  * byte_jump and byte_jump relative works if the previous keyword is byte_jump
1211  * (bug 165)
1212  */
1213 static int DetectByteJumpTestPacket02 (void)
1214 {
1215  int result = 0;
1216  uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53,
1217  0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18,
1218  0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1219  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1220  0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff,
1221  0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00,
1222  0x00, 0xff };
1223  uint16_t buflen = sizeof(buf);
1224  Packet *p;
1225  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1226 
1227  if (p == NULL)
1228  goto end;
1229 
1230  char sig[] = "alert tcp any any -> any any (msg:\"byte_jump with byte_jump"
1231  " + relative\"; byte_jump:1,13; byte_jump:4,0,relative; "
1232  "content:\"|48 00 00|\"; within:3; sid:144; rev:1;)";
1233 
1234  result = UTHPacketMatchSig(p, sig);
1235 
1236  UTHFreePacket(p);
1237 end:
1238  return result;
1239 }
1240 
1241 static int DetectByteJumpTestPacket03(void)
1242 {
1243  int result = 0;
1244  uint8_t *buf = NULL;
1245  uint16_t buflen = 0;
1246  buf = SCMalloc(4);
1247  if (unlikely(buf == NULL)) {
1248  printf("malloc failed\n");
1249  exit(EXIT_FAILURE);
1250  }
1251  memcpy(buf, "boom", 4);
1252  buflen = 4;
1253 
1254  Packet *p;
1255  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1256 
1257  if (p == NULL)
1258  goto end;
1259 
1260  char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; "
1261  "byte_jump:1,214748364; sid:1; rev:1;)";
1262 
1263  result = !UTHPacketMatchSig(p, sig);
1264 
1265  UTHFreePacket(p);
1266 
1267 end:
1268  if (buf != NULL)
1269  SCFree(buf);
1270  return result;
1271 }
1272 
1273 /**
1274  * \test check matches of with from_beginning (bug 626/627)
1275  */
1276 static int DetectByteJumpTestPacket04 (void)
1277 {
1278  int result = 0;
1279  uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1280  uint16_t buflen = strlen((char *)buf);
1281  Packet *p;
1282  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1283 
1284  if (p == NULL)
1285  goto end;
1286 
1287  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;)";
1288 
1289  result = UTHPacketMatchSig(p, sig);
1290 
1291  UTHFreePacket(p);
1292 end:
1293  return result;
1294 }
1295 
1296 /**
1297  * \test check matches of with from_beginning (bug 626/627)
1298  */
1299 static int DetectByteJumpTestPacket05 (void)
1300 {
1301  int result = 0;
1302  uint8_t *buf = (uint8_t *)"XYZ04abcdABCD";
1303  uint16_t buflen = strlen((char *)buf);
1304  Packet *p;
1305  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1306 
1307  if (p == NULL)
1308  goto end;
1309 
1310  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;)";
1311 
1312  result = UTHPacketMatchSig(p, sig) ? 0 : 1;
1313 
1314  UTHFreePacket(p);
1315 end:
1316  return result;
1317 }
1318 
1319 /**
1320  * \test check matches of with from_beginning (bug 626/627)
1321  */
1322 static int DetectByteJumpTestPacket06 (void)
1323 {
1324  int result = 0;
1325  uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1326  uint16_t buflen = strlen((char *)buf);
1327  Packet *p;
1328  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1329 
1330  if (p == NULL)
1331  goto end;
1332 
1333  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;)";
1334 
1335  result = UTHPacketMatchSig(p, sig);
1336 
1337  UTHFreePacket(p);
1338 end:
1339  return result;
1340 }
1341 
1342 /**
1343  * \test check matches of with from_beginning (bug 626/627)
1344  */
1345 static int DetectByteJumpTestPacket07 (void)
1346 {
1347  int result = 0;
1348  uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1349  uint16_t buflen = strlen((char *)buf);
1350  Packet *p;
1351  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1352 
1353  if (p == NULL)
1354  goto end;
1355 
1356  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;)";
1357 
1358  result = UTHPacketMatchSig(p, sig) ? 1 : 0;
1359 
1360  UTHFreePacket(p);
1361 end:
1362  return result;
1363 }
1364 
1365 /**
1366  * \test check matches of with from_end
1367  */
1368 static int DetectByteJumpTestPacket08 (void)
1369 {
1370  uint8_t *buf = (uint8_t *)"XX04abcdABCD";
1371  uint16_t buflen = strlen((char *)buf);
1372  Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1373 
1374  FAIL_IF_NULL(p);
1375 
1376  char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,"
1377  "relative,string,dec,from_end, post_offset -8; content:\"ABCD\"; sid:1; rev:1;)";
1378 
1379  FAIL_IF_NOT(UTHPacketMatchSig(p, sig));
1380 
1381  UTHFreePacket(p);
1382 
1383  PASS;
1384 }
1385 
1386 /**
1387  * \brief this function registers unit tests for DetectBytejump
1388  */
1389 static void DetectBytejumpRegisterTests(void)
1390 {
1391  g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
1392  g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
1393 
1394  UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01);
1395  UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02);
1396  UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03);
1397  UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04);
1398  UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05);
1399  UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06);
1400  UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07);
1401  UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08);
1402  UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09);
1403  UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10);
1404  UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11);
1405  UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12);
1406  UtRegisterTest("DetectBytejumpTestParse13", DetectBytejumpTestParse13);
1407  UtRegisterTest("DetectBytejumpTestParse14", DetectBytejumpTestParse14);
1408 
1409  UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01);
1410  UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02);
1411  UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03);
1412  UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04);
1413  UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05);
1414  UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06);
1415  UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07);
1416  UtRegisterTest("DetectByteJumpTestPacket08", DetectByteJumpTestPacket08);
1417 }
1418 #endif /* UNITTESTS */
DetectBytejumpData_::post_offset
int32_t post_offset
Definition: detect-bytejump.h:50
util-byte.h
SigTableElmt_::url
const char * url
Definition: detect.h:1287
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
DetectSignatureSetAppProto
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:1703
detect-content.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
DetectEngineThreadCtx_::buffer_offset
uint32_t buffer_offset
Definition: detect.h:1102
detect-engine.h
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:110
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:437
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:566
SigTableElmt_::desc
const char * desc
Definition: detect.h:1286
ByteExtractUint64
int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes)
Definition: util-byte.c:122
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
ALPROTO_DCERPC
@ ALPROTO_DCERPC
Definition: app-layer-protos.h:38
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1274
PARSE_REGEX
#define PARSE_REGEX
Regex for parsing our options.
Definition: detect-bytejump.c:49
DetectParseRegex
Definition: detect-parse.h:62
SigTableElmt_::name
const char * name
Definition: detect.h:1284
DETECT_BYTEJUMP
@ DETECT_BYTEJUMP
Definition: detect-engine-register.h:76
SigFree
void SigFree(DetectEngineCtx *, Signature *)
Definition: detect-parse.c:1594
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
DETECT_BYTEJUMP_LITTLE
#define DETECT_BYTEJUMP_LITTLE
Definition: detect-bytejump.h:35
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:62
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
DETECT_BYTEJUMP_NBYTES_VAR
#define DETECT_BYTEJUMP_NBYTES_VAR
Definition: detect-bytejump.h:43
Packet_::payload
uint8_t * payload
Definition: decode.h:577
DETECT_BYTEJUMP_BASE_OCT
#define DETECT_BYTEJUMP_BASE_OCT
Definition: detect-bytejump.h:29
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:826
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2592
DE_QUIET
#define DE_QUIET
Definition: detect.h:314
UTHPacketMatchSig
int UTHPacketMatchSig(Packet *p, const char *sig)
Definition: util-unittest-helper.c:843
DETECT_BYTEJUMP_DCE
#define DETECT_BYTEJUMP_DCE
Definition: detect-bytejump.h:40
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:337
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:2623
DetectContentData_
Definition: detect-content.h:93
StringParseInt32
int StringParseInt32(int32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:622
DetectPcreData_::flags
uint16_t flags
Definition: detect-pcre.h:48
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:46
ByteExtractStringUint64
int ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:234
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:2569
DetectBufferGetActiveList
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine.c:1453
DETECT_BYTEJUMP_BIG
#define DETECT_BYTEJUMP_BIG
Definition: detect-bytejump.h:36
DetectBytejumpData_::base
uint8_t base
Definition: detect-bytejump.h:47
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1269
detect-pcre.h
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:578
DetectBytejumpData_
Definition: detect-bytejump.h:45
DetectByteIndexType
uint8_t DetectByteIndexType
Definition: detect-byte.h:28
util-unittest.h
DetectBytejumpData_::offset
int32_t offset
Definition: detect-bytejump.h:49
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
DetectBytejumpData_::multiplier
uint16_t multiplier
Definition: detect-bytejump.h:51
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1124
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
DetectBytejumpRegister
void DetectBytejumpRegister(void)
Definition: detect-bytejump.c:74
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1074
DETECT_BYTEJUMP_ALIGN
#define DETECT_BYTEJUMP_ALIGN
Definition: detect-bytejump.h:39
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2747
DETECT_BYTEJUMP_END
#define DETECT_BYTEJUMP_END
Definition: detect-bytejump.h:42
SignatureInitData_::list
int list
Definition: detect.h:550
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect.h
DetectBytejumpDoMatch
int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchCtx *ctx, const uint8_t *payload, uint32_t payload_len, uint16_t flags, int32_t nbytes, int32_t offset)
Byte jump match function.
Definition: detect-bytejump.c:138
StringParseU16RangeCheck
int StringParseU16RangeCheck(uint16_t *res, int base, size_t len, const char *str, uint16_t min, uint16_t max)
Definition: util-byte.c:433
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:344
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2264
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:343
BYTE_BIG_ENDIAN
#define BYTE_BIG_ENDIAN
Definition: util-byte.h:29
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2042
Packet_
Definition: decode.h:430
detect-engine-build.h
detect-bytejump.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DETECT_BYTEJUMP_BASE_UNSET
#define DETECT_BYTEJUMP_BASE_UNSET
Definition: detect-bytejump.h:28
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:653
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1252
detect-byte.h
DETECT_BYTEJUMP_BASE_HEX
#define DETECT_BYTEJUMP_BASE_HEX
Definition: detect-bytejump.h:31
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:322
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:64
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:335
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:135
DETECT_BYTETEST
@ DETECT_BYTETEST
Definition: detect-engine-register.h:75
BYTE_LITTLE_ENDIAN
#define BYTE_LITTLE_ENDIAN
Definition: util-byte.h:30
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
DetectByteRetrieveSMVar
bool DetectByteRetrieveSMVar(const char *arg, const Signature *s, DetectByteIndexType *index)
Used to retrieve args from BM.
Definition: detect-byte.c:39
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:341
detect-byte-extract.h
DetectBytejumpData_::nbytes
uint8_t nbytes
Definition: detect-bytejump.h:46
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:129
DetectBufferGetFirstSigMatch
SigMatch * DetectBufferGetFirstSigMatch(const Signature *s, const uint32_t buf_id)
Definition: detect-engine.c:1356
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
DETECT_BYTEJUMP_BASE_DEC
#define DETECT_BYTEJUMP_BASE_DEC
Definition: detect-bytejump.h:30
util-validate.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
str
#define str(s)
Definition: suricata-common.h:286
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:787
SCFree
#define SCFree(p)
Definition: util-mem.h:61
UTHFreePacket
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:485
DETECT_BYTE_EXTRACT
@ DETECT_BYTE_EXTRACT
Definition: detect-engine-register.h:178
detect-parse.h
Signature_
Signature container.
Definition: detect.h:581
SigMatch_
a single match condition for a signature
Definition: detect.h:340
payload_len
uint16_t payload_len
Definition: stream-tcp-private.h:1
DETECT_ISDATAAT
@ DETECT_ISDATAAT
Definition: detect-engine-register.h:82
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2553
DETECT_PCRE_RELATIVE_NEXT
#define DETECT_PCRE_RELATIVE_NEXT
Definition: detect-pcre.h:35
DetectPcreData_
Definition: detect-pcre.h:43
DETECT_BYTEMATH
@ DETECT_BYTEMATH
Definition: detect-engine-register.h:77
DETECT_BYTEJUMP_STRING
#define DETECT_BYTEJUMP_STRING
Definition: detect-bytejump.h:37
detect-uricontent.h
DetectGetLastSMFromLists
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
Definition: detect-parse.c:586
DETECT_BYTEJUMP_BEGIN
#define DETECT_BYTEJUMP_BEGIN
Definition: detect-bytejump.h:34
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:828
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1479
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:771
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:104
DETECT_BYTEJUMP_RELATIVE
#define DETECT_BYTEJUMP_RELATIVE
Definition: detect-bytejump.h:38
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1276
DetectBytejumpData_::flags
uint16_t flags
Definition: detect-bytejump.h:48
app-layer.h
DETECT_CONTENT_OFFSET_VAR
#define DETECT_CONTENT_OFFSET_VAR
Definition: detect-content.h:45