1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2007-2013 Sourcefire, Inc.
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation.  You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 **
21 **/
22 
23 /**
24 **  @file        detection_options.c
25 **
26 **  @author      Steven Sturges
27 **
28 **  @brief       Support functions for rule option tree
29 **
30 **  This implements tree processing for rule options, evaluating common
31 **  detection options only once per pattern match.
32 **
33 */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include "sfutil/sfxhash.h"
40 #include "sfutil/sfhashfcn.h"
41 #include "detection_options.h"
42 #include "detection_util.h"
43 #include "rules.h"
44 #include "treenodes.h"
45 #include "util.h"
46 #include "fpcreate.h"
47 #include "parser.h"
48 
49 #include "sp_asn1.h"
50 #include "sp_byte_check.h"
51 #include "sp_byte_jump.h"
52 #include "sp_byte_extract.h"
53 #include "sp_byte_math.h"
54 #include "sp_clientserver.h"
55 #include "sp_cvs.h"
56 #include "sp_dsize_check.h"
57 #include "sp_flowbits.h"
58 #include "sp_ftpbounce.h"
59 #include "sp_icmp_code_check.h"
60 #include "sp_icmp_id_check.h"
61 #include "sp_icmp_seq_check.h"
62 #include "sp_icmp_type_check.h"
63 #include "sp_ip_fragbits.h"
64 #include "sp_ip_id_check.h"
65 #include "sp_ipoption_check.h"
66 #include "sp_ip_proto.h"
67 #include "sp_ip_same_check.h"
68 #include "sp_ip_tos_check.h"
69 #include "sp_file_data.h"
70 #include "sp_base64_decode.h"
71 #include "sp_isdataat.h"
72 #include "sp_pattern_match.h"
73 #include "sp_pcre.h"
74 #ifdef ENABLE_REACT
75 #include "sp_react.h"
76 #endif
77 #include "sp_replace.h"
78 #ifdef ENABLE_RESPOND
79 #include "sp_respond.h"
80 #endif
81 #include "sp_rpc_check.h"
82 #include "sp_session.h"
83 #include "sp_tcp_ack_check.h"
84 #include "sp_tcp_flag_check.h"
85 #include "sp_tcp_seq_check.h"
86 #include "sp_tcp_win_check.h"
87 #include "sp_ttl_check.h"
88 #include "sp_urilen_check.h"
89 #include "sp_hdr_opt_wrap.h"
90 # include "sp_file_type.h"
91 
92 #include "sp_preprocopt.h"
93 #include "sp_dynamic.h"
94 
95 #include "fpdetect.h"
96 #include "ppm.h"
97 #include "profiler.h"
98 #include "sfPolicy.h"
99 #include "detection_filter.h"
100 #include "encode.h"
101 #if defined(FEAT_OPEN_APPID)
102 #include "stream_common.h"
103 #include "sp_appid.h"
104 #endif /* defined(FEAT_OPEN_APPID) */
105 
106 typedef struct _detection_option_key
107 {
108     option_type_t option_type;
109     void *option_data;
110 } detection_option_key_t;
111 
112 #define HASH_RULE_OPTIONS 16384
113 #define HASH_RULE_TREE 8192
114 
detection_option_hash_func(SFHASHFCN * p,unsigned char * k,int n)115 uint32_t detection_option_hash_func(SFHASHFCN *p, unsigned char *k, int n)
116 {
117     uint32_t hash = 0;
118     detection_option_key_t *key = (detection_option_key_t*)k;
119 
120     switch (key->option_type)
121     {
122         /* Call hash function specific to the key type */
123         case RULE_OPTION_TYPE_ASN1:
124             hash = Asn1Hash(key->option_data);
125             break;
126         case RULE_OPTION_TYPE_BYTE_TEST:
127             hash = ByteTestHash(key->option_data);
128             break;
129         case RULE_OPTION_TYPE_BYTE_JUMP:
130             hash = ByteJumpHash(key->option_data);
131             break;
132         case RULE_OPTION_TYPE_BYTE_EXTRACT:
133             hash = ByteExtractHash(key->option_data);
134             break;
135         case RULE_OPTION_TYPE_BYTE_MATH:
136             hash = ByteMathHash(key->option_data);
137             break;
138         case RULE_OPTION_TYPE_FLOW:
139             hash = FlowHash(key->option_data);
140             break;
141         case RULE_OPTION_TYPE_CVS:
142             hash = CvsHash(key->option_data);
143             break;
144         case RULE_OPTION_TYPE_DSIZE:
145             hash = DSizeCheckHash(key->option_data);
146             break;
147         case RULE_OPTION_TYPE_FLOWBIT:
148             hash = FlowBitsHash(key->option_data);
149             break;
150         case RULE_OPTION_TYPE_FTPBOUNCE:
151             break;
152         case RULE_OPTION_TYPE_FILE_DATA:
153             hash = FileDataHash(key->option_data);
154             break;
155         case RULE_OPTION_TYPE_BASE64_DECODE:
156             hash = Base64DecodeHash(key->option_data);
157             break;
158         case RULE_OPTION_TYPE_BASE64_DATA:
159             break;
160         case RULE_OPTION_TYPE_PKT_DATA:
161             break;
162         case RULE_OPTION_TYPE_ICMP_CODE:
163             hash = IcmpCodeCheckHash(key->option_data);
164             break;
165         case RULE_OPTION_TYPE_ICMP_ID:
166             hash = IcmpIdCheckHash(key->option_data);
167             break;
168         case RULE_OPTION_TYPE_ICMP_SEQ:
169             hash = IcmpSeqCheckHash(key->option_data);
170             break;
171         case RULE_OPTION_TYPE_ICMP_TYPE:
172             hash = IcmpTypeCheckHash(key->option_data);
173             break;
174         case RULE_OPTION_TYPE_IP_FRAGBITS:
175             hash = IpFragBitsCheckHash(key->option_data);
176             break;
177         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
178             hash = IpFragOffsetCheckHash(key->option_data);
179             break;
180         case RULE_OPTION_TYPE_IP_ID:
181             hash = IpIdCheckHash(key->option_data);
182             break;
183         case RULE_OPTION_TYPE_IP_OPTION:
184             hash = IpOptionCheckHash(key->option_data);
185             break;
186         case RULE_OPTION_TYPE_IP_PROTO:
187             hash = IpProtoCheckHash(key->option_data);
188             break;
189         case RULE_OPTION_TYPE_IP_SAME:
190             hash = IpSameCheckHash(key->option_data);
191             break;
192         case RULE_OPTION_TYPE_IP_TOS:
193             hash = IpTosCheckHash(key->option_data);
194             break;
195         case RULE_OPTION_TYPE_IS_DATA_AT:
196             hash = IsDataAtHash(key->option_data);
197             break;
198         case RULE_OPTION_TYPE_CONTENT:
199         case RULE_OPTION_TYPE_CONTENT_URI:
200             hash = PatternMatchHash(key->option_data);
201             break;
202         case RULE_OPTION_TYPE_PCRE:
203             hash = PcreHash(key->option_data);
204             break;
205 #ifdef ENABLE_REACT
206         case RULE_OPTION_TYPE_REACT:
207             hash = ReactHash(key->option_data);
208             break;
209 #endif
210 #ifdef ENABLE_RESPOND
211         case RULE_OPTION_TYPE_RESPOND:
212             hash = RespondHash(key->option_data);
213             break;
214 #endif
215         case RULE_OPTION_TYPE_RPC_CHECK:
216             hash = RpcCheckHash(key->option_data);
217             break;
218         case RULE_OPTION_TYPE_SESSION:
219             hash = SessionHash(key->option_data);
220             break;
221         case RULE_OPTION_TYPE_TCP_ACK:
222             hash = TcpAckCheckHash(key->option_data);
223             break;
224         case RULE_OPTION_TYPE_TCP_FLAG:
225             hash = TcpFlagCheckHash(key->option_data);
226             break;
227         case RULE_OPTION_TYPE_TCP_SEQ:
228             hash = TcpSeqCheckHash(key->option_data);
229             break;
230         case RULE_OPTION_TYPE_TCP_WIN:
231             hash = TcpWinCheckHash(key->option_data);
232             break;
233         case RULE_OPTION_TYPE_TTL:
234             hash = TtlCheckHash(key->option_data);
235             break;
236         case RULE_OPTION_TYPE_URILEN:
237             hash = UriLenCheckHash(key->option_data);
238             break;
239         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
240             hash = HdrOptCheckHash(key->option_data);
241             break;
242         case RULE_OPTION_TYPE_FILE_TYPE:
243             hash = FileTypeHash(key->option_data);
244             break;
245         case RULE_OPTION_TYPE_PREPROCESSOR:
246             hash = PreprocessorRuleOptionHash(key->option_data);
247             break;
248         case RULE_OPTION_TYPE_DYNAMIC:
249             hash = DynamicRuleHash(key->option_data);
250             break;
251         case RULE_OPTION_TYPE_LEAF_NODE:
252             hash = 0;
253             break;
254 #if defined(FEAT_OPEN_APPID)
255         case RULE_OPTION_TYPE_APPID:
256             hash = optionAppIdHash(key->option_data);
257             break;
258 #endif /* defined(FEAT_OPEN_APPID) */
259     }
260 
261     return hash;
262 }
263 
detection_option_key_compare_func(const void * k1,const void * k2,size_t n)264 int detection_option_key_compare_func(const void *k1, const void *k2, size_t n)
265 {
266     int ret = DETECTION_OPTION_NOT_EQUAL;
267     const detection_option_key_t *key1 = (detection_option_key_t*)k1;
268     const detection_option_key_t *key2 = (detection_option_key_t*)k2;
269 
270 #ifdef KEEP_THEM_ALLOCATED
271     return DETECTION_OPTION_NOT_EQUAL;
272 #endif
273 
274     if (!key1 || !key2)
275         return DETECTION_OPTION_NOT_EQUAL;
276 
277     if (key1->option_type != key2->option_type)
278         return DETECTION_OPTION_NOT_EQUAL;
279 
280     switch (key1->option_type)
281     {
282         /* Call compare function specific to the key type */
283         case RULE_OPTION_TYPE_LEAF_NODE:
284             /* Leaf node always not equal. */
285             break;
286         case RULE_OPTION_TYPE_ASN1:
287             ret = Asn1Compare(key1->option_data, key2->option_data);
288             break;
289         case RULE_OPTION_TYPE_BYTE_TEST:
290             ret = ByteTestCompare(key1->option_data, key2->option_data);
291             break;
292         case RULE_OPTION_TYPE_BYTE_JUMP:
293             ret = ByteJumpCompare(key1->option_data, key2->option_data);
294             break;
295         case RULE_OPTION_TYPE_BYTE_EXTRACT:
296             ret = ByteExtractCompare(key1->option_data, key2->option_data);
297             break;
298         case RULE_OPTION_TYPE_BYTE_MATH:
299             ret = ByteMathCompare(key1->option_data, key2->option_data);
300             break;
301         case RULE_OPTION_TYPE_FLOW:
302             ret = FlowCompare(key1->option_data, key2->option_data);
303             break;
304         case RULE_OPTION_TYPE_CVS:
305             ret = CvsCompare(key1->option_data, key2->option_data);
306             break;
307         case RULE_OPTION_TYPE_DSIZE:
308             ret = DSizeCheckCompare(key1->option_data, key2->option_data);
309             break;
310         case RULE_OPTION_TYPE_FLOWBIT:
311             ret = FlowBitsCompare(key1->option_data, key2->option_data);
312             break;
313         case RULE_OPTION_TYPE_FTPBOUNCE:
314             break;
315         case RULE_OPTION_TYPE_FILE_DATA:
316             ret = FileDataCompare(key1->option_data, key2->option_data);
317             break;
318         case RULE_OPTION_TYPE_BASE64_DECODE:
319             ret = Base64DecodeCompare(key1->option_data, key2->option_data);
320             break;
321         case RULE_OPTION_TYPE_BASE64_DATA:
322             break;
323         case RULE_OPTION_TYPE_PKT_DATA:
324             break;
325         case RULE_OPTION_TYPE_ICMP_CODE:
326             ret = IcmpCodeCheckCompare(key1->option_data, key2->option_data);
327             break;
328         case RULE_OPTION_TYPE_ICMP_ID:
329             ret = IcmpIdCheckCompare(key1->option_data, key2->option_data);
330             break;
331         case RULE_OPTION_TYPE_ICMP_SEQ:
332             ret = IcmpSeqCheckCompare(key1->option_data, key2->option_data);
333             break;
334         case RULE_OPTION_TYPE_ICMP_TYPE:
335             ret = IcmpTypeCheckCompare(key1->option_data, key2->option_data);
336             break;
337         case RULE_OPTION_TYPE_IP_FRAGBITS:
338             ret = IpFragBitsCheckCompare(key1->option_data, key2->option_data);
339             break;
340         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
341             ret = IpFragOffsetCheckCompare(key1->option_data, key2->option_data);
342             break;
343         case RULE_OPTION_TYPE_IP_ID:
344             ret = IpIdCheckCompare(key1->option_data, key2->option_data);
345             break;
346         case RULE_OPTION_TYPE_IP_OPTION:
347             ret = IpOptionCheckCompare(key1->option_data, key2->option_data);
348             break;
349         case RULE_OPTION_TYPE_IP_PROTO:
350             ret = IpProtoCheckCompare(key1->option_data, key2->option_data);
351             break;
352         case RULE_OPTION_TYPE_IP_SAME:
353             ret = IpSameCheckCompare(key1->option_data, key2->option_data);
354             break;
355         case RULE_OPTION_TYPE_IP_TOS:
356             ret = IpTosCheckCompare(key1->option_data, key2->option_data);
357             break;
358         case RULE_OPTION_TYPE_IS_DATA_AT:
359             ret = IsDataAtCompare(key1->option_data, key2->option_data);
360             break;
361         case RULE_OPTION_TYPE_CONTENT:
362         case RULE_OPTION_TYPE_CONTENT_URI:
363             ret = PatternMatchCompare(key1->option_data, key2->option_data);
364             break;
365         case RULE_OPTION_TYPE_PCRE:
366             ret = PcreCompare(key1->option_data, key2->option_data);
367             break;
368 #ifdef ENABLE_REACT
369         case RULE_OPTION_TYPE_REACT:
370             ret = ReactCompare(key1->option_data, key2->option_data);
371             break;
372 #endif
373 #ifdef ENABLE_RESPOND
374         case RULE_OPTION_TYPE_RESPOND:
375             ret = RespondCompare(key1->option_data, key2->option_data);
376             break;
377 #endif
378         case RULE_OPTION_TYPE_RPC_CHECK:
379             ret = RpcCheckCompare(key1->option_data, key2->option_data);
380             break;
381         case RULE_OPTION_TYPE_SESSION:
382             ret = SessionCompare(key1->option_data, key2->option_data);
383             break;
384         case RULE_OPTION_TYPE_TCP_ACK:
385             ret = TcpAckCheckCompare(key1->option_data, key2->option_data);
386             break;
387         case RULE_OPTION_TYPE_TCP_FLAG:
388             ret = TcpFlagCheckCompare(key1->option_data, key2->option_data);
389             break;
390         case RULE_OPTION_TYPE_TCP_SEQ:
391             ret = TcpSeqCheckCompare(key1->option_data, key2->option_data);
392             break;
393         case RULE_OPTION_TYPE_TCP_WIN:
394             ret = TcpWinCheckCompare(key1->option_data, key2->option_data);
395             break;
396         case RULE_OPTION_TYPE_TTL:
397             ret = TtlCheckCompare(key1->option_data, key2->option_data);
398             break;
399         case RULE_OPTION_TYPE_URILEN:
400             ret = UriLenCheckCompare(key1->option_data, key2->option_data);
401             break;
402         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
403             ret = HdrOptCheckCompare(key1->option_data, key2->option_data);
404             break;
405         case RULE_OPTION_TYPE_FILE_TYPE:
406             ret = FileTypeCompare(key1->option_data, key2->option_data);
407             break;
408         case RULE_OPTION_TYPE_PREPROCESSOR:
409             ret = PreprocessorRuleOptionCompare(key1->option_data, key2->option_data);
410             break;
411         case RULE_OPTION_TYPE_DYNAMIC:
412             ret = DynamicRuleCompare(key1->option_data, key2->option_data);
413             break;
414 #if defined(FEAT_OPEN_APPID)
415         case RULE_OPTION_TYPE_APPID:
416             ret = optionAppIdCompare(key1->option_data, key2->option_data);
417             break;
418 #endif /* defined(FEAT_OPEN_APPID) */
419     }
420 
421     return ret;
422 }
423 
detection_hash_free_func(void * option_key,void * data)424 int detection_hash_free_func(void *option_key, void *data)
425 {
426     detection_option_key_t *key = (detection_option_key_t*)option_key;
427 
428     switch (key->option_type)
429     {
430         /* Call free function specific to the key type */
431         case RULE_OPTION_TYPE_ASN1:
432             free(key->option_data);
433             break;
434         case RULE_OPTION_TYPE_BYTE_TEST:
435             free(key->option_data);
436             break;
437         case RULE_OPTION_TYPE_BYTE_JUMP:
438             free(key->option_data);
439             break;
440         case RULE_OPTION_TYPE_BYTE_EXTRACT:
441             ByteExtractFree(key->option_data);
442             break;
443         case RULE_OPTION_TYPE_BYTE_MATH:
444             ByteMathFree(key->option_data);
445             break;
446         case RULE_OPTION_TYPE_FLOW:
447             free(key->option_data);
448             break;
449         case RULE_OPTION_TYPE_CVS:
450             free(key->option_data);
451             break;
452         case RULE_OPTION_TYPE_DSIZE:
453             free(key->option_data);
454             break;
455         case RULE_OPTION_TYPE_FLOWBIT:
456             FlowBitsFree(key->option_data);
457             break;
458         case RULE_OPTION_TYPE_FTPBOUNCE:
459             /* Data is NULL, nothing to free */
460             break;
461         case RULE_OPTION_TYPE_FILE_DATA:
462             free(key->option_data);
463             break;
464         case RULE_OPTION_TYPE_BASE64_DECODE:
465             free(key->option_data);
466             break;
467         case RULE_OPTION_TYPE_BASE64_DATA:
468             break;
469         case RULE_OPTION_TYPE_PKT_DATA:
470             break;
471         case RULE_OPTION_TYPE_ICMP_CODE:
472             free(key->option_data);
473             break;
474         case RULE_OPTION_TYPE_ICMP_ID:
475             free(key->option_data);
476             break;
477         case RULE_OPTION_TYPE_ICMP_SEQ:
478             free(key->option_data);
479             break;
480         case RULE_OPTION_TYPE_ICMP_TYPE:
481             free(key->option_data);
482             break;
483         case RULE_OPTION_TYPE_IP_FRAGBITS:
484             free(key->option_data);
485             break;
486         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
487             free(key->option_data);
488             break;
489         case RULE_OPTION_TYPE_IP_ID:
490             free(key->option_data);
491             break;
492         case RULE_OPTION_TYPE_IP_OPTION:
493             free(key->option_data);
494             break;
495         case RULE_OPTION_TYPE_IP_PROTO:
496             free(key->option_data);
497             break;
498         case RULE_OPTION_TYPE_IP_SAME:
499             /* Data is NULL, nothing to free */
500             break;
501         case RULE_OPTION_TYPE_IP_TOS:
502             free(key->option_data);
503             break;
504         case RULE_OPTION_TYPE_IS_DATA_AT:
505             free(key->option_data);
506             break;
507         case RULE_OPTION_TYPE_CONTENT:
508         case RULE_OPTION_TYPE_CONTENT_URI:
509             PatternMatchFree(key->option_data);
510             break;
511         case RULE_OPTION_TYPE_PCRE:
512             PcreFree(key->option_data);
513             break;
514 #ifdef ENABLE_REACT
515         case RULE_OPTION_TYPE_REACT:
516             ReactFree(key->option_data);
517             break;
518 #endif
519 #ifdef ENABLE_RESPOND
520         case RULE_OPTION_TYPE_RESPOND:
521             free(key->option_data);
522             break;
523 #endif
524         case RULE_OPTION_TYPE_RPC_CHECK:
525             free(key->option_data);
526             break;
527         case RULE_OPTION_TYPE_SESSION:
528             free(key->option_data);
529             break;
530         case RULE_OPTION_TYPE_TCP_ACK:
531             free(key->option_data);
532             break;
533         case RULE_OPTION_TYPE_TCP_FLAG:
534             free(key->option_data);
535             break;
536         case RULE_OPTION_TYPE_TCP_SEQ:
537             free(key->option_data);
538             break;
539         case RULE_OPTION_TYPE_TCP_WIN:
540             free(key->option_data);
541             break;
542         case RULE_OPTION_TYPE_TTL:
543             free(key->option_data);
544             break;
545         case RULE_OPTION_TYPE_URILEN:
546             free(key->option_data);
547             break;
548         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
549             break;
550         case RULE_OPTION_TYPE_FILE_TYPE:
551             FileTypeFree(key->option_data);
552             break;
553         case RULE_OPTION_TYPE_PREPROCESSOR:
554             PreprocessorRuleOptionsFreeFunc(key->option_data);
555             break;
556         case RULE_OPTION_TYPE_DYNAMIC:
557             fpDynamicDataFree(key->option_data);
558             break;
559         case RULE_OPTION_TYPE_LEAF_NODE:
560             break;
561 #if defined(FEAT_OPEN_APPID)
562         case RULE_OPTION_TYPE_APPID:
563             optionAppIdFree(key->option_data);
564             break;
565 #endif /* defined(FEAT_OPEN_APPID) */
566     }
567     return 0;
568 }
569 
DetectionHashTableNew(void)570 SFXHASH * DetectionHashTableNew(void)
571 {
572     SFXHASH *doht = sfxhash_new(HASH_RULE_OPTIONS,
573                                 sizeof(detection_option_key_t),
574                                 0,      /* Data size == 0, just store the ptr */
575                                 0,      /* Memcap */
576                                 0,      /* Auto node recovery */
577                                 NULL,   /* Auto free function */
578                                 detection_hash_free_func,   /* User free function */
579                                 1);     /* Recycle nodes */
580 
581 
582     if (doht == NULL)
583         FatalError("Failed to create rule detection option hash table");
584 
585     sfxhash_set_keyops(doht, detection_option_hash_func,
586                        detection_option_key_compare_func);
587 
588     return doht;
589 }
590 
DetectionHashTableFree(SFXHASH * doht)591 void DetectionHashTableFree(SFXHASH *doht)
592 {
593     if (doht != NULL)
594         sfxhash_delete(doht);
595 }
596 
add_detection_option(struct _SnortConfig * sc,option_type_t type,void * option_data,void ** existing_data)597 int add_detection_option(struct _SnortConfig *sc, option_type_t type, void *option_data, void **existing_data)
598 {
599     detection_option_key_t key;
600 
601     if (sc == NULL)
602     {
603         FatalError("%s(%d) Snort config is NULL.\n",
604                    __FILE__, __LINE__);
605     }
606 
607     if (sc->detection_option_hash_table == NULL)
608         sc->detection_option_hash_table = DetectionHashTableNew();
609 
610     if (!option_data)
611     {
612         /* No option data, no conflict to resolve. */
613         return DETECTION_OPTION_EQUAL;
614     }
615 
616     key.option_type = type;
617     key.option_data = option_data;
618 
619     *existing_data = sfxhash_find(sc->detection_option_hash_table, &key);
620     if (*existing_data)
621     {
622         return DETECTION_OPTION_EQUAL;
623     }
624 
625     sfxhash_add(sc->detection_option_hash_table, &key, option_data);
626     return DETECTION_OPTION_NOT_EQUAL;
627 }
628 
detection_option_tree_hash(detection_option_tree_node_t * node)629 uint32_t detection_option_tree_hash(detection_option_tree_node_t *node)
630 {
631     uint32_t a,b,c;
632     int i;
633 
634     if (!node)
635         return 0;
636 
637     a = b = c = 0;
638 
639     for (i=0;i<node->num_children;i++)
640     {
641 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
642         {
643             /* Cleanup warning because of cast from 64bit ptr to 32bit int
644              * warning on 64bit OSs */
645             uint64_t ptr; /* Addresses are 64bits */
646             ptr = (uint64_t)node->children[i]->option_data;
647             a += (ptr >> 32);
648             b += (ptr & 0xFFFFFFFF);
649         }
650 #else
651         a += (uint32_t)node->children[i]->option_data;
652         b += 0;
653 #endif
654         c += detection_option_tree_hash(node->children[i]);
655         mix(a,b,c);
656         a += node->children[i]->num_children;
657         mix(a,b,c);
658 #if 0
659         a += (uint32_t)node->children[i]->option_data;
660         /* Recurse & hash up this guy's children */
661         b += detection_option_tree_hash(node->children[i]);
662         c += node->children[i]->num_children;
663         mix(a,b,c);
664 #endif
665     }
666 
667     final(a,b,c);
668 
669     return c;
670 }
671 
detection_option_tree_hash_func(SFHASHFCN * p,unsigned char * k,int n)672 uint32_t detection_option_tree_hash_func(SFHASHFCN *p, unsigned char *k, int n)
673 {
674     detection_option_key_t *key = (detection_option_key_t *)k;
675     detection_option_tree_node_t *node;
676 
677     if (!key || !key->option_data)
678         return 0;
679 
680     node = (detection_option_tree_node_t*)key->option_data;
681 
682     return detection_option_tree_hash(node);
683 }
684 
detection_option_tree_compare(detection_option_tree_node_t * r,detection_option_tree_node_t * l)685 int detection_option_tree_compare(detection_option_tree_node_t *r, detection_option_tree_node_t *l)
686 {
687     int ret = DETECTION_OPTION_NOT_EQUAL;
688     int i;
689 
690     if ((r == NULL) && (l == NULL))
691         return DETECTION_OPTION_EQUAL;
692 
693     if ((!r && l) || (r && !l))
694         return DETECTION_OPTION_NOT_EQUAL;
695 
696     if (r->option_data != l->option_data)
697         return DETECTION_OPTION_NOT_EQUAL;
698 
699     if (r->num_children != l->num_children)
700         return DETECTION_OPTION_NOT_EQUAL;
701 
702     for (i=0;i<r->num_children;i++)
703     {
704         /* Recurse & check the children for equality */
705         ret = detection_option_tree_compare(r->children[i], l->children[i]);
706         if (ret != DETECTION_OPTION_EQUAL)
707             return ret;
708     }
709 
710     return DETECTION_OPTION_EQUAL;
711 }
712 
detection_option_tree_compare_func(const void * k1,const void * k2,size_t n)713 int detection_option_tree_compare_func(const void *k1, const void *k2, size_t n)
714 {
715     detection_option_key_t *key_r = (detection_option_key_t *)k1;
716     detection_option_key_t *key_l = (detection_option_key_t *)k2;
717     detection_option_tree_node_t *r;
718     detection_option_tree_node_t *l;
719 
720     if (!key_r || !key_l)
721         return DETECTION_OPTION_NOT_EQUAL;
722 
723     r = (detection_option_tree_node_t *)key_r->option_data;
724     l = (detection_option_tree_node_t *)key_l->option_data;
725 
726     return detection_option_tree_compare(r, l);
727 }
728 
detection_option_tree_free_func(void * option_key,void * data)729 int detection_option_tree_free_func(void *option_key, void *data)
730 {
731     detection_option_tree_node_t *node = (detection_option_tree_node_t *)data;
732     /* In fpcreate.c */
733     free_detection_option_tree(node);
734     return 0;
735 }
736 
DetectionTreeHashTableFree(SFXHASH * dtht)737 void DetectionTreeHashTableFree(SFXHASH *dtht)
738 {
739     if (dtht != NULL)
740         sfxhash_delete(dtht);
741 }
742 
DetectionTreeHashTableNew(void)743 SFXHASH * DetectionTreeHashTableNew(void)
744 {
745     SFXHASH *dtht = sfxhash_new(HASH_RULE_TREE,
746                                 sizeof(detection_option_key_t),
747                                 0,      /* Data size == 0, just store the ptr */
748                                 0,      /* Memcap */
749                                 0,      /* Auto node recovery */
750                                 NULL,   /* Auto free function */
751                                 detection_option_tree_free_func,   /* User free function */
752                                 1);     /* Recycle nodes */
753 
754 
755     if (dtht == NULL)
756         FatalError("Failed to create rule detection option hash table");
757 
758     sfxhash_set_keyops(dtht, detection_option_tree_hash_func,
759                        detection_option_tree_compare_func);
760 
761     return dtht;
762 }
763 
764 char *option_type_str[] =
765 {
766     "RULE_OPTION_TYPE_LEAF_NODE",
767     "RULE_OPTION_TYPE_ASN1",
768     "RULE_OPTION_TYPE_BYTE_TEST",
769     "RULE_OPTION_TYPE_BYTE_JUMP",
770     "RULE_OPTION_TYPE_BYTE_EXTRACT",
771     "RULE_OPTION_TYPE_FLOW",
772     "RULE_OPTION_TYPE_CVS",
773     "RULE_OPTION_TYPE_DSIZE",
774     "RULE_OPTION_TYPE_FLOWBIT",
775     "RULE_OPTION_TYPE_FTPBOUNCE",
776     "RULE_OPTION_TYPE_ICMP_CODE",
777     "RULE_OPTION_TYPE_ICMP_ID",
778     "RULE_OPTION_TYPE_ICMP_SEQ",
779     "RULE_OPTION_TYPE_ICMP_TYPE",
780     "RULE_OPTION_TYPE_IP_FRAGBITS",
781     "RULE_OPTION_TYPE_IP_FRAG_OFFSET",
782     "RULE_OPTION_TYPE_IP_ID",
783     "RULE_OPTION_TYPE_IP_OPTION",
784     "RULE_OPTION_TYPE_IP_PROTO",
785     "RULE_OPTION_TYPE_IP_SAME",
786     "RULE_OPTION_TYPE_IP_TOS",
787     "RULE_OPTION_TYPE_IS_DATA_AT",
788     "RULE_OPTION_TYPE_FILE_DATA",
789     "RULE_OPTION_TYPE_FILE_TYPE",
790     "RULE_OPTION_TYPE_BASE64_DECODE",
791     "RULE_OPTION_TYPE_BASE64_DATA",
792     "RULE_OPTION_TYPE_PKT_DATA",
793     "RULE_OPTION_TYPE_CONTENT",
794     "RULE_OPTION_TYPE_CONTENT_URI",
795     "RULE_OPTION_TYPE_PCRE",
796 #ifdef ENABLE_REACT
797     "RULE_OPTION_TYPE_REACT",
798 #endif
799 #ifdef ENABLE_RESPOND
800     "RULE_OPTION_TYPE_RESPOND",
801 #endif
802     "RULE_OPTION_TYPE_RPC_CHECK",
803     "RULE_OPTION_TYPE_SESSION",
804     "RULE_OPTION_TYPE_TCP_ACK",
805     "RULE_OPTION_TYPE_TCP_FLAG",
806     "RULE_OPTION_TYPE_TCP_SEQ",
807     "RULE_OPTION_TYPE_TCP_WIN",
808     "RULE_OPTION_TYPE_TTL",
809     "RULE_OPTION_TYPE_URILEN",
810     "RULE_OPTION_TYPE_HDR_OPT_CHECK",
811     "RULE_OPTION_TYPE_PREPROCESSOR",
812     "RULE_OPTION_TYPE_DYNAMIC"
813 #if defined(FEAT_OPEN_APPID)
814     ,"RULE_OPTION_TYPE_APPID"
815 #endif /* defined(FEAT_OPEN_APPID) */
816     ,"RULE_OPTION_TYPE_BYTE_MATH"
817 };
818 
819 #ifdef DEBUG_OPTION_TREE
print_option_tree(detection_option_tree_node_t * node,int level)820 void print_option_tree(detection_option_tree_node_t *node, int level)
821 {
822     int i;
823     unsigned int indent = 12 - (11 - level) + strlen(option_type_str[node->option_type]);
824     unsigned int offset = 0;
825     if (level >= 10)
826         offset++;
827 
828     DEBUG_WRAP(
829         DebugMessage(DEBUG_DETECT, "%d%*s%*d 0x%x\n",
830            level, indent - offset, option_type_str[node->option_type],
831            54 - indent, node->num_children,
832            node->option_data);
833         for (i=0;i<node->num_children;i++)
834             print_option_tree(node->children[i], level+1);
835     );
836 }
837 #endif
838 
add_detection_option_tree(SnortConfig * sc,detection_option_tree_node_t * option_tree,void ** existing_data)839 int add_detection_option_tree(SnortConfig *sc, detection_option_tree_node_t *option_tree, void **existing_data)
840 {
841     detection_option_key_t key;
842 
843     if (sc == NULL)
844     {
845         FatalError("%s(%d) Snort config for parsing is NULL.\n",
846                    __FILE__, __LINE__);
847     }
848 
849     if (sc->detection_option_tree_hash_table == NULL)
850         sc->detection_option_tree_hash_table = DetectionTreeHashTableNew();
851 
852     if (!option_tree)
853     {
854         /* No option data, no conflict to resolve. */
855         return DETECTION_OPTION_EQUAL;
856     }
857 
858     key.option_data = (void *)option_tree;
859     key.option_type = RULE_OPTION_TYPE_LEAF_NODE;
860 
861     *existing_data = sfxhash_find(sc->detection_option_tree_hash_table, &key);
862     if (*existing_data)
863     {
864         return DETECTION_OPTION_EQUAL;
865     }
866 
867     sfxhash_add(sc->detection_option_tree_hash_table, &key, option_tree);
868     return DETECTION_OPTION_NOT_EQUAL;
869 }
870 
871 
872 uint64_t rule_eval_pkt_count = 0;
873 
874 /* Include "detection_leaf_node.c"
875  *
876  * Service matches, toggles 'check_ports' and then evaluation
877  * of the leaf nodes (ie. the rule header stuffs).
878  *
879  * This defines the routine "detection_leaf_node_eval($,$)" which
880  * is called from the switch case RULE_OPTION_TYPE_LEAF_NODE below.
881  */
882 #include "detection_leaf_node.c"
883 
detection_option_node_evaluate(detection_option_tree_node_t * node,detection_option_eval_data_t * eval_data)884 int detection_option_node_evaluate(detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data)
885 {
886     int i, result = 0, prior_result = 0;
887     int rval = DETECTION_OPTION_NO_MATCH;
888     const uint8_t *orig_doe_ptr;
889     char tmp_noalert_flag = 0;
890     PatternMatchData dup_content_option_data;
891     PcreData dup_pcre_option_data;
892     const uint8_t *dp = NULL;
893     char continue_loop = 1;
894     char flowbits_setoperation = 0;
895     int loop_count = 0;
896     uint32_t tmp_byte_extract_vars[NUM_BYTE_EXTRACT_VARS];
897     uint16_t save_dflags = 0;
898     uint64_t cur_eval_pkt_count = (rule_eval_pkt_count + (GetRebuiltPktCount()));
899     NODE_PROFILE_VARS;
900 
901     if (!node || !eval_data || !eval_data->p || !eval_data->pomd)
902         return 0;
903 
904     save_dflags = Get_DetectFlags();
905 
906     /* see if evaluated it before ... */
907     if (node->last_check.is_relative == 0)
908     {
909         /* Only matters if not relative... */
910         if ((node->last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
911             (node->last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
912             (node->last_check.packet_number == cur_eval_pkt_count) &&
913             (node->last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)) &&
914             (!(eval_data->p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT)))
915         {
916             /* eval'd this rule option before on this packet,
917              * use the cached result. */
918             if ((node->last_check.flowbit_failed == 0) &&
919                 !(eval_data->p->packet_flags & PKT_IP_RULE_2ND) &&
920                 !(eval_data->p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP )))
921             {
922                 return node->last_check.result;
923             }
924         }
925     }
926 
927     NODE_PROFILE_START(node);
928 
929     node->last_check.ts.tv_sec = eval_data->p->pkth->ts.tv_sec;
930     node->last_check.ts.tv_usec = eval_data->p->pkth->ts.tv_usec;
931     node->last_check.packet_number = cur_eval_pkt_count;
932     node->last_check.rebuild_flag = (eval_data->p->packet_flags & PKT_REBUILT_STREAM);
933     node->last_check.flowbit_failed = 0;
934 
935     /* Save some stuff off for repeated pattern tests */
936     orig_doe_ptr = doe_ptr;
937 
938     if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
939             (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
940     {
941         PatternMatchDuplicatePmd(node->option_data, &dup_content_option_data);
942 
943         if (dup_content_option_data.buffer_func == CHECK_URI_PATTERN_MATCH)
944         {
945             const HttpBuffer* hb = GetHttpBuffer(dup_content_option_data.http_buffer);
946             dp = hb ? hb->buf : NULL;  // FIXTHIS set length too
947         }
948         else if (dup_content_option_data.rawbytes == 0)
949         {
950             /* If AltDetect is set by calling the rule options which set it,
951              * we should use the Alt Detect before checking for any other buffers.
952              * Alt Detect will take precedence over the Alt Decode and/or packet data.
953              */
954             if(Is_DetectFlag(FLAG_ALT_DETECT))
955                 dp = DetectBuffer.data;
956             else if(Is_DetectFlag(FLAG_ALT_DECODE))
957                 dp = (uint8_t *)DecodeBuffer.data;
958             else
959                 dp = eval_data->p->data;
960         }
961         else
962         {
963             dp = eval_data->p->data;
964         }
965     }
966     else if (node->option_type == RULE_OPTION_TYPE_PCRE)
967     {
968         unsigned hb_type;
969         PcreDuplicatePcreData(node->option_data, &dup_pcre_option_data);
970         hb_type = dup_pcre_option_data.options & SNORT_PCRE_HTTP_BUFS;
971 
972         if ( hb_type )
973         {
974             const HttpBuffer* hb = GetHttpBuffer(hb_type);
975             dp = hb ? hb->buf : NULL;  // FIXTHIS set length too
976         }
977         else if (!(dup_pcre_option_data.options & SNORT_PCRE_RAWBYTES))
978         {
979             /* If AltDetect is set by calling the rule options which set it,
980              * we should use the Alt Detect before checking for any other buffers.
981              * Alt Detect will take precedence over the Alt Decode and/or packet data.
982              */
983             if(Is_DetectFlag(FLAG_ALT_DETECT))
984                 dp = DetectBuffer.data;
985             else if(Is_DetectFlag(FLAG_ALT_DECODE))
986                 dp = (uint8_t *)DecodeBuffer.data;
987             else
988                 dp = eval_data->p->data;
989         }
990         else
991         {
992             dp = eval_data->p->data;
993         }
994     }
995 
996     /* No, haven't evaluated this one before... Check it. */
997     do
998     {
999         switch (node->option_type)
1000         {
1001             case RULE_OPTION_TYPE_LEAF_NODE:
1002                 /* Add the match for this otn to the queue. */
1003                 {
1004                     int pattern_size    = 0;
1005                     int eval_rtn_result = 1;
1006                     int check_ports     = 1;
1007                     OptTreeNode *otn = (OptTreeNode*) node->option_data;
1008                     PatternMatchData *pmd = (PatternMatchData*) eval_data->pmd;
1009 
1010                     if (pmd)
1011                         pattern_size = pmd->pattern_size;
1012 
1013                     // See "detection_leaf_node.c" (detection_leaf_node_eval).
1014 #ifdef TARGET_BASED
1015                     switch (detection_leaf_node_eval (node, eval_data))
1016                     {
1017                         case Leaf_Abort:
1018                             eval_rtn_result = 0;
1019                             break;
1020 
1021                         case Leaf_SkipPorts:
1022                             check_ports = 0;
1023                             // fall through
1024 
1025                         case Leaf_CheckPorts:
1026                             NODE_PROFILE_TMPEND(node);
1027                             eval_rtn_result = fpEvalRTN (getRuntimeRtnFromOtn (otn), eval_data->p, check_ports);
1028                             NODE_PROFILE_TMPSTART(node);
1029                             break;
1030                     }
1031 #endif
1032 
1033                     if (eval_rtn_result)
1034                     {
1035 			    if ((!otn->detection_filter) ||
1036                                  !detection_filter_test(
1037                                  otn->detection_filter,
1038                                  GET_SRC_IP(eval_data->p), GET_DST_IP(eval_data->p),
1039                                  eval_data->p->pkth->ts.tv_sec, eval_data))
1040                         {
1041 #ifdef PERF_PROFILING
1042                             if (PROFILING_RULES)
1043                                 otn->matches++;
1044 #endif
1045                             if (!eval_data->flowbit_noalert)
1046                             {
1047                                 fpAddMatch(eval_data->pomd, pattern_size, otn);
1048                             }
1049                             result = rval = DETECTION_OPTION_MATCH;
1050                         }
1051                     }
1052                 }
1053                 break;
1054 
1055             case RULE_OPTION_TYPE_CONTENT:
1056                 if (node->evaluate)
1057                 {
1058                     /* This will be set in the fast pattern matcher if we found
1059                      * a content and the rule option specifies not that
1060                      * content. Essentially we've already evaluated this rule
1061                      * option via the content option processing since only not
1062                      * contents that are not relative in any way will have this
1063                      * flag set */
1064                     if (dup_content_option_data.exception_flag)
1065                     {
1066                         if ((dup_content_option_data.last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
1067                             (dup_content_option_data.last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
1068                             (dup_content_option_data.last_check.packet_number == cur_eval_pkt_count) &&
1069                             (dup_content_option_data.last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)))
1070                         {
1071                             rval = DETECTION_OPTION_NO_MATCH;
1072                             break;
1073                         }
1074                     }
1075 
1076                     rval = node->evaluate(&dup_content_option_data, eval_data->p);
1077                 }
1078                 break;
1079             case RULE_OPTION_TYPE_CONTENT_URI:
1080                 if (node->evaluate)
1081                 {
1082                     rval = node->evaluate(&dup_content_option_data, eval_data->p);
1083                 }
1084                 break;
1085             case RULE_OPTION_TYPE_PCRE:
1086                 if (node->evaluate)
1087                 {
1088                     rval = node->evaluate(&dup_pcre_option_data, eval_data->p);
1089                 }
1090                 break;
1091             case RULE_OPTION_TYPE_PKT_DATA:
1092             case RULE_OPTION_TYPE_FILE_DATA:
1093             case RULE_OPTION_TYPE_BASE64_DATA:
1094                 if (node->evaluate)
1095                 {
1096                     save_dflags = Get_DetectFlags();
1097                     rval = node->evaluate(node->option_data, eval_data->p);
1098                 }
1099                 break;
1100             case RULE_OPTION_TYPE_FLOWBIT:
1101                 if (node->evaluate)
1102                 {
1103                     flowbits_setoperation = FlowBits_SetOperation(node->option_data);
1104                     if (!flowbits_setoperation)
1105                     {
1106                         rval = node->evaluate(node->option_data, eval_data->p);
1107                     }
1108                     else
1109                     {
1110                         /* set to match so we don't bail early.  */
1111                         rval = DETECTION_OPTION_MATCH;
1112                     }
1113                 }
1114                 break;
1115             case RULE_OPTION_TYPE_ASN1:
1116             case RULE_OPTION_TYPE_BYTE_TEST:
1117             case RULE_OPTION_TYPE_BYTE_JUMP:
1118             case RULE_OPTION_TYPE_BYTE_EXTRACT:
1119             case RULE_OPTION_TYPE_BYTE_MATH:
1120             case RULE_OPTION_TYPE_FLOW:
1121             case RULE_OPTION_TYPE_CVS:
1122             case RULE_OPTION_TYPE_DSIZE:
1123             case RULE_OPTION_TYPE_FTPBOUNCE:
1124             case RULE_OPTION_TYPE_BASE64_DECODE:
1125             case RULE_OPTION_TYPE_ICMP_CODE:
1126             case RULE_OPTION_TYPE_ICMP_ID:
1127             case RULE_OPTION_TYPE_ICMP_SEQ:
1128             case RULE_OPTION_TYPE_ICMP_TYPE:
1129             case RULE_OPTION_TYPE_IP_FRAGBITS:
1130             case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
1131             case RULE_OPTION_TYPE_IP_ID:
1132             case RULE_OPTION_TYPE_IP_OPTION:
1133             case RULE_OPTION_TYPE_IP_PROTO:
1134             case RULE_OPTION_TYPE_IP_SAME:
1135             case RULE_OPTION_TYPE_IP_TOS:
1136             case RULE_OPTION_TYPE_IS_DATA_AT:
1137 #ifdef ENABLE_REACT
1138             case RULE_OPTION_TYPE_REACT:
1139 #endif
1140 #ifdef ENABLE_RESPOND
1141             case RULE_OPTION_TYPE_RESPOND:
1142 #endif
1143             case RULE_OPTION_TYPE_RPC_CHECK:
1144             case RULE_OPTION_TYPE_SESSION:
1145             case RULE_OPTION_TYPE_TCP_ACK:
1146             case RULE_OPTION_TYPE_TCP_FLAG:
1147             case RULE_OPTION_TYPE_TCP_SEQ:
1148             case RULE_OPTION_TYPE_TCP_WIN:
1149             case RULE_OPTION_TYPE_TTL:
1150             case RULE_OPTION_TYPE_URILEN:
1151             case RULE_OPTION_TYPE_HDR_OPT_CHECK:
1152             case RULE_OPTION_TYPE_FILE_TYPE:
1153             case RULE_OPTION_TYPE_PREPROCESSOR:
1154                 if (node->evaluate)
1155                     rval = node->evaluate(node->option_data, eval_data->p);
1156                 break;
1157             case RULE_OPTION_TYPE_DYNAMIC:
1158                 if (node->evaluate)
1159                     rval = node->evaluate(node->option_data, eval_data->p);
1160                 break;
1161 #if defined(FEAT_OPEN_APPID)
1162             case RULE_OPTION_TYPE_APPID:
1163                 if (node->evaluate)
1164                     rval = node->evaluate(node->option_data, eval_data->p);
1165                 break;
1166 #endif /* defined(FEAT_OPEN_APPID) */
1167         }
1168 
1169         if (rval == DETECTION_OPTION_NO_MATCH)
1170         {
1171             node->last_check.result = result;
1172             NODE_PROFILE_END_NOMATCH(node);
1173             return result;
1174         }
1175         else if (rval == DETECTION_OPTION_FAILED_BIT)
1176         {
1177             eval_data->flowbit_failed = 1;
1178             /* clear the timestamp so failed flowbit gets eval'd again */
1179             node->last_check.flowbit_failed = 1;
1180             node->last_check.result = result;
1181             NODE_PROFILE_END_NOMATCH(node);
1182             return 0;
1183         }
1184         else if (rval == DETECTION_OPTION_NO_ALERT)
1185         {
1186             /* Cache the current flowbit_noalert flag, and set it
1187              * so nodes below this don't alert. */
1188             tmp_noalert_flag = eval_data->flowbit_noalert;
1189             eval_data->flowbit_noalert = 1;
1190         }
1191 
1192         /* Back up byte_extract vars so they don't get overwritten between rules */
1193         for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
1194         {
1195             GetByteExtractValue(&(tmp_byte_extract_vars[i]), (int8_t)i);
1196         }
1197 
1198 #ifdef PPM_MGR
1199         if( PPM_PKTS_ENABLED() )
1200         {
1201             PPM_GET_TIME();
1202             PPM_PACKET_TEST();
1203             if( PPM_PACKET_ABORT_FLAG() )
1204             {
1205                 /* bail if we exceeded time */
1206                 if (result == DETECTION_OPTION_NO_MATCH)
1207                 {
1208                     NODE_PROFILE_END_NOMATCH(node);
1209                 }
1210                 else
1211                 {
1212                     NODE_PROFILE_END_MATCH(node);
1213                 }
1214                 node->last_check.result = result;
1215                 Reset_DetectFlags(save_dflags);
1216                 return result;
1217             }
1218         }
1219 #endif
1220         /* Don't include children's time in this node */
1221         NODE_PROFILE_TMPEND(node);
1222 
1223         /* Passed, check the children. */
1224         if (node->num_children)
1225         {
1226             const uint8_t *tmp_doe_ptr = doe_ptr;
1227             const uint8_t tmp_doe_flags = doe_buf_flags;
1228 
1229             for (i=0;i<node->num_children; i++)
1230             {
1231                 int j = 0;
1232                 detection_option_tree_node_t *child_node = node->children[i];
1233 
1234                 /* reset the DOE ptr for each child from here */
1235                 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
1236 
1237                 for (j = 0; j < NUM_BYTE_EXTRACT_VARS; j++)
1238                 {
1239                     SetByteExtractValue(tmp_byte_extract_vars[j], (int8_t)j);
1240                 }
1241 
1242                 if (loop_count > 0)
1243                 {
1244                     if (child_node->result == DETECTION_OPTION_NO_MATCH)
1245                     {
1246                         if (((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
1247                                     || (child_node->option_type == RULE_OPTION_TYPE_PCRE))
1248                                 && !child_node->last_check.is_relative)
1249                         {
1250                             /* If it's a non-relative content or pcre, no reason
1251                              * to check again.  Only increment result once.
1252                              * Should hit this condition on first loop iteration. */
1253                             if (loop_count == 1)
1254                                 result++;
1255                             continue;
1256                         }
1257                         else if ((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
1258                                 && child_node->last_check.is_relative)
1259                         {
1260                             PatternMatchData *pmd = (PatternMatchData *)child_node->option_data;
1261 
1262                             /* Check for an unbounded relative search.  If this
1263                              * failed before, it's going to fail again so don't
1264                              * go down this path again
1265                              * Check for protected pattern because in this case
1266                              * we had checked for 'n'bytes only where 'n' is the
1267                              * length of protected pattern.
1268                              * */
1269                             if (pmd->within == PMD_WITHIN_UNDEFINED && !pmd->protected_pattern)
1270                             {
1271                                 /* Only increment result once. Should hit this
1272                                  * condition on first loop iteration. */
1273                                 if (loop_count == 1)
1274                                     result++;
1275                                 continue;
1276                             }
1277                         }
1278                     }
1279                     else if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1280                     {
1281                         /* Leaf node matched, don't eval again */
1282                         continue;
1283                     }
1284                     else if (child_node->result == child_node->num_children)
1285                     {
1286                         /* This branch of the tree matched or has options that
1287                          * don't need to be evaluated again, so don't need to
1288                          * evaluate this option again */
1289                         continue;
1290                     }
1291                 }
1292 
1293                 child_node->result = detection_option_node_evaluate(node->children[i], eval_data);
1294                 if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1295                 {
1296                     /* Leaf node won't have any children but will return success
1297                      * or failure; regardless we must count them here */
1298                     result += 1;
1299                 }
1300                 else if (child_node->result == child_node->num_children)
1301                 {
1302                     /* Indicate that the child's tree branches are done */
1303                     result++;
1304                 }
1305 #ifdef PPM_MGR
1306                 if( PPM_PKTS_ENABLED() )
1307                 {
1308                     PPM_GET_TIME();
1309                     PPM_PACKET_TEST();
1310                     if( PPM_PACKET_ABORT_FLAG() )
1311                     {
1312                         /* bail if we exceeded time */
1313                         node->last_check.result = result;
1314                         Reset_DetectFlags(save_dflags);
1315                         return result;
1316                     }
1317                 }
1318 #endif
1319             }
1320 
1321             /* If all children branches matched, we don't need to reeval any of
1322              * the children so don't need to reeval this content/pcre rule
1323              * option at a new offset.
1324              * Else, reset the DOE ptr to last eval for offset/depth,
1325              * distance/within adjustments for this same content/pcre
1326              * rule option */
1327             if (result == node->num_children)
1328                 continue_loop = 0;
1329             else
1330                 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
1331 
1332             /* Don't need to reset since it's only checked after we've gone
1333              * through the loop at least once and the result will have
1334              * been set again already */
1335             //for (i = 0; i < node->num_children; i++)
1336             //    node->children[i]->result;
1337         }
1338 
1339         if (result - prior_result > 0
1340             && node->option_type == RULE_OPTION_TYPE_CONTENT
1341             && Replace_OffsetStored(&dup_content_option_data) && ScIpsInlineMode())
1342         {
1343           if(!ScDisableReplaceOpt())
1344           {
1345             Replace_QueueChange(&dup_content_option_data);
1346             prior_result = result;
1347           }
1348         }
1349 
1350         NODE_PROFILE_TMPSTART(node);
1351 
1352         if (rval == DETECTION_OPTION_NO_ALERT)
1353         {
1354             /* Reset the flowbit_noalert flag in eval data */
1355             eval_data->flowbit_noalert = tmp_noalert_flag;
1356         }
1357 
1358         if (continue_loop && (rval == DETECTION_OPTION_MATCH) && (node->relative_children))
1359         {
1360             if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
1361                     (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
1362             {
1363                 if (dup_content_option_data.exception_flag)
1364                 {
1365                     continue_loop = 0;
1366                 }
1367                 else
1368                 {
1369                     const uint8_t *orig_ptr;
1370 
1371                     if (dup_content_option_data.use_doe)
1372                         orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
1373                     else
1374                         orig_ptr = dp;
1375 
1376                     continue_loop = PatternMatchAdjustRelativeOffsets((PatternMatchData *)node->option_data,
1377                             &dup_content_option_data, doe_ptr, orig_ptr);
1378                 }
1379             }
1380             else if (node->option_type == RULE_OPTION_TYPE_PCRE)
1381             {
1382                 if (dup_pcre_option_data.options & SNORT_PCRE_INVERT)
1383                 {
1384                     continue_loop = 0;
1385                 }
1386                 else
1387                 {
1388                     const uint8_t *orig_ptr;
1389 
1390                     if (dup_pcre_option_data.options & SNORT_PCRE_RELATIVE)
1391                         orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
1392                     else
1393                         orig_ptr = dp;
1394 
1395                     continue_loop = PcreAdjustRelativeOffsets(&dup_pcre_option_data, doe_ptr - orig_ptr);
1396                 }
1397             }
1398             else
1399             {
1400                 continue_loop = 0;
1401             }
1402         }
1403         else
1404         {
1405             continue_loop = 0;
1406         }
1407 
1408 #ifdef PERF_PROFILING
1409         /* We're essentially checking this node again and it potentially
1410          * might match again */
1411         if (continue_loop && PROFILING_RULES)
1412             node->checks++;
1413 #endif
1414 
1415         loop_count++;
1416 
1417         if (continue_loop)
1418             UpdateDoePtr(orig_doe_ptr, 0);
1419 
1420     } while (continue_loop);
1421 
1422     if (flowbits_setoperation && (result == DETECTION_OPTION_MATCH))
1423     {
1424         /* Do any setting/clearing/resetting/toggling of flowbits here
1425          * given that other rule options matched. */
1426         rval = node->evaluate(node->option_data, eval_data->p);
1427         if (rval != DETECTION_OPTION_MATCH)
1428         {
1429             result = rval;
1430         }
1431     }
1432 
1433     if (eval_data->flowbit_failed)
1434     {
1435         /* something deeper in the tree failed a flowbit test, we may need to
1436          * reeval this node. */
1437         node->last_check.flowbit_failed = 1;
1438     }
1439     node->last_check.result = result;
1440 
1441     if (result == DETECTION_OPTION_NO_MATCH)
1442     {
1443         NODE_PROFILE_END_NOMATCH(node);
1444     }
1445     else
1446     {
1447         NODE_PROFILE_END_MATCH(node);
1448     }
1449 
1450     Reset_DetectFlags(save_dflags);
1451     return result;
1452 }
1453 
1454 #ifdef PERF_PROFILING
1455 typedef struct node_profile_stats
1456 {
1457     uint64_t ticks;
1458     uint64_t ticks_match;
1459     uint64_t ticks_no_match;
1460     uint64_t checks;
1461     uint64_t disables;
1462 } node_profile_stats_t;
1463 
detection_option_node_update_otn_stats(detection_option_tree_node_t * node,node_profile_stats_t * stats,uint64_t checks,uint64_t disables)1464 static void detection_option_node_update_otn_stats(detection_option_tree_node_t *node,
1465                                                    node_profile_stats_t *stats, uint64_t checks
1466 #ifdef PPM_MGR
1467                                                    , uint64_t disables
1468 #endif
1469                                                    )
1470 {
1471     int i;
1472     node_profile_stats_t local_stats; /* cumulative stats for this node */
1473 
1474     if (stats)
1475     {
1476         local_stats.ticks = stats->ticks + node->ticks;
1477         local_stats.ticks_match = stats->ticks_match + node->ticks_match;
1478         local_stats.ticks_no_match = stats->ticks_no_match + node->ticks_no_match;
1479         if (node->checks > stats->checks)
1480             local_stats.checks = node->checks;
1481         else
1482             local_stats.checks = stats->checks;
1483 #ifdef PPM_MGR
1484         local_stats.disables = disables;
1485 #endif
1486     }
1487     else
1488     {
1489         local_stats.ticks = node->ticks;
1490         local_stats.ticks_match = node->ticks_match;
1491         local_stats.ticks_no_match = node->ticks_no_match;
1492         local_stats.checks = node->checks;
1493 #ifdef PPM_MGR
1494         local_stats.disables = disables;
1495 #endif
1496     }
1497 
1498     if (node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1499     {
1500         OptTreeNode *otn = (OptTreeNode *)node->option_data;
1501         /* Update stats for this otn */
1502         otn->ticks += local_stats.ticks;
1503         otn->ticks_match += local_stats.ticks_match;
1504         otn->ticks_no_match += local_stats.ticks_no_match;
1505         if (local_stats.checks > otn->checks)
1506             otn->checks = local_stats.checks;
1507 #ifdef PPM_MGR
1508         otn->ppm_disable_cnt += local_stats.disables;
1509 #endif
1510     }
1511 
1512     if (node->num_children)
1513     {
1514         for (i=0;i<node->num_children; i++)
1515         {
1516             detection_option_node_update_otn_stats(node->children[i], &local_stats, checks
1517 #ifdef PPM_MGR
1518                 , disables
1519 #endif
1520                 );
1521         }
1522     }
1523 }
1524 
detection_option_tree_update_otn_stats(SFXHASH * doth)1525 void detection_option_tree_update_otn_stats(SFXHASH *doth)
1526 {
1527     SFXHASH_NODE *hashnode;
1528 
1529     if (doth == NULL)
1530         return;
1531 
1532     /* Find the first tree root in the table */
1533     hashnode = sfxhash_findfirst(doth);
1534     while (hashnode)
1535     {
1536         detection_option_tree_node_t *node = hashnode->data;
1537         if (node->checks)
1538         {
1539             detection_option_node_update_otn_stats(node, NULL, node->checks
1540 #ifdef PPM_MGR
1541                                                    , node->ppm_disable_cnt
1542 #endif
1543                                                   );
1544         }
1545         hashnode = sfxhash_findnext(doth);
1546     }
1547 }
1548 #endif
1549