1 /* $Id$ */
2 /*
3 ** Copyright (C) 2003 Brian Caswell <bmc@snort.org>
4 ** Copyright (C) 2003 Michael J. Pomraning <mjp@securepipe.com>
5 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
6 ** Copyright (C) 2003-2013 Sourcefire, Inc.
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License Version 2 as
10 ** published by the Free Software Foundation. You may not use, modify or
11 ** distribute this program under any other version of the GNU General
12 ** Public License.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24 #include <sys/types.h>
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "sf_types.h"
31 #include "snort_bounds.h"
32 #include "rules.h"
33 #include "treenodes.h"
34 #include "snort_debug.h"
35 #include "decode.h"
36 #include "plugbase.h"
37 #include "parser.h"
38 #include "plugin_enum.h"
39 #include "util.h"
40 #include "mstring.h"
41 #include "sfhashfcn.h"
42
43 #ifdef WIN32
44 #define PCRE_DEFINITION
45 #endif
46
47 #include "sp_pcre.h"
48
49 #include <pcre.h>
50
51 #include "snort.h"
52 #include "profiler.h"
53 #ifdef PERF_PROFILING
54 PreprocStats pcrePerfStats;
55 extern PreprocStats ruleOTNEvalPerfStats;
56 #endif
57
58 #include "sfhashfcn.h"
59 #include "detection_options.h"
60 #include "detection_util.h"
61
62 /*
63 * we need to specify the vector length for our pcre_exec call. we only care
64 * about the first vector, which if the match is successful will include the
65 * offset to the end of the full pattern match. If we decide to store other
66 * matches, make *SURE* that this is a multiple of 3 as pcre requires it.
67 */
68 static int s_pcre_init = 1;
69
70 void SnortPcreInit(struct _SnortConfig *, char *, OptTreeNode *, int);
71 void SnortPcreParse(struct _SnortConfig *, char *, PcreData *, OptTreeNode *);
72 void SnortPcreDump(PcreData *);
73 int SnortPcre(void *option_data, Packet *p);
74
PcreFree(void * d)75 void PcreFree(void *d)
76 {
77 PcreData *data = (PcreData *)d;
78
79 free(data->expression);
80 free(data->re);
81 free(data->pe);
82 free(data);
83 }
84
PcreHash(void * d)85 uint32_t PcreHash(void *d)
86 {
87 int i,j,k,l,expression_len;
88 uint32_t a,b,c,tmp;
89 PcreData *data = (PcreData *)d;
90
91 expression_len = strlen(data->expression);
92 a = b = c = 0;
93
94 for (i=0,j=0;i<expression_len;i+=4)
95 {
96 tmp = 0;
97 k = expression_len - i;
98 if (k > 4)
99 k=4;
100
101 for (l=0;l<k;l++)
102 {
103 tmp |= *(data->expression + i + l) << l*8;
104 }
105
106 switch (j)
107 {
108 case 0:
109 a += tmp;
110 break;
111 case 1:
112 b += tmp;
113 break;
114 case 2:
115 c += tmp;
116 break;
117 }
118 j++;
119
120 if (j == 3)
121 {
122 mix(a,b,c);
123 j=0;
124 }
125 }
126
127 if (j != 0)
128 {
129 mix(a,b,c);
130 }
131
132 a += RULE_OPTION_TYPE_PCRE;
133 b += data->options;
134
135 final(a,b,c);
136
137 return c;
138 }
139
PcreCompare(void * l,void * r)140 int PcreCompare(void *l, void *r)
141 {
142 PcreData *left = (PcreData *)l;
143 PcreData *right = (PcreData *)r;
144
145 if (!left || !right)
146 return DETECTION_OPTION_NOT_EQUAL;
147
148 if (( strcmp(left->expression, right->expression) == 0) &&
149 ( left->options == right->options))
150 {
151 return DETECTION_OPTION_EQUAL;
152 }
153
154 return DETECTION_OPTION_NOT_EQUAL;
155 }
156
PcreDuplicatePcreData(void * src,PcreData * pcre_dup)157 void PcreDuplicatePcreData(void *src, PcreData *pcre_dup)
158 {
159 PcreData *pcre_src = (PcreData *)src;
160
161 pcre_dup->expression = pcre_src->expression;
162 pcre_dup->options = pcre_src->options;
163 pcre_dup->search_offset = 0;
164 pcre_dup->pe = pcre_src->pe;
165 pcre_dup->re = pcre_src->re;
166 }
167
PcreAdjustRelativeOffsets(PcreData * pcre,uint32_t search_offset)168 int PcreAdjustRelativeOffsets(PcreData *pcre, uint32_t search_offset)
169 {
170 if ((pcre->options & (SNORT_PCRE_INVERT | SNORT_PCRE_ANCHORED)))
171 {
172 return 0; /* Don't search again */
173 }
174
175 if (pcre->options & ( SNORT_PCRE_HTTP_BUFS ))
176 {
177 return 0;
178 }
179
180 /* What's coming in has the absolute offset */
181 pcre->search_offset += search_offset;
182
183 return 1; /* Continue searcing */
184 }
185
SetupPcre(void)186 void SetupPcre(void)
187 {
188 RegisterRuleOption("pcre", SnortPcreInit, NULL, OPT_TYPE_DETECTION, NULL);
189 #ifdef PERF_PROFILING
190 RegisterPreprocessorProfile("pcre", &pcrePerfStats, 3, &ruleOTNEvalPerfStats, NULL);
191 #endif
192 }
193
Ovector_Init(struct _SnortConfig * sc,int unused,void * data)194 static void Ovector_Init(struct _SnortConfig *sc, int unused, void *data)
195 {
196 /* Since SO rules are loaded 1 time at startup, regardless of
197 * configuraton, we won't pcre capture count again, so save the max. */
198 static int s_ovector_max = 0;
199
200 /* The pcre_fullinfo() function can be used to find out how many
201 * capturing subpatterns there are in a compiled pattern. The
202 * smallest size for ovector that will allow for n captured
203 * substrings, in addition to the offsets of the substring matched
204 * by the whole pattern, is (n+1)*3. */
205 sc->pcre_ovector_size += 1;
206 sc->pcre_ovector_size *= 3;
207
208 if (sc->pcre_ovector_size > s_ovector_max)
209 s_ovector_max = sc->pcre_ovector_size;
210
211 sc->pcre_ovector = (int *) SnortAlloc(s_ovector_max*sizeof(int));
212 }
213
214 #if SNORT_RELOAD
Ovector_Reload(struct _SnortConfig * sc,int unused,void * data)215 static void Ovector_Reload(struct _SnortConfig *sc, int unused, void *data)
216 {
217 Ovector_Init(sc, unused, data);
218 }
219 #endif
220
PcreCapture(struct _SnortConfig * sc,const void * code,const void * extra)221 void PcreCapture(struct _SnortConfig *sc, const void *code, const void *extra)
222 {
223 int tmp_ovector_size = 0;
224
225 pcre_fullinfo((const pcre *)code, (const pcre_extra *)extra,
226 PCRE_INFO_CAPTURECOUNT, &tmp_ovector_size);
227
228 if (tmp_ovector_size > sc->pcre_ovector_size)
229 sc->pcre_ovector_size = tmp_ovector_size;
230
231 if (s_pcre_init)
232 {
233 AddFuncToPostConfigList(sc, Ovector_Init, NULL);
234 #if SNORT_RELOAD
235 AddFuncToReloadList(Ovector_Reload, NULL);
236 #endif
237 s_pcre_init = 0;
238 }
239
240 }
241
SnortPcreInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)242 void SnortPcreInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
243 {
244 PcreData *pcre_data;
245 OptFpList *fpl;
246 void *pcre_dup;
247
248 /*
249 * allocate the data structure for pcre
250 */
251 pcre_data = (PcreData *) SnortAlloc(sizeof(PcreData));
252
253 SnortPcreParse(sc, data, pcre_data, otn);
254
255 otn->pcre_flag = 1;
256
257 fpl = AddOptFuncToList(SnortPcre, otn);
258 fpl->type = RULE_OPTION_TYPE_PCRE;
259
260 if (add_detection_option(sc, RULE_OPTION_TYPE_PCRE, (void *)pcre_data, &pcre_dup) == DETECTION_OPTION_EQUAL)
261 {
262 #ifdef DEBUG_RULE_OPTION_TREE
263 LogMessage("Duplicate PCRE:\n%d %s\n%d %s\n\n",
264 pcre_data->options, pcre_data->expression,
265 ((PcreData *)pcre_dup)->options,
266 ((PcreData *)pcre_dup)->expression);
267 #endif
268
269 if (pcre_data->expression)
270 free(pcre_data->expression);
271 if (pcre_data->pe)
272 free(pcre_data->pe);
273 if (pcre_data->re)
274 free(pcre_data->re);
275
276 free(pcre_data);
277 pcre_data = pcre_dup;
278 }
279
280 /*
281 * attach it to the context node so that we can call each instance
282 * individually
283 */
284 fpl->context = (void *) pcre_data;
285
286 if (pcre_data->options & SNORT_PCRE_RELATIVE)
287 fpl->isRelative = 1;
288
289 if (otn->ds_list[PLUGIN_PCRE] == NULL)
290 otn->ds_list[PLUGIN_PCRE] = (void *)pcre_data;
291
292 return;
293 }
294
ValidatePcreHttpContentModifiers(PcreData * pcre_data)295 static inline void ValidatePcreHttpContentModifiers(PcreData *pcre_data)
296 {
297 if( pcre_data->options & SNORT_PCRE_RELATIVE )
298 FatalError("%s(%d): PCRE unsupported configuration : both relative & uri options specified\n",
299 file_name, file_line);
300
301 if( pcre_data->options & SNORT_PCRE_RAWBYTES )
302 FatalError("%s(%d): PCRE unsupported configuration : both rawbytes & uri options specified\n",
303 file_name, file_line);
304 }
305
SnortPcreParse(struct _SnortConfig * sc,char * data,PcreData * pcre_data,OptTreeNode * otn)306 void SnortPcreParse(struct _SnortConfig *sc, char *data, PcreData *pcre_data, OptTreeNode *otn)
307 {
308 const char *error;
309 char *re, *free_me;
310 char *opts;
311 char delimit = '/';
312 int erroffset;
313 int compile_flags = 0;
314 unsigned http = 0;
315
316 if(data == NULL)
317 {
318 FatalError("%s (%d): pcre requires a regular expression\n",
319 file_name, file_line);
320 }
321
322 free_me = SnortStrdup(data);
323 re = free_me;
324
325 /* get rid of starting and ending whitespace */
326 while (isspace((int)re[strlen(re)-1])) re[strlen(re)-1] = '\0';
327 while (isspace((int)*re)) re++;
328
329 if(*re == '!') {
330 pcre_data->options |= SNORT_PCRE_INVERT;
331 re++;
332 while(isspace((int)*re)) re++;
333 }
334
335 /* now we wrap the RE in double quotes. stupid snort parser.... */
336 if(*re != '"') {
337 printf("It isn't \"\n");
338 goto syntax;
339 }
340 re++;
341
342 if(re[strlen(re)-1] != '"')
343 {
344 printf("It isn't \"\n");
345 goto syntax;
346 }
347
348 /* remove the last quote from the string */
349 re[strlen(re) - 1] = '\0';
350
351 /* 'm//' or just '//' */
352
353 if(*re == 'm')
354 {
355 re++;
356 if(! *re) goto syntax;
357
358 /* Space as a ending delimiter? Uh, no. */
359 if(isspace((int)*re)) goto syntax;
360 /* using R would be bad, as it triggers RE */
361 if(*re == 'R') goto syntax;
362
363 delimit = *re;
364 }
365 else if(*re != delimit)
366 goto syntax;
367
368 pcre_data->expression = SnortStrdup(re);
369
370 /* find ending delimiter, trim delimit chars */
371 opts = strrchr(re, delimit);
372 if (opts == NULL)
373 goto syntax;
374
375 if(!((opts - re) > 1)) /* empty regex(m||) or missing delim not OK */
376 goto syntax;
377
378 re++;
379 *opts++ = '\0';
380
381 /* process any /regex/ismxR options */
382 while(*opts != '\0') {
383 switch(*opts) {
384 case 'i': compile_flags |= PCRE_CASELESS; break;
385 case 's': compile_flags |= PCRE_DOTALL; break;
386 case 'm': compile_flags |= PCRE_MULTILINE; break;
387 case 'x': compile_flags |= PCRE_EXTENDED; break;
388
389 /*
390 * these are pcre specific... don't work with perl
391 */
392 case 'A': compile_flags |= PCRE_ANCHORED; break;
393 case 'E': compile_flags |= PCRE_DOLLAR_ENDONLY; break;
394 case 'G': compile_flags |= PCRE_UNGREEDY; break;
395
396 /*
397 * these are snort specific don't work with pcre or perl
398 */
399 case 'R': pcre_data->options |= SNORT_PCRE_RELATIVE; break;
400 case 'B': pcre_data->options |= SNORT_PCRE_RAWBYTES; break;
401 case 'O': pcre_data->options |= SNORT_OVERRIDE_MATCH_LIMIT; break;
402 case 'U': pcre_data->options |= SNORT_PCRE_HTTP_URI; http++; break;
403 case 'P': pcre_data->options |= SNORT_PCRE_HTTP_BODY; http++; break;
404 case 'H': pcre_data->options |= SNORT_PCRE_HTTP_HEADER; http++; break;
405 case 'M': pcre_data->options |= SNORT_PCRE_HTTP_METHOD; http++; break;
406 case 'C': pcre_data->options |= SNORT_PCRE_HTTP_COOKIE; http++; break;
407 case 'I': pcre_data->options |= SNORT_PCRE_HTTP_RAW_URI; http++; break;
408 case 'D': pcre_data->options |= SNORT_PCRE_HTTP_RAW_HEADER; http++; break;
409 case 'K': pcre_data->options |= SNORT_PCRE_HTTP_RAW_COOKIE; http++; break;
410 case 'S': pcre_data->options |= SNORT_PCRE_HTTP_STAT_CODE; http++; break;
411 case 'Y': pcre_data->options |= SNORT_PCRE_HTTP_STAT_MSG; http++; break;
412
413 default:
414 FatalError("%s (%d): unknown/extra pcre option encountered\n", file_name, file_line);
415 }
416 opts++;
417 }
418
419 if ( http > 1 )
420 ParseWarning("at most one HTTP buffer may be indicated with pcre");
421
422 if(pcre_data->options & (SNORT_PCRE_HTTP_BUFS))
423 ValidatePcreHttpContentModifiers(pcre_data);
424
425 /* now compile the re */
426 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre: compiling %s\n", re););
427 pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, NULL);
428
429 if(pcre_data->re == NULL)
430 {
431 FatalError("%s(%d) : pcre compile of \"%s\" failed at offset "
432 "%d : %s\n", file_name, file_line, re, erroffset, error);
433 }
434
435
436 /* now study it... */
437 pcre_data->pe = pcre_study(pcre_data->re, 0, &error);
438
439 if (pcre_data->pe)
440 {
441 if ((ScPcreMatchLimitNewConf(sc) != -1) && !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
442 {
443 if (pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT)
444 {
445 pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc);
446 }
447 else
448 {
449 pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
450 pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc);
451 }
452 }
453
454 #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
455 if ((ScPcreMatchLimitRecursionNewConf(sc) != -1) && !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
456 {
457 if (pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION)
458 {
459 pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc);
460 }
461 else
462 {
463 pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
464 pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc);
465 }
466 }
467 #endif
468 }
469 else
470 {
471 if (!(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT) &&
472 ((ScPcreMatchLimitNewConf(sc) != -1) || (ScPcreMatchLimitRecursionNewConf(sc) != -1)))
473 {
474 pcre_data->pe = (pcre_extra *)SnortAlloc(sizeof(pcre_extra));
475 if (ScPcreMatchLimitNewConf(sc) != -1)
476 {
477 pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
478 pcre_data->pe->match_limit = ScPcreMatchLimitNewConf(sc);
479 }
480
481 #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
482 if (ScPcreMatchLimitRecursionNewConf(sc) != -1)
483 {
484 pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
485 pcre_data->pe->match_limit_recursion = ScPcreMatchLimitRecursionNewConf(sc);
486 }
487 #endif
488 }
489 }
490
491 if(error != NULL)
492 {
493 FatalError("%s(%d) : pcre study failed : %s\n", file_name,
494 file_line, error);
495 }
496
497 PcreCapture(sc, pcre_data->re, pcre_data->pe);
498
499 PcreCheckAnchored(pcre_data);
500
501 free(free_me);
502
503 return;
504
505 syntax:
506 free(free_me);
507
508 FatalError("%s Line %d => unable to parse pcre regex %s\n",
509 file_name, file_line, data);
510
511 }
512
PcreCheckAnchored(PcreData * pcre_data)513 void PcreCheckAnchored(PcreData *pcre_data)
514 {
515 int rc;
516 unsigned long int options = 0;
517
518 if ((pcre_data == NULL) || (pcre_data->re == NULL) || (pcre_data->pe == NULL))
519 return;
520
521 rc = pcre_fullinfo(pcre_data->re, pcre_data->pe, PCRE_INFO_OPTIONS, (void *)&options);
522 switch (rc)
523 {
524 /* pcre_fullinfo fails for the following:
525 * PCRE_ERROR_NULL - the argument code was NULL
526 * the argument where was NULL
527 * PCRE_ERROR_BADMAGIC - the "magic number" was not found
528 * PCRE_ERROR_BADOPTION - the value of what was invalid
529 * so a failure here means we passed in bad values and we should
530 * probably fatal error */
531
532 case 0:
533 /* This is the success code */
534 break;
535
536 case PCRE_ERROR_NULL:
537 FatalError("%s(%d) pcre_fullinfo: code and/or where were NULL.\n",
538 __FILE__, __LINE__);
539
540 case PCRE_ERROR_BADMAGIC:
541 FatalError("%s(%d) pcre_fullinfo: compiled code didn't have "
542 "correct magic.\n", __FILE__, __LINE__);
543
544 case PCRE_ERROR_BADOPTION:
545 FatalError("%s(%d) pcre_fullinfo: option type is invalid.\n",
546 __FILE__, __LINE__);
547
548 default:
549 FatalError("%s(%d) pcre_fullinfo: Unknown error code.\n",
550 __FILE__, __LINE__);
551 }
552
553 if ((options & PCRE_ANCHORED) && !(options & PCRE_MULTILINE))
554 {
555 /* This means that this pcre rule option shouldn't be reevaluted
556 * even if any of it's relative children should fail to match.
557 * It is anchored to the cursor set by the previous cursor setting
558 * rule option */
559 pcre_data->options |= SNORT_PCRE_ANCHORED;
560 }
561 }
562
563 /**
564 * Perform a search of the PCRE data.
565 *
566 * @param pcre_data structure that options and patterns are passed in
567 * @param buf buffer to search
568 * @param len size of buffer
569 * @param start_offset initial offset into the buffer
570 * @param found_offset pointer to an integer so that we know where the search ended
571 *
572 * *found_offset will be set to -1 when the find is unsucessful OR the routine is inverted
573 *
574 * @return 1 when we find the string, 0 when we don't (unless we've been passed a flag to invert)
575 */
pcre_search(const PcreData * pcre_data,const char * buf,int len,int start_offset,int * found_offset)576 static int pcre_search(const PcreData *pcre_data,
577 const char *buf,
578 int len,
579 int start_offset,
580 int *found_offset)
581 {
582 int matched;
583 int result;
584
585 if(pcre_data == NULL
586 || buf == NULL
587 || len <= 0
588 || start_offset < 0
589 || start_offset >= len
590 || found_offset == NULL)
591 {
592 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
593 "Returning 0 because we didn't have the required parameters!\n"););
594 return 0;
595 }
596
597 *found_offset = -1;
598
599 result = pcre_exec(pcre_data->re, /* result of pcre_compile() */
600 pcre_data->pe, /* result of pcre_study() */
601 buf, /* the subject string */
602 len, /* the length of the subject string */
603 start_offset, /* start at offset 0 in the subject */
604 0, /* options(handled at compile time */
605 snort_conf->pcre_ovector, /* vector for substring information */
606 snort_conf->pcre_ovector_size);/* number of elements in the vector */
607
608 if(result >= 0)
609 {
610 matched = 1;
611 /* From the PCRE man page:
612 * When a match is successful, information about captured substrings is returned in pairs of integers,
613 * starting at the beginning of ovector, and continuing up to two-thirds of its length at the most.
614 * The first element of a pair is set to the offset of the first character in a substring, and the
615 * second is set to the offset of the first character after the end of a substring. The first pair,
616 * ovector[0] and ovector[1], identify the portion of the subject string matched by the entire pattern.
617 * The next pair is used for the first capturing subpattern, and so on. The value returned by
618 * pcre_exec() is the number of pairs that have been set. If there are no capturing subpatterns, the
619 * return value from a successful match is 1, indicating that just the first pair of offsets has been set.
620 *
621 * In Snort's case, the ovector size only allows for the first pair and a single int for scratch space.
622 */
623 *found_offset = snort_conf->pcre_ovector[1];
624 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
625 "Setting Doe_ptr and found_offset: %p %d\n",
626 doe_ptr, found_offset););
627 }
628 else if(result == PCRE_ERROR_NOMATCH)
629 {
630 matched = 0;
631 }
632 else
633 {
634 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result););
635 return 0;
636 }
637
638 /* invert sense of match */
639 if(pcre_data->options & SNORT_PCRE_INVERT)
640 {
641 matched = !matched;
642 }
643
644 return matched;
645 }
646
SnortPcre(void * option_data,Packet * p)647 int SnortPcre(void *option_data, Packet *p)
648 {
649 PcreData *pcre_data = (PcreData *)option_data;
650 int found_offset = -1; /* where is the ending location of the pattern */
651 const uint8_t *base_ptr, *end_ptr, *start_ptr;
652 int dsize;
653 int length; /* length of the buffer pointed to by base_ptr */
654 int matched = 0;
655 uint8_t rst_doe_flags = 1;
656 unsigned hb_type;
657 DEBUG_WRAP(char *hexbuf;)
658
659 PROFILE_VARS;
660 PREPROC_PROFILE_START(pcrePerfStats);
661
662 //short circuit this for testing pcre performance impact
663 if (ScNoPcre())
664 {
665 PREPROC_PROFILE_END(pcrePerfStats);
666 return DETECTION_OPTION_NO_MATCH;
667 }
668
669 /* This is the HTTP case */
670 if ( (hb_type = pcre_data->options & SNORT_PCRE_HTTP_BUFS) )
671 {
672 const HttpBuffer* hb = GetHttpBuffer(hb_type);
673
674 if ( hb )
675 {
676 matched = pcre_search(
677 pcre_data, (const char*)hb->buf, hb->length, 0, &found_offset);
678
679 if ( matched )
680 {
681 /* don't touch doe_ptr on URI contents */
682 PREPROC_PROFILE_END(pcrePerfStats);
683 return DETECTION_OPTION_MATCH;
684 }
685 }
686 PREPROC_PROFILE_END(pcrePerfStats);
687 return DETECTION_OPTION_NO_MATCH;
688 }
689 /* end of the HTTP case */
690
691 if( !(pcre_data->options & SNORT_PCRE_RAWBYTES))
692 {
693 if(Is_DetectFlag(FLAG_ALT_DETECT))
694 {
695 dsize = DetectBuffer.len;
696 start_ptr = DetectBuffer.data;
697 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
698 "using alternative detect buffer in pcre!\n"););
699 }
700 else if(Is_DetectFlag(FLAG_ALT_DECODE))
701 {
702 dsize = DecodeBuffer.len;
703 start_ptr = DecodeBuffer.data;
704 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
705 "using alternative decode buffer in pcre!\n"););
706 }
707 else
708 {
709 if(IsLimitedDetect(p))
710 dsize = p->alt_dsize;
711 else
712 dsize = p->dsize;
713 start_ptr = p->data;
714 }
715 }
716 else
717 {
718 dsize = p->dsize;
719 start_ptr = p->data;
720 }
721
722 base_ptr = start_ptr;
723 end_ptr = start_ptr + dsize;
724
725 /* doe_ptr's would be set by the previous content option */
726 if(pcre_data->options & SNORT_PCRE_RELATIVE && doe_ptr)
727 {
728 if(!inBounds(start_ptr, end_ptr, doe_ptr))
729 {
730 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
731 "pcre bounds check failed on a relative content match\n"););
732 PREPROC_PROFILE_END(pcrePerfStats);
733 return DETECTION_OPTION_NO_MATCH;
734 }
735
736 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
737 "pcre ... checking relative offset\n"););
738 base_ptr = doe_ptr;
739 rst_doe_flags = 0;
740 }
741 else
742 {
743 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
744 "pcre ... checking absolute offset\n"););
745 base_ptr = start_ptr;
746 }
747
748 length = end_ptr - base_ptr;
749
750 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
751 "pcre ... base: %p start: %p end: %p doe: %p length: %d\n",
752 base_ptr, start_ptr, end_ptr, doe_ptr, length););
753
754 DEBUG_WRAP(hexbuf = hex(base_ptr, length);
755 DebugMessage(DEBUG_PATTERN_MATCH, "pcre payload: %s\n", hexbuf);
756 free(hexbuf);
757 );
758
759 matched = pcre_search(pcre_data, (const char *)base_ptr, length, pcre_data->search_offset, &found_offset);
760
761 /* set the doe_ptr if we have a valid offset */
762 if(found_offset > 0)
763 {
764 UpdateDoePtr(((uint8_t *) base_ptr + found_offset), rst_doe_flags);
765 }
766
767 if (matched)
768 {
769 PREPROC_PROFILE_END(pcrePerfStats);
770 return DETECTION_OPTION_MATCH;
771 }
772
773 /* finally return 0 */
774 PREPROC_PROFILE_END(pcrePerfStats);
775 return DETECTION_OPTION_NO_MATCH;
776 }
777