"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/detection-plugins/sp_byte_math.c" (16 Oct 2020, 33760 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "sp_byte_math.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.9.16.1_vs_2.9.17.
1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2003-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 * Filename sp_byte_math.c
25 *
26 * Authors Krishnakanth <vkambala@cisco.com>
27 * Seshaiah <serugu@cisco.com>
28 *
29 * Description
30 * byte math is tied to the other byte operations – byte_test,byte_extract,byte_jump.
31 * allowed operations are +,-,*,/,<<,>> on the data that was extracted.
32 * options order can be change as they are prefix with identifier.
33 * Parser can identify the option with its prefix.
34 * result varaible should mention in the rule along with bytes_to extract,value and offset.
35 * result varaible stores the output of the byte_math opeation
36 * Byte_math output can be given input to Byte_extarct offset, Byte_Jump offset and Byte_test offset and value options
37
38 *Eg : byte_math: bytes 2, offset 0, oper *, rvalue 10, result area; byte_test:2,>,area,16;
39 * At the zero offset of the paylod, extract 2 bytes and apply multiplication operation with value 10,store result in variable area. The area variable output is given as
40 * input to byte_test value.
41 *
42 * Lets consider 2 bytes of extarcted data in byte_math is 5.
43 * The rvalue is 10. after multiplication operator applied between rvalue and extracted data,it became 50.
44 * result option variable area holds value 50.
45 * the byte_test can use the area varaible as input to it in either offset/value options.
46 *
47 * Rule Examples :
48 * alert tcp any any -> any any (sid :1;byte_math:bytes 4,oper +,rvalue 123, offset 12,result var; msg: "Byte_math_valid";content : "|74 63 6c 61|";)
49 *
50 * alert tcp any any -> any any (sid :1;byte_math:bytes 1,oper <<,rvalue 123, offset 12,result var; msg: "Byte_math_valid";content : "|74 63 6c 61|";)
51 *
52 * alert tcp any any -> any any (msg:"byte_math IT : byte_jump ####### CASE-5 # byte_math byte_extract and byte_jump with bitmask in each rule"; byte_math:oper /,rvalue 2, relative, result OFF1,offset 0, endian big,bytes 1,bitmask 0xA;byte_extract:1,1,OFF2,bitmask 0xA;byte_jump:1,OFF2,bitmask 0xA;byte_extract:1,3,VALUE,bitmask 0x5; byte_test:1,<,VALUE,OFF1,bitmask 0xCB;content:"SKIPME"; sid:2;)
53
54 */
55
56 #ifdef HAVE_CONFIG_H
57 #include "config.h"
58 #endif
59
60 #include <sys/types.h>
61 #include <stdlib.h>
62 #include <ctype.h>
63 #ifdef HAVE_STRINGS_H
64 #include <strings.h>
65 #endif
66 #include <errno.h>
67 #include "limits.h"
68 #include "sf_types.h"
69 #include "snort_bounds.h"
70 #include "byte_extract.h"
71 #include "rules.h"
72 #include "treenodes.h"
73 #include "decode.h"
74 #include "plugbase.h"
75 #include "parser.h"
76 #include "snort_debug.h"
77 #include "util.h"
78 #include "plugin_enum.h"
79 #include "mstring.h"
80 #include "sfhashfcn.h"
81 #include "sp_byte_math.h"
82 #include "sp_byte_extract.h"
83
84 #define PARSELEN 10
85 #define TEXTLEN (PARSELEN + 2)
86
87 #include "snort.h"
88 #include "profiler.h"
89 #include "sfhashfcn.h"
90 #include "detection_options.h"
91 #include "detection_util.h"
92
93 #ifdef PERF_PROFILING
94 PreprocStats byteMathPerfStats;
95 extern PreprocStats ruleOTNEvalPerfStats;
96 #endif
97
98
99
100 typedef struct _ByteMathOverrideData
101 {
102 char *keyword;
103 char *option;
104 union
105 {
106 RuleOptOverrideFunc fptr;
107 void *void_fptr;
108 } fptr;
109 struct _ByteMathOverrideData *next;
110
111 } ByteMathOverrideData;
112
113 ByteMathOverrideData *byteMathOverrideFuncs = NULL;
114
115 static void ByteMathOverride(char *keyword, char *option, RuleOptOverrideFunc roo_func);
116 static void ByteMathOverrideFuncsFree(void);
117 static void ByteMathInit(struct _SnortConfig *, char *, OptTreeNode *, int);
118 static ByteMathOverrideData * ByteMathParse(char *data, ByteMathData *idx, OptTreeNode *otn);
119 static void ByteMathOverrideCleanup(int, void *);
120 static char* ByteMath_tok_extract(char *,char *);
121 void AddVarName_Bytemath(ByteMathData *);
122
123 char *bytemath_variable_name = NULL;
124 uint32_t bytemath_variable;
125 uint32_t common_var;
126
127 uint32_t find_value (char *token)
128 {
129 if (token == NULL)
130 return BYTE_EXTRACT_NO_VAR;
131
132 uint32_t match_e = 0 ,match_b = 0;
133 /* check byte_math already has the same name */
134 if ( bytemath_variable_name && (strcmp(bytemath_variable_name,token) == 0) )
135 match_b = BYTE_MATH_VAR_INDEX;
136
137 /* check byte_extract already has the same name */
138 match_e = GetVarByName(token);
139
140 /* if same name found in both pick the latest one else the matched one */
141 if ( (match_e != BYTE_EXTRACT_NO_VAR) && (match_b == BYTE_MATH_VAR_INDEX) )
142 {
143 return COMMON_VAR_INDEX;
144 }
145 else if ( (match_e != BYTE_EXTRACT_NO_VAR) && (match_b != BYTE_MATH_VAR_INDEX) )
146 {
147 return match_e;
148 }
149 else if ( (match_e == BYTE_EXTRACT_NO_VAR) && (match_b == BYTE_MATH_VAR_INDEX) )
150 {
151 return BYTE_MATH_VAR_INDEX;
152 }
153 return BYTE_EXTRACT_NO_VAR;
154 }
155
156 uint32_t ByteMathHash(void *d)
157 {
158 uint32_t a,b,c;
159 ByteMathData *data = (ByteMathData *)d;
160
161 a = data->bytes_to_extract;
162 b = data->rvalue;
163 c = data->operator;
164
165 mix(a,b,c);
166
167 a += data->offset;
168 b += (data->rvalue_var << 24 |
169 data->relative_flag << 16 |
170 data->data_string_convert_flag << 8 |
171 data->endianess);
172 c += data->base;
173
174 mix(a,b,c);
175
176 a += RULE_OPTION_TYPE_BYTE_MATH;
177 b += data->bitmask_val;
178 c += data->offset_var;
179
180 mix(a,b,c);
181
182 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
183 {
184 /* Cleanup warning because of cast from 64bit ptr to 32bit int
185 * warning on 64bit OSs */
186 uint64_t ptr; /* Addresses are 64bits */
187
188 ptr = (uint64_t) data->byte_order_func;
189 a += (ptr >> 32);
190 b += (ptr & 0xFFFFFFFF);
191 }
192 #else
193 a += (uint32_t)data->byte_order_func;
194 #endif
195
196 final(a,b,c);
197
198 return c;
199 }
200
201
202 int ByteMathCompare(void *l, void *r)
203 {
204 ByteMathData *left = (ByteMathData *)l;
205 ByteMathData *right = (ByteMathData *)r;
206
207 if (!left || !right)
208 return DETECTION_OPTION_NOT_EQUAL;
209
210 if (( left->bytes_to_extract == right->bytes_to_extract) &&
211 ( left->rvalue == right->rvalue) &&
212 ( left->operator == right->operator) &&
213 ( left->offset == right->offset) &&
214 ( left->relative_flag == right->relative_flag) &&
215 ( left->data_string_convert_flag == right->data_string_convert_flag) &&
216 ( left->endianess == right->endianess) &&
217 ( left->base == right->base) &&
218 ( left->bitmask_val == right->bitmask_val) &&
219 ( left->rvalue_var == right->rvalue_var) &&
220 ( left->offset_var == right->offset_var) &&
221 ( left->byte_order_func == right->byte_order_func))
222 {
223 return DETECTION_OPTION_EQUAL;
224 }
225
226 return DETECTION_OPTION_NOT_EQUAL;
227 }
228
229 static void ByteMathOverride(char *keyword, char *option, RuleOptOverrideFunc roo_func)
230 {
231 ByteMathOverrideData *new = SnortAlloc(sizeof(ByteMathOverrideData));
232
233 new->keyword = SnortStrdup(keyword);
234 new->option = SnortStrdup(option);
235 new->func = roo_func;
236
237 new->next = byteMathOverrideFuncs;
238 byteMathOverrideFuncs = new;
239 }
240
241
242 static void ByteMathOverrideFuncsFree(void)
243 {
244 ByteMathOverrideData *node = byteMathOverrideFuncs;
245
246 while (node != NULL)
247 {
248 ByteMathOverrideData *tmp = node;
249
250 node = node->next;
251
252 if (tmp->keyword != NULL)
253 free(tmp->keyword);
254
255 if (tmp->option != NULL)
256 free(tmp->option);
257
258 free(tmp);
259 }
260
261 byteMathOverrideFuncs = NULL;
262 }
263
264 static void ByteMathOverrideCleanup(int signal, void *data)
265 {
266 if (byteMathOverrideFuncs != NULL)
267 ByteMathOverrideFuncsFree();
268 }
269
270 /****************************************************************************
271 * Function: SetupByteMath()
272 *
273 * Purpose: Register byte_math name and initialization function
274 *
275 * Arguments: None.
276 *
277 * Returns: void function
278 *
279 ****************************************************************************/
280 void SetupByteMath(void)
281 {
282 /* map the keyword to an initialization/processing function */
283 RegisterRuleOption("byte_math", ByteMathInit, ByteMathOverride, OPT_TYPE_DETECTION, NULL);
284 AddFuncToCleanExitList(ByteMathOverrideCleanup, NULL);
285 AddFuncToRuleOptParseCleanupList(ByteMathOverrideFuncsFree);
286 #ifdef PERF_PROFILING
287 RegisterPreprocessorProfile("byte_math", &byteMathPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
288 #endif
289 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: ByteMath Setup\n"););
290 }
291
292 /****************************************************************************
293 *
294 * Function: ByteMathInit(char *, OptTreeNode *)
295 *
296 * Purpose: Generic rule configuration function. Handles parsing the rule
297 * information and attaching the associated detection function to
298 * the OTN.
299 *
300 * Arguments: data => rule arguments/data
301 * otn => pointer to the current rule option list node
302 * protocol => protocol the rule is on (we don't care in this case)
303 *
304 * Returns: void function
305 *
306 ****************************************************************************/
307 static void ByteMathInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
308 {
309
310 ByteMathData *idx;
311 OptFpList *fpl;
312 ByteMathOverrideData *override;
313 void *idx_dup;
314
315 /* allocate the data structure and attach it to the
316 rule's data struct list */
317 idx = (ByteMathData *) calloc(sizeof(ByteMathData), sizeof(char));
318
319 if(idx == NULL)
320 {
321 ParseError("Byte_Math Unable to allocate byte_Math data node\n");
322 }
323 /* this is where the keyword arguments are processed and placed into the
324 rule option's data structure */
325 override = ByteMathParse(data, idx, otn);
326 if (override)
327 {
328 /* There is an override function */
329 free(idx->result_var);
330 free(idx);
331 override->func(sc, override->keyword, override->option, data, otn, protocol);
332 return;
333 }
334
335 AddVarName_Bytemath(idx);
336
337 fpl = AddOptFuncToList(ByteMath, otn);
338 fpl->type = RULE_OPTION_TYPE_BYTE_MATH;
339
340 if (add_detection_option(sc, RULE_OPTION_TYPE_BYTE_MATH, (void *)idx, &idx_dup) == DETECTION_OPTION_EQUAL)
341 {
342 #ifdef DEBUG_RULE_OPTION_TREE
343 LogMessage("Byte_Math Duplicate ByteCheck:\n%d %d %c %d %d %c %c %c %c 0x%x %d\n"
344 "%d %d %c %d %d %c %c %c %c 0x%x %d\n\n",
345 idx->bytes_to_extract,
346 idx->rvalue,idx->rvalue_var,
347 idx->operator,
348 idx->offset,idx->offset_var,
349 idx->relative_flag,
350 idx->data_string_convert_flag,
351 idx->endianess, idx->base,
352 idx->bitmask_val,
353 ((ByteMathData *)idx_dup)->bytes_to_extract,
354 ((ByteMathData *)idx_dup)->rvalue,
355 ((ByteMathData *)idx_dup)->rvalue_var,
356 ((ByteMathData *)idx_dup)->operator,
357 ((ByteMathData *)idx_dup)->offset,
358 ((ByteMathData *)idx_dup)->offset_var,
359 ((ByteMathData *)idx_dup)->relative_flag,
360 ((ByteMathData *)idx_dup)->data_string_convert_flag,
361 ((ByteMathData *)idx_dup)->bitmask_val,
362 ((ByteMathData *)idx_dup)->endianess, ((ByteMathData *)idx_dup)->base);
363 #endif
364 free(idx->result_var);
365 free(idx);
366 idx = idx_dup;
367 }
368
369 /* attach it to the context node so that we can call each instance
370 * individually
371 */
372 fpl->context = (void *) idx;
373
374 if (idx->relative_flag == 1)
375 fpl->isRelative = 1;
376 }
377
378 /****************************************************************************
379 *
380 * Function: ByteMath_tok_extract(char *,char *)
381 *
382 * Purpose: This function does extracting token content in rule options
383 *
384 * Arguments: src => Input token from the rule
385 * del => Option the token to be mapped
386 *
387 * Returns: On success returns the resultant string address else trigger fatal error
388 *
389 ****************************************************************************/
390
391 static char* ByteMath_tok_extract(char *src,char *del)
392 {
393 char *ret_tok=NULL;
394 ret_tok = strtok(src," ");
395 if (ret_tok && !strcmp(ret_tok,del))
396 {
397 ret_tok = strtok(NULL, ",");
398 if (ret_tok)
399 {
400 while(isspace((int)*ret_tok)) {ret_tok++;}
401 return (ret_tok);
402 }
403 }
404 ParseError("Byte_Math token input[%s] is invalid one for options[%s]\n",ret_tok,del);
405 return ret_tok;
406 }
407
408
409 /****************************************************************************
410 *
411 * Function: ByteMathParse(char *, ByteMathData *, OptTreeNode *)
412 *
413 * Purpose: This is the function that is used to process the option keyword's
414 * arguments and attach them to the rule's data structures.
415 *
416 * Arguments: data => argument data
417 * idx => pointer to the processed argument storage
418 * otn => pointer to the current rule's OTN
419 *
420 * Returns: void function
421 *
422 ****************************************************************************/
423
424
425 static ByteMathOverrideData * ByteMathParse(char *data, ByteMathData *idx, OptTreeNode *otn)
426 {
427
428 char **toks;
429 char *endp;
430 int num_toks;
431 char *cptr;
432 int i = 0;
433 bool offset_flag = false;
434 RuleOptByteOrderFunc tmp_byte_order_func;
435
436 idx->rvalue_var = -1;
437
438 toks = mSplit(data, ",", 13, &num_toks, 0);
439
440 while(i < num_toks)
441 {
442 cptr=toks[i];
443 while(isspace((int)*cptr)) {cptr++;}
444 /* set how many bytes to process from the packet */
445 if (!strncmp(cptr,"bytes",5))
446 {
447 if (!idx->bytes_to_extract)
448 {
449 cptr=ByteMath_tok_extract(cptr,"bytes");
450 idx->bytes_to_extract = strtol(cptr, &endp, 10);
451 if (*endp != '\0')
452 {
453 ParseError("byte_math option has bad input: %s.", cptr);
454 }
455 if(idx->bytes_to_extract > PARSELEN || idx->bytes_to_extract == 0)
456 {
457 ParseError("byte_math option bytes_to_extract has invalid input.valid range is 1 to 10 bytes\n");
458 }
459 i++;
460 continue;
461
462 }
463 }
464
465 else if (!strncmp(cptr,"oper",4))
466 {
467 if (!idx->operator)
468 {
469 cptr=ByteMath_tok_extract(cptr,"oper");
470 /* set the operator */
471 switch(*cptr)
472 {
473 case '+': idx->operator = BM_PLUS;
474 break;
475
476 case '-': idx->operator = BM_MINUS;
477 break;
478
479 case '*': idx->operator = BM_MULTIPLY;
480 break;
481
482 case '/': idx->operator = BM_DIVIDE;
483 break;
484
485 case '<': cptr++;
486 if (*cptr == '<')
487 idx->operator = BM_LEFT_SHIFT;
488 else
489 ParseError("byte_math unknown operator [%s]\n",--cptr);
490 break;
491
492 case '>': cptr++;
493 if (*cptr == '>')
494 idx->operator = BM_RIGHT_SHIFT;
495 else
496 ParseError("byte_math unknown operator [%s]\n",--cptr);
497 break;
498
499 default:
500 ParseError("byte_math unknown operator [%s]\n",cptr);
501 }
502
503 cptr++;
504 if (*cptr)
505 {
506 ParseError("byte_math unknown operator[%s]\n",--cptr);
507 }
508 i++;
509 continue;
510 }
511 else
512 {
513 ParseError("byte_math option OPERATOR is already configured in rule\n");
514 }
515 }
516
517 else if (!strncmp(cptr,"rvalue",6))
518 {
519 if (!idx->rvalue)
520 {
521 /* set the value to test against */
522 cptr=ByteMath_tok_extract(cptr,"rvalue");
523 if (isdigit(*cptr) || *cptr == '-')
524 {
525 int64_t rval = SnortStrtoul(cptr, &endp,0);
526 if (rval > MAX_RVAL || !rval)
527 {
528 ParseError("byte_math rule option has invalid rvalue."
529 "Valid rvalue range %u-%u.",
530 MIN_RVAL,MAX_RVAL);
531 }
532 idx->rvalue=rval;
533 idx->rvalue_var = -1;
534 if(*endp != '\0')
535 {
536 ParseError("byte_math option has bad rvalue: %s", cptr);
537 }
538 }
539 else
540 {
541 idx->rvalue_var = GetVarByName(cptr);
542 if (idx->rvalue_var == BYTE_EXTRACT_NO_VAR)
543 {
544 ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "byte_Math", cptr);
545 }
546 }
547 i++;
548 continue;
549 }
550 else
551 {
552 ParseError("byte_math rvalue is already configured in rule once\n");
553 }
554 }
555
556 else if (!strncmp(cptr,"offset",6))
557 {
558 if (!idx->offset)
559 {
560 cptr=ByteMath_tok_extract(cptr,"offset");
561 /* set offset */
562 if (isdigit(*cptr) || *cptr == '-')
563 {
564 idx->offset = SnortStrtoul(cptr, &endp,0);
565 idx->offset_var = -1;
566 if(*endp != '\0')
567 {
568 ParseError("byte_math option has bad offset: %s", cptr);
569 }
570 }
571 else
572 {
573 idx->offset_var = GetVarByName(cptr);
574 if (idx->offset_var == BYTE_EXTRACT_NO_VAR)
575 {
576 ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "byte_Math", cptr);
577 }
578 }
579 offset_flag = true;
580 i++;
581 continue;
582 }
583 else
584 {
585 ParseError("byte_math option offset is Already configured in rule once\n");
586 }
587 }
588 else if (!strncmp(cptr,"result",6))
589 {
590 if (!idx->result_var)
591 {
592 cptr=ByteMath_tok_extract(cptr,"result");
593 /* set result variable */
594 idx->result_var = SnortStrdup(cptr);
595 if (!idx->result_var)
596 ParseError("byte_Math::result_var malloc failure");
597
598 if (idx->result_var && isdigit(idx->result_var[0]))
599 {
600 free(idx->result_var);
601 ParseError("byte_Math rule option has a name which starts with a digit. "
602 "Variable names must start with a letter.");
603 }
604 isvalidstr(idx->result_var,"byte_math");
605 i++;
606 continue;
607 }
608 else
609 {
610
611 ParseError("byte_math result is Already configured in rule once\n");
612 }
613 }
614
615 else if (!strncmp(cptr,"relative",8))
616 {
617 /* the offset is relative to the last pattern match */
618 idx->relative_flag = 1;
619 i++;
620 continue;
621 }
622 else if(!strncmp(cptr, "string",6))
623 {
624 if (!idx->data_string_convert_flag )
625 {
626 /* the data will be represented as a string that needs
627 * to be converted to an int, binary is assumed otherwise
628 */
629 idx->data_string_convert_flag = 1;
630 cptr=ByteMath_tok_extract(cptr,"string");
631 if(!strcasecmp(cptr, "hex"))
632 {
633 idx->base = 16;
634 }
635 else if(!strcasecmp(cptr, "dec"))
636 {
637 idx->base = 10;
638 }
639 else if(!strcasecmp(cptr, "oct"))
640 {
641 idx->base = 8;
642 }
643 else
644 {
645 ParseError("byte_math Unable to parse string option\n");
646 }
647 }
648 else
649 {
650 ParseError("byte_math string is Already configured in rule once\n");
651 }
652 i++;
653 continue;
654 }
655
656 else if(strncasecmp(cptr,"bitmask ",8) == 0)
657 {
658 RuleOptionBitmaskParse(&(idx->bitmask_val), cptr, idx->bytes_to_extract,"BYTE_MATH");
659 i++;
660 continue;
661 }
662 else if(!strncmp(cptr, "endian",6))
663 {
664 if (!idx->endianess)
665 {
666 cptr=ByteMath_tok_extract(cptr,"endian");
667 if(!strcasecmp(cptr, "little"))
668 {
669 idx->endianess = LITTLE;
670 }
671 else if(!strcasecmp(cptr, "big"))
672 {
673 /* this is the default */
674 idx->endianess = BIG;
675 }
676 else
677 {
678 ParseError("byte_math Unable to parse Endian option\n");
679 }
680 }
681 else
682 {
683
684 ParseError("byte_math Endian is Already configured in rule\n");
685 }
686 i++;
687 continue;
688 }
689 else if((tmp_byte_order_func = GetByteOrderFunc(cptr)) != NULL)
690 {
691 idx->byte_order_func = tmp_byte_order_func;
692 i++;
693 continue;
694 }
695 else
696 {
697 ByteMathOverrideData *override = byteMathOverrideFuncs;
698
699 while (override != NULL)
700 {
701 if (!strcasecmp(cptr, override->option))
702 {
703 mSplitFree(&toks, num_toks);
704 return override;
705 }
706
707 override = override->next;
708 }
709
710 ParseError("byte_math unknown modifier \"%s\"\n",cptr);
711 }
712
713
714 }
715 if ( (!idx->bytes_to_extract) || (!idx->operator) || ( (!idx->rvalue) && (idx->rvalue_var == -1) ) || (!idx->result_var) || (!offset_flag) )
716 {
717 ParseError("Check the bytes_to_extract/operator/offset/rvalue/result variable\n");
718 }
719 if ( ( (idx->operator == BM_LEFT_SHIFT) || (idx->operator == BM_RIGHT_SHIFT) ) && (idx->rvalue >32) )
720 {
721 ParseError("Number of bits in rvalue input [%d] should be less than 32 bits for operator\n",idx->rvalue);
722 }
723 if ( ( (idx->operator == BM_LEFT_SHIFT) || (idx->operator == BM_RIGHT_SHIFT) ) && (idx->bytes_to_extract >4) )
724 {
725 ParseError("for operators << and >> valid bytes_to_extract input range is 1 to 4 bytes\n");
726 }
727 if (idx->offset < MIN_BYTE_EXTRACT_OFFSET || idx->offset > MAX_BYTE_EXTRACT_OFFSET)
728 {
729 ParseError("byte_math rule option has invalid offset. "
730 "Valid offsets are between %d and %d.",
731 MIN_BYTE_EXTRACT_OFFSET, MAX_BYTE_EXTRACT_OFFSET);
732 }
733 if (idx->bytes_to_extract > MAX_BYTES_TO_GRAB && !idx->data_string_convert_flag)
734 {
735 ParseError("byte_math rule option cannot extract more than %d bytes without valid string prefix.",
736 MAX_BYTES_TO_GRAB);
737 }
738 mSplitFree(&toks, num_toks);
739 return NULL;
740
741 }
742
743
744 /****************************************************************************
745 *
746 * Function: ByteMath(char *, OptTreeNode *, OptFpList *)
747 *
748 * Purpose: Use this function to perform the particular detection routine
749 * that this rule keyword is supposed to encompass.
750 *
751 * Arguments: p => pointer to the decoded packet
752 * otn => pointer to the current rule's OTN
753 * fp_list => pointer to the function pointer list
754 *
755 * Returns: If the detection test fails, this function *must* return a zero!
756 * On success, it calls the next function in the detection list
757 *
758 ****************************************************************************/
759 int ByteMath(void *option_data, Packet *p)
760 {
761 ByteMathData *btd = (ByteMathData *)option_data;
762 int rval = DETECTION_OPTION_NO_MATCH;
763 uint32_t *value = 0;
764 int success = 0;
765 int dsize;
766 const char *base_ptr, *end_ptr, *start_ptr;
767 int payload_bytes_grabbed;
768 int32_t offset;
769 uint32_t extract_offset, extract_rvalue;
770 int search_start = 0;
771 PROFILE_VARS;
772
773 PREPROC_PROFILE_START(byteMathPerfStats);
774
775 if (Is_DetectFlag(FLAG_ALT_DETECT))
776 {
777 dsize = DetectBuffer.len;
778 start_ptr = (const char*)DetectBuffer.data;
779 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
780 "Using Alternative Detect buffer!\n"););
781 }
782 else if(Is_DetectFlag(FLAG_ALT_DECODE))
783 {
784 dsize = DecodeBuffer.len;
785 start_ptr = (char *)DecodeBuffer.data;
786 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
787 "Using Alternative Decode buffer!\n"););
788 }
789 else
790 {
791 if(IsLimitedDetect(p))
792 dsize = p->alt_dsize;
793 else
794 dsize = p->dsize;
795 start_ptr = (char *) p->data;
796 }
797
798 base_ptr = start_ptr;
799 end_ptr = start_ptr + dsize;
800
801 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
802 "[*] byte Math firing...\n");
803 DebugMessage(DEBUG_PATTERN_MATCH,"payload starts at %p\n", start_ptr);
804 DebugMessage(DEBUG_PATTERN_MATCH,"payload ends at %p\n", end_ptr);
805 DebugMessage(DEBUG_PATTERN_MATCH,"doe_ptr %p\n", doe_ptr);
806 );
807
808 value = &bytemath_variable;
809
810 /* Get values from byte_extract variables, if present. */
811 if (btd->rvalue_var >= 0 && btd->rvalue_var < NUM_BYTE_EXTRACT_VARS)
812 {
813 GetByteExtractValue(&extract_rvalue, btd->rvalue_var);
814 btd->rvalue = (int32_t) extract_rvalue;
815 if (!btd->rvalue && (btd->operator == BM_DIVIDE))
816 {
817 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
818 "byte math input value zero for Divide operator is invalid\n"););
819 PREPROC_PROFILE_END(byteMathPerfStats);
820 return DETECTION_OPTION_NO_MATCH;
821 }
822 }
823
824 if (btd->offset_var >= 0 && btd->offset_var < NUM_BYTE_EXTRACT_VARS)
825 {
826 GetByteExtractValue(&extract_offset, btd->offset_var);
827 btd->offset = (int32_t) extract_offset;
828 }
829
830 if(btd->relative_flag && doe_ptr)
831 {
832 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
833 "Checking relative offset!\n"););
834
835 /* @todo: possibly degrade to use the other buffer, seems non-intuitive
836 * Because doe_ptr can be "end" in the last match,
837 * use end + 1 for upper bound
838 * Bound checked also after offset is applied
839 * (see byte_extract() and string_extract())
840 */
841 if(!inBounds((const uint8_t *)start_ptr, (const uint8_t *)end_ptr + 1, doe_ptr))
842 {
843 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
844 "[*] byte Math bounds check failed..\n"););
845 PREPROC_PROFILE_END(byteMathPerfStats);
846 return rval;
847 }
848
849 search_start = (doe_ptr - (const uint8_t *)start_ptr) + btd->offset;
850 base_ptr = (const char *)doe_ptr;
851 }
852 else
853 {
854 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
855 "checking absolute offset %d\n", btd->offset););
856 search_start = btd->offset;
857 base_ptr = start_ptr;
858 }
859
860 if( search_start < 0 )
861 {
862 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
863 "[*] byte Math bounds check failed..\n"););
864 PREPROC_PROFILE_END(byteMathPerfStats);
865 return rval;
866 }
867
868 base_ptr = base_ptr + btd->offset;
869
870 /* Use byte_order_func to determine endianess, if present */
871 if (btd->byte_order_func)
872 {
873 offset = (int32_t) ((const uint8_t *)base_ptr - p->data);
874 btd->endianess = btd->byte_order_func(p, offset);
875 if (btd->endianess == -1)
876 {
877 PREPROC_PROFILE_END(byteMathPerfStats);
878 return DETECTION_OPTION_NO_MATCH;
879 }
880 }
881
882 /* both of these functions below perform their own bounds checking within
883 * byte_extract.c
884 */
885 if(!btd->data_string_convert_flag)
886 {
887 if(byte_extract(btd->endianess, btd->bytes_to_extract,
888 (const uint8_t *)base_ptr, (const uint8_t *)start_ptr, (const uint8_t *)end_ptr, value))
889 {
890 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
891 "Byte Extraction Failed\n"););
892
893 PREPROC_PROFILE_END(byteMathPerfStats);
894 return rval;
895 }
896 payload_bytes_grabbed = (int)btd->bytes_to_extract;
897 }
898 else
899 {
900 payload_bytes_grabbed = string_extract(
901 btd->bytes_to_extract, btd->base,
902 (const uint8_t *)base_ptr, (const uint8_t *)start_ptr,
903 (const uint8_t *)end_ptr, value);
904
905 if ( payload_bytes_grabbed < 0 )
906 {
907 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
908 "String Extraction Failed\n"););
909
910 PREPROC_PROFILE_END(byteMathPerfStats);
911 return rval;
912 }
913
914 }
915
916 if(btd->bitmask_val != 0 )
917 {
918 int num_tailing_zeros_bitmask = getNumberTailingZerosInBitmask(btd->bitmask_val);
919 *value = (*value) & btd->bitmask_val ;
920 if ( (*value ) && num_tailing_zeros_bitmask )
921 {
922 *value = (*value) >> num_tailing_zeros_bitmask;
923 }
924 }
925
926 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
927 "Grabbed %d bytes at offset %d rvalue = 0x%08X(%u) value = 0x%08X(%u)\n",
928 payload_bytes_grabbed, btd->offset, btd->rvalue, btd->rvalue, value, value); );
929 switch(btd->operator)
930 {
931 case BM_PLUS: if ((UINT_MAX - *value) < btd->rvalue)
932 {
933 LogMessage("%s-%d > %s-%d Buffer Overflow during ADDITION\n",
934 inet_ntoa(GET_SRC_IP(p)),ntohs(p->tcph->th_sport),
935 inet_ntoa(GET_DST_IP(p)),ntohs(p->tcph->th_dport));
936 return DETECTION_OPTION_NO_MATCH;
937 }
938 else
939 {
940 *value += btd->rvalue;
941 success = 1;
942 break;
943 }
944
945 case BM_MINUS: if (*value < btd->rvalue)
946 {
947 LogMessage("%s-%d > %s-%d Buffer Underflow during SUBTRACTION\n",
948 inet_ntoa(GET_SRC_IP(p)),ntohs(p->tcph->th_sport),
949 inet_ntoa(GET_DST_IP(p)),ntohs(p->tcph->th_dport));
950 return DETECTION_OPTION_NO_MATCH;
951 }
952 else
953 {
954 *value -= btd->rvalue;
955 success = 1;
956 break;
957 }
958
959 case BM_MULTIPLY: if ( (*value) && ((UINT_MAX/(*value)) < btd->rvalue))
960 {
961 LogMessage("%s-%d > %s-%d Buffer Overflow during MULTIPLY\n",
962 inet_ntoa(GET_SRC_IP(p)),ntohs(p->tcph->th_sport),
963 inet_ntoa(GET_DST_IP(p)),ntohs(p->tcph->th_dport));
964 return DETECTION_OPTION_NO_MATCH;
965 }
966 else
967 {
968 *value *= btd->rvalue;
969 success = 1;
970 break;
971 }
972
973 case BM_DIVIDE: *value = (*value/ btd->rvalue);
974 success = 1;
975 break;
976
977 case BM_LEFT_SHIFT: *value = (*value << btd->rvalue);
978 success = 1;
979 break;
980
981 case BM_RIGHT_SHIFT: *value = (*value >> btd->rvalue);
982 success = 1;
983 break;
984 }
985
986 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
987 "byte_math result final value = 0x%08X(%u)\n",
988 value, value); );
989 if (success)
990 {
991 rval = DETECTION_OPTION_MATCH;
992 common_var = *value;
993 }
994
995 /* if the test isn't successful, this function *must* return 0 */
996 PREPROC_PROFILE_END(byteMathPerfStats);
997 return rval;
998 }
999
1000 void ByteMathFree(void *d)
1001 {
1002 ByteMathData *data = (ByteMathData *)d;
1003 if (data && data->result_var)
1004 {
1005 free(data->result_var);
1006 data->result_var=NULL;
1007 }
1008
1009 if ( bytemath_variable_name != NULL )
1010 {
1011 free( bytemath_variable_name );
1012 bytemath_variable_name = NULL;
1013 }
1014 free(data);
1015 }
1016
1017 /*for given an OptFpList,clear the variable_name */
1018 void ClearByteMathVarNames(OptFpList *fpl)
1019 {
1020 while (fpl != NULL)
1021 {
1022 if (fpl->type == RULE_OPTION_TYPE_BYTE_MATH)
1023 return;
1024
1025 fpl = fpl->next;
1026 }
1027 if (bytemath_variable_name != NULL)
1028 {
1029 free(bytemath_variable_name);
1030 bytemath_variable_name = NULL;
1031 }
1032 }
1033
1034 /* Given a variable name, retrieve its index. For use by other options.dynamic-plugin support */
1035 int8_t GetVarByName_check(char *name)
1036 {
1037 return (find_value(name));
1038 }
1039
1040 void AddVarName_Bytemath(ByteMathData *data)
1041 {
1042 if (bytemath_variable_name != NULL)
1043 {
1044 free(bytemath_variable_name);
1045 bytemath_variable_name = NULL;
1046 }
1047 bytemath_variable_name = SnortStrdup(data->result_var);
1048
1049 }
1050
1051 int8_t Var_check_byte_math(char *name)
1052 {
1053 if (!strcmp(bytemath_variable_name,name))
1054 {
1055 return 1;
1056 }
1057 return 0;
1058 }