"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 }