"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/detection-plugins/sp_byte_check.c" (16 Oct 2020, 27255 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_check.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 /* $Id$ */
    2 /*
    3  ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4  ** Copyright (C) 2002-2013 Sourcefire, Inc.
    5  ** Author: Martin Roesch
    6  **
    7  ** This program is free software; you can redistribute it and/or modify
    8  ** it under the terms of the GNU General Public License Version 2 as
    9  ** published by the Free Software Foundation.  You may not use, modify or
   10  ** distribute this program under any other version of the GNU General
   11  ** Public License.
   12  **
   13  ** This program is distributed in the hope that it will be useful,
   14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  ** GNU General Public License for more details.
   17  **
   18  ** You should have received a copy of the GNU General Public License
   19  ** along with this program; if not, write to the Free Software
   20  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   21  */
   22 
   23 /* sp_byte_check
   24  *
   25  * Purpose:
   26  *      Test a byte field against a specific value (with operator).  Capable
   27  *      of testing binary values or converting represenative byte strings
   28  *      to their binary equivalent and testing them.
   29  *
   30  *
   31  * Arguments:
   32  *      Required:
   33  *      <bytes_to_convert>: number of bytes to pick up from the packet
   34  *      <operator>: operation to perform to test the value (<,>,=,!)
   35  *      <value>: value to test the converted value against
   36  *      <offset>: number of bytes into the payload to start processing
   37  *      Optional:
   38  *      ["relative"]: offset relative to last pattern match
   39  *      ["big"]: process data as big endian (default)
   40  *      ["little"]: process data as little endian
   41  *      ["string"]: converted bytes represented as a string needing conversion
   42  *      ["hex"]: converted string data is represented in hexidecimal
   43  *      ["dec"]: converted string data is represented in decimal
   44  *      ["oct"]: converted string data is represented in octal
   45  *
   46  *   sample rules:
   47  *   alert udp $EXTERNAL_NET any -> $HOME_NET any \
   48  *      (msg:"AMD procedure 7 plog overflow "; \
   49  *      content: "|00 04 93 F3|"; \
   50  *      content: "|00 00 00 07|"; distance: 4; within: 4; \
   51  *      byte_test: 4,>, 1000, 20, relative;)
   52  *
   53  *   alert tcp $EXTERNAL_NET any -> $HOME_NET any \
   54  *      (msg:"AMD procedure 7 plog overflow "; \
   55  *      content: "|00 04 93 F3|"; \
   56  *      content: "|00 00 00 07|"; distance: 4; within: 4; \
   57  *      byte_test: 4, >,1000, 20, relative;)
   58  *
   59  * alert udp any any -> any 1234 \
   60  *      (byte_test: 4, =, 1234, 0, string, dec; \
   61  *      msg: "got 1234!";)
   62  *
   63  * alert udp any any -> any 1235 \
   64  *      (byte_test: 3, =, 123, 0, string, dec; \
   65  *      msg: "got 123!";)
   66  *
   67  * alert udp any any -> any 1236 \
   68  *      (byte_test: 2, =, 12, 0, string, dec; \
   69  *      msg: "got 12!";)
   70  *
   71  * alert udp any any -> any 1237 \
   72  *      (byte_test: 10, =, 1234567890, 0, string, dec; \
   73  *      msg: "got 1234567890!";)
   74  *
   75  * alert udp any any -> any 1238 \
   76  *      (byte_test: 8, =, 0xdeadbeef, 0, string, hex; \
   77  *      msg: "got DEADBEEF!";)
   78  *
   79  * Effect:
   80  *
   81  *      Reads in the indicated bytes, converts them to an numeric
   82  *      representation and then performs the indicated operation/test on
   83  *      the data using the value field.  Returns 1 if the operation is true,
   84  *      0 if it is not.
   85  *
   86  * Comments:
   87  *
   88  * Any comments?
   89  *
   90  */
   91 
   92 #ifdef HAVE_CONFIG_H
   93 #include "config.h"
   94 #endif
   95 
   96 #include <sys/types.h>
   97 #include <stdlib.h>
   98 #include <ctype.h>
   99 #ifdef HAVE_STRINGS_H
  100 #include <strings.h>
  101 #endif
  102 #include <errno.h>
  103 
  104 #include "sf_types.h"
  105 #include "snort_bounds.h"
  106 #include "byte_extract.h"
  107 #include "rules.h"
  108 #include "treenodes.h"
  109 #include "decode.h"
  110 #include "plugbase.h"
  111 #include "parser.h"
  112 #include "snort_debug.h"
  113 #include "util.h"
  114 #include "plugin_enum.h"
  115 #include "mstring.h"
  116 #include "sfhashfcn.h"
  117 #include "sp_byte_check.h"
  118 #include "sp_byte_extract.h"
  119 #include "sp_byte_math.h"
  120 
  121 #define PARSELEN 10
  122 #define TEXTLEN  (PARSELEN + 2)
  123 
  124 #include "snort.h"
  125 #include "profiler.h"
  126 #include "sfhashfcn.h"
  127 #include "detection_options.h"
  128 #include "detection_util.h"
  129 
  130 #ifdef PERF_PROFILING
  131 PreprocStats byteTestPerfStats;
  132 extern PreprocStats ruleOTNEvalPerfStats;
  133 #endif
  134 
  135 
  136 typedef struct _ByteTestOverrideData
  137 {
  138     char *keyword;
  139     char *option;
  140     union
  141     {
  142         RuleOptOverrideFunc fptr;
  143         void *void_fptr;
  144     } fptr;
  145     struct _ByteTestOverrideData *next;
  146 
  147 } ByteTestOverrideData;
  148 
  149 ByteTestOverrideData *byteTestOverrideFuncs = NULL;
  150 
  151 static void ByteTestOverride(char *keyword, char *option, RuleOptOverrideFunc roo_func);
  152 static void ByteTestOverrideFuncsFree(void);
  153 static void ByteTestInit(struct _SnortConfig *, char *, OptTreeNode *, int);
  154 static ByteTestOverrideData * ByteTestParse(char *data, ByteTestData *idx, OptTreeNode *otn);
  155 static void ByteTestOverrideCleanup(int, void *);
  156 
  157 uint32_t ByteTestHash(void *d)
  158 {
  159     uint32_t a,b,c;
  160     ByteTestData *data = (ByteTestData *)d;
  161 
  162     a = data->bytes_to_compare;
  163     b = data->cmp_value;
  164     c = data->operator;
  165 
  166     mix(a,b,c);
  167 
  168     a += data->offset;
  169     b += (data->not_flag << 24 |
  170           data->relative_flag << 16 |
  171           data->data_string_convert_flag << 8 |
  172           data->endianess);
  173     c += data->base;
  174 
  175     mix(a,b,c);
  176 
  177     a += data->bitmask_val;
  178     b += RULE_OPTION_TYPE_BYTE_TEST;
  179     c += (data->cmp_value_var << 8 |
  180           data->offset_var );
  181 
  182     mix(a,b,c);
  183 
  184 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
  185     {
  186         /* Cleanup warning because of cast from 64bit ptr to 32bit int
  187          * warning on 64bit OSs */
  188         uint64_t ptr; /* Addresses are 64bits */
  189 
  190         ptr = (uint64_t) data->byte_order_func;
  191         a += (ptr >> 32);
  192         b += (ptr & 0xFFFFFFFF);
  193     }
  194 #else
  195     a += (uint32_t)data->byte_order_func;
  196 #endif
  197 
  198     final(a,b,c);
  199 
  200     return c;
  201 }
  202 
  203 int ByteTestCompare(void *l, void *r)
  204 {
  205     ByteTestData *left = (ByteTestData *)l;
  206     ByteTestData *right = (ByteTestData *)r;
  207 
  208     if (!left || !right)
  209         return DETECTION_OPTION_NOT_EQUAL;
  210 
  211     if (( left->bytes_to_compare == right->bytes_to_compare) &&
  212         ( left->cmp_value == right->cmp_value) &&
  213         ( left->operator == right->operator) &&
  214         ( left->offset == right->offset) &&
  215         ( left->not_flag == right->not_flag) &&
  216         ( left->relative_flag == right->relative_flag) &&
  217         ( left->data_string_convert_flag == right->data_string_convert_flag) &&
  218         ( left->endianess == right->endianess) &&
  219         ( left->base == right->base) &&
  220         ( left->cmp_value_var == right->cmp_value_var) &&
  221         ( left->offset_var == right->offset_var) &&
  222         ( left->byte_order_func == right->byte_order_func) &&
  223         ( left->bitmask_val == right->bitmask_val))
  224     {
  225         return DETECTION_OPTION_EQUAL;
  226     }
  227 
  228     return DETECTION_OPTION_NOT_EQUAL;
  229 }
  230 
  231 static void ByteTestOverride(char *keyword, char *option, RuleOptOverrideFunc roo_func)
  232 {
  233     ByteTestOverrideData *new = SnortAlloc(sizeof(ByteTestOverrideData));
  234 
  235     new->keyword = SnortStrdup(keyword);
  236     new->option = SnortStrdup(option);
  237     new->func = roo_func;
  238 
  239     new->next = byteTestOverrideFuncs;
  240     byteTestOverrideFuncs = new;
  241 }
  242 
  243 static void ByteTestOverrideFuncsFree(void)
  244 {
  245     ByteTestOverrideData *node = byteTestOverrideFuncs;
  246 
  247     while (node != NULL)
  248     {
  249         ByteTestOverrideData *tmp = node;
  250 
  251         node = node->next;
  252 
  253         if (tmp->keyword != NULL)
  254             free(tmp->keyword);
  255 
  256         if (tmp->option != NULL)
  257             free(tmp->option);
  258 
  259         free(tmp);
  260     }
  261 
  262     byteTestOverrideFuncs = NULL;
  263 }
  264 
  265 /****************************************************************************
  266  * Function: SetupByteTest()
  267  *
  268  * Purpose: Register byte_test name and initialization function
  269  *
  270  * Arguments: None.
  271  *
  272  * Returns: void function
  273  *
  274  ****************************************************************************/
  275 void SetupByteTest(void)
  276 {
  277     /* map the keyword to an initialization/processing function */
  278     RegisterRuleOption("byte_test", ByteTestInit, ByteTestOverride, OPT_TYPE_DETECTION, NULL);
  279     AddFuncToCleanExitList(ByteTestOverrideCleanup, NULL);
  280     AddFuncToRuleOptParseCleanupList(ByteTestOverrideFuncsFree);
  281 
  282 #ifdef PERF_PROFILING
  283     RegisterPreprocessorProfile("byte_test", &byteTestPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
  284 #endif
  285     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: ByteTest Setup\n"););
  286 }
  287 
  288 
  289 /****************************************************************************
  290  *
  291  * Function: ByteTestInit(char *, OptTreeNode *)
  292  *
  293  * Purpose: Generic rule configuration function.  Handles parsing the rule
  294  *          information and attaching the associated detection function to
  295  *          the OTN.
  296  *
  297  * Arguments: data => rule arguments/data
  298  *            otn => pointer to the current rule option list node
  299  *            protocol => protocol the rule is on (we don't care in this case)
  300  *
  301  * Returns: void function
  302  *
  303  ****************************************************************************/
  304 static void ByteTestInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
  305 {
  306     ByteTestData *idx;
  307     OptFpList *fpl;
  308     ByteTestOverrideData *override;
  309     void *idx_dup;
  310 
  311     /* allocate the data structure and attach it to the
  312        rule's data struct list */
  313     idx = (ByteTestData *) calloc(sizeof(ByteTestData), sizeof(char));
  314 
  315     if(idx == NULL)
  316     {
  317         FatalError("%s(%d): Unable to allocate byte_test data node\n",
  318                 file_name, file_line);
  319     }
  320 
  321     /* this is where the keyword arguments are processed and placed into the
  322        rule option's data structure */
  323     override = ByteTestParse(data, idx, otn);
  324     if (override)
  325     {
  326         /* There is an override function */
  327         free(idx);
  328         override->func(sc, override->keyword, override->option, data, otn, protocol);
  329         return;
  330     }
  331 
  332     fpl = AddOptFuncToList(ByteTest, otn);
  333     fpl->type = RULE_OPTION_TYPE_BYTE_TEST;
  334 
  335     if (add_detection_option(sc, RULE_OPTION_TYPE_BYTE_TEST, (void *)idx, &idx_dup) == DETECTION_OPTION_EQUAL)
  336     {
  337 #ifdef DEBUG_RULE_OPTION_TREE
  338         LogMessage("Duplicate ByteCheck:\n%d %d %d %d %c %c %c %c %d 0x%x\n"
  339             "%d %d %d %d %c %c %c %c %d 0x%x\n\n",
  340             idx->bytes_to_compare,
  341             idx->cmp_value,
  342             idx->operator,
  343             idx->offset,
  344             idx->not_flag, idx->relative_flag,
  345             idx->data_string_convert_flag,
  346             idx->endianess, idx->base,
  347             idx->bitmask_val,
  348             ((ByteTestData *)idx_dup)->bytes_to_compare,
  349             ((ByteTestData *)idx_dup)->cmp_value,
  350             ((ByteTestData *)idx_dup)->operator,
  351             ((ByteTestData *)idx_dup)->offset,
  352             ((ByteTestData *)idx_dup)->not_flag, ((ByteTestData *)idx_dup)->relative_flag,
  353             ((ByteTestData *)idx_dup)->data_string_convert_flag,
  354             ((ByteTestData *)idx_dup)->endianess, ((ByteTestData *)idx_dup)->base,
  355             ((ByteTestData *)idx_dup)->bitmask_val);
  356 #endif
  357         free(idx);
  358         idx = idx_dup;
  359     }
  360 
  361     /* attach it to the context node so that we can call each instance
  362      * individually
  363      */
  364     fpl->context = (void *) idx;
  365 
  366     if (idx->relative_flag == 1)
  367         fpl->isRelative = 1;
  368 }
  369 
  370 /****************************************************************************
  371  *
  372  * Function: ByteTestParse(char *, ByteTestData *, OptTreeNode *)
  373  *
  374  * Purpose: This is the function that is used to process the option keyword's
  375  *          arguments and attach them to the rule's data structures.
  376  *
  377  * Arguments: data => argument data
  378  *            idx => pointer to the processed argument storage
  379  *            otn => pointer to the current rule's OTN
  380  *
  381  * Returns: void function
  382  *
  383  ****************************************************************************/
  384 static ByteTestOverrideData * ByteTestParse(char *data, ByteTestData *idx, OptTreeNode *otn)
  385 {
  386     char **toks;
  387     char *endp;
  388     int num_toks;
  389     char *cptr;
  390     int i =0;
  391     RuleOptByteOrderFunc tmp_byte_order_func;
  392 
  393     toks = mSplit(data, ",", 13, &num_toks, 0);
  394 
  395     if(num_toks < 4)
  396         ParseError(" Bad arguments to byte_test: %s\n",data);
  397 
  398     /* set how many bytes to process from the packet */
  399     idx->bytes_to_compare = strtol(toks[0], &endp, 10);
  400 
  401     if(toks[0] == endp)
  402     {
  403         ParseError(" Unable to parse as byte value %s\n",toks[0]);
  404     }
  405 
  406     if(*endp != '\0')
  407     {
  408         ParseError("byte_test option has bad value: %s.", toks[0]);
  409     }
  410 
  411     if(idx->bytes_to_compare > PARSELEN || idx->bytes_to_compare == 0)
  412     {
  413         ParseError(" byte_test can't process more than "
  414                 "10 bytes!\n");
  415     }
  416 
  417     cptr = toks[1];
  418 
  419     while(isspace((int)*cptr)) {cptr++;}
  420 
  421     if(*cptr == '!')
  422     {
  423         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  424                     "enabling not flag\n"););
  425        idx->not_flag = 1;
  426        cptr++;
  427     }
  428 
  429     if (idx->not_flag && strlen(cptr) == 0)
  430     {
  431         idx->operator = BT_EQUALS;
  432     }
  433     else
  434     {
  435         /* set the operator */
  436         switch(*cptr)
  437         {
  438             case '<': idx->operator = BT_LESS_THAN;
  439                       cptr++;
  440                       if (*cptr == '=')
  441                           idx->operator = BT_LESS_THAN_EQUAL;
  442                       else
  443                           cptr--;
  444                       break;
  445 
  446             case '=': idx->operator = BT_EQUALS;
  447                       break;
  448 
  449             case '>': idx->operator = BT_GREATER_THAN;
  450                       cptr++;
  451                       if (*cptr == '=')
  452                           idx->operator = BT_GREATER_THAN_EQUAL;
  453                       else
  454                           cptr--;
  455                       break;
  456 
  457             case '&': idx->operator = BT_AND;
  458                       break;
  459 
  460             case '^': idx->operator = BT_XOR;
  461                       break;
  462 
  463             default: ParseError(" byte_test unknown "
  464                              "operator ('%c, %s')\n",
  465                              *cptr, toks[1]);
  466         }
  467     }
  468 
  469 
  470     /* set the value to test against */
  471     if (isdigit(toks[2][0]) || toks[2][0] == '-')
  472     {
  473         int64_t rval = SnortStrtoul(toks[2], &endp,0);
  474         if (rval > MAX_RVAL)
  475         {
  476             ParseError("byte_test rule option has invalid rvalue."
  477                  "Valid rvalue range %u-%u.",
  478                   MIN_RVAL-1,MAX_RVAL);
  479         }
  480         idx->cmp_value=rval;
  481         idx->cmp_value_var = -1;
  482 
  483         if(toks[2] == endp)
  484         {
  485             ParseError(" Unable to parse as comparison value %s\n",
  486                        toks[2]);
  487         }
  488 
  489         if(*endp != '\0')
  490         {
  491             ParseError("byte_test option has bad comparison value: %s.", toks[2]);
  492         }
  493 
  494         if(errno == ERANGE)
  495         {
  496             ParseError("Bad range: %s\n", toks[2]);
  497         }
  498     }
  499     else
  500     {
  501         idx->cmp_value_var = find_value(toks[2]);
  502         if ( idx->cmp_value_var == BYTE_EXTRACT_NO_VAR)
  503         {
  504             ParseError(BYTE_TEST_INVALID_ERR_FMT, "byte_test : value", toks[2]);
  505         }
  506     }
  507 
  508     if (isdigit(toks[3][0]) || toks[3][0] == '-')
  509     {
  510         /* set offset */
  511         idx->offset = strtol(toks[3], &endp, 10);
  512         idx->offset_var = -1;
  513 
  514         if(toks[3] == endp)
  515         {
  516             ParseError(" Unable to parse as offset value %s\n",
  517                         toks[3]);
  518         }
  519 
  520         if(*endp != '\0')
  521         {
  522             ParseError("byte_test option has bad offset: %s.", toks[3]);
  523         }
  524     }
  525     else
  526     {
  527         idx->offset_var = find_value(toks[3]);
  528         if ( idx->offset_var == BYTE_EXTRACT_NO_VAR)
  529         {
  530             ParseError(BYTE_TEST_INVALID_ERR_FMT, "byte_test : offset", toks[3]);
  531         }
  532     }
  533 
  534 
  535     i = 4;
  536 
  537     /* is it a relative offset? */
  538     if(num_toks > 4)
  539     {
  540         while(i < num_toks)
  541         {
  542             cptr = toks[i];
  543 
  544             while(isspace((int)*cptr)) {cptr++;}
  545 
  546             if(!strcasecmp(cptr, "relative"))
  547             {
  548                 /* the offset is relative to the last pattern match */
  549                 idx->relative_flag = 1;
  550             }
  551             else if(!strcasecmp(cptr, "string"))
  552             {
  553                 /* the data will be represented as a string that needs
  554                  * to be converted to an int, binary is assumed otherwise
  555                  */
  556                 idx->data_string_convert_flag = 1;
  557             }
  558             else if(!strcasecmp(cptr, "little"))
  559             {
  560                 idx->endianess = LITTLE;
  561             }
  562             else if(!strcasecmp(cptr, "big"))
  563             {
  564                 /* this is the default */
  565                 idx->endianess = BIG;
  566             }
  567             else if(!strcasecmp(cptr, "hex"))
  568             {
  569                 idx->base = 16;
  570             }
  571             else if(!strcasecmp(cptr, "dec"))
  572             {
  573                 idx->base = 10;
  574             }
  575             else if(!strcasecmp(cptr, "oct"))
  576             {
  577                 idx->base = 8;
  578             }
  579             else if((tmp_byte_order_func = GetByteOrderFunc(cptr)) != NULL)
  580             {
  581                 idx->byte_order_func = tmp_byte_order_func;
  582             }
  583             else if(strncasecmp(cptr,"bitmask ",8) == 0)
  584             {
  585                 RuleOptionBitmaskParse(&(idx->bitmask_val), cptr, idx->bytes_to_compare, "BYTE_TEST");
  586             }
  587             else
  588             {
  589                 ByteTestOverrideData *override = byteTestOverrideFuncs;
  590 
  591                 while (override != NULL)
  592                 {
  593                     if (!strcasecmp(cptr, override->option))
  594                     {
  595                         mSplitFree(&toks, num_toks);
  596                         return override;
  597                     }
  598 
  599                     override = override->next;
  600                 }
  601 
  602                 ParseError("unknown modifier \"%s\"\n",cptr);
  603             }
  604 
  605             i++;
  606         }
  607     }
  608 
  609     if (idx->bytes_to_compare > MAX_BYTES_TO_GRAB && !idx->data_string_convert_flag)
  610     {
  611         ParseError("byte_test rule option cannot extract more than %d bytes without valid string prefix.",
  612                      MAX_BYTES_TO_GRAB);
  613     }
  614     /* idx->base is only set if the parameter is specified */
  615     if(!idx->data_string_convert_flag && idx->base)
  616     {
  617         ParseError("hex, dec and oct modifiers must be used in conjunction \n"
  618                    "        with the 'string' modifier\n");
  619     }
  620     if (idx->offset < MIN_BYTE_EXTRACT_OFFSET || idx->offset > MAX_BYTE_EXTRACT_OFFSET)
  621     {
  622         ParseError("byte_test rule option has invalid offset. "
  623               "Valid offsets are between %d and %d.",
  624                MIN_BYTE_EXTRACT_OFFSET, MAX_BYTE_EXTRACT_OFFSET);
  625     }
  626     mSplitFree(&toks, num_toks);
  627     return NULL;
  628 }
  629 
  630 
  631 /****************************************************************************
  632  *
  633  * Function: ByteTest(char *, OptTreeNode *, OptFpList *)
  634  *
  635  * Purpose: Use this function to perform the particular detection routine
  636  *          that this rule keyword is supposed to encompass.
  637  *
  638  * Arguments: p => pointer to the decoded packet
  639  *            otn => pointer to the current rule's OTN
  640  *            fp_list => pointer to the function pointer list
  641  *
  642  * Returns: If the detection test fails, this function *must* return a zero!
  643  *          On success, it calls the next function in the detection list
  644  *
  645  ****************************************************************************/
  646 int ByteTest(void *option_data, Packet *p)
  647 {
  648     ByteTestData *btd = (ByteTestData *)option_data;
  649     int rval = DETECTION_OPTION_NO_MATCH;
  650     uint32_t value = 0;
  651     int success = 0;
  652     int dsize;
  653     const char *base_ptr, *end_ptr, *start_ptr;
  654     int payload_bytes_grabbed;
  655     int32_t offset;
  656     uint32_t extract_offset, extract_cmp_value;
  657     int search_start = 0;
  658     PROFILE_VARS;
  659 
  660     PREPROC_PROFILE_START(byteTestPerfStats);
  661 
  662     if (Is_DetectFlag(FLAG_ALT_DETECT))
  663     {
  664         dsize = DetectBuffer.len;
  665         start_ptr = (const char*)DetectBuffer.data;
  666         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  667                 "Using Alternative Detect buffer!\n"););
  668     }
  669     else if(Is_DetectFlag(FLAG_ALT_DECODE))
  670     {
  671         dsize = DecodeBuffer.len;
  672         start_ptr = (char *)DecodeBuffer.data;
  673         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  674                     "Using Alternative Decode buffer!\n"););
  675     }
  676     else
  677     {
  678         if(IsLimitedDetect(p))
  679             dsize = p->alt_dsize;
  680         else
  681             dsize = p->dsize;
  682         start_ptr = (char *) p->data;
  683     }
  684 
  685     base_ptr = start_ptr;
  686     end_ptr = start_ptr + dsize;
  687 
  688     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  689                 "[*] byte test firing...\npayload starts at %p\n", start_ptr););
  690 
  691 
  692     /* Get values from byte_extract variables, if present. */
  693     if (btd->cmp_value_var >= 0 )
  694     {
  695 
  696         if(btd->cmp_value_var == BYTE_MATH_VAR_INDEX )
  697         {
  698             btd->cmp_value = (int32_t) bytemath_variable;
  699         }
  700         else if(btd->cmp_value_var == COMMON_VAR_INDEX )
  701         {
  702             btd->cmp_value = (int32_t) common_var;
  703         }
  704         else if (btd->cmp_value_var < NUM_BYTE_EXTRACT_VARS)
  705         {
  706             GetByteExtractValue(&extract_cmp_value, btd->cmp_value_var);
  707             btd->cmp_value = (int32_t) extract_cmp_value;
  708         }
  709 
  710     }
  711     if (btd->offset_var >= 0 )
  712     {
  713         if(btd->offset_var == BYTE_MATH_VAR_INDEX )
  714         {
  715             btd->offset = (int32_t) bytemath_variable;
  716         }
  717         else if(btd->offset_var == COMMON_VAR_INDEX )
  718         {
  719             btd->offset = (int32_t) common_var;
  720         }
  721         else if (btd->offset_var < NUM_BYTE_EXTRACT_VARS)
  722         {
  723             GetByteExtractValue(&extract_offset, btd->offset_var);
  724             btd->offset = (int32_t) extract_offset;
  725         }
  726 
  727     }
  728 
  729 
  730     if(btd->relative_flag && doe_ptr)
  731     {
  732         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  733                                 "Checking relative offset!\n"););
  734 
  735         /* @todo: possibly degrade to use the other buffer, seems non-intuitive
  736          *  Because doe_ptr can be "end" in the last match,
  737          *  use end + 1 for upper bound
  738          *  Bound checked also after offset is applied
  739          *  (see byte_extract() and string_extract())
  740          */
  741         if(!inBounds((const uint8_t *)start_ptr, (const uint8_t *)end_ptr + 1, doe_ptr))
  742         {
  743             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  744                                     "[*] byte test bounds check failed..\n"););
  745             PREPROC_PROFILE_END(byteTestPerfStats);
  746             return rval;
  747         }
  748 
  749         search_start = (doe_ptr - (const uint8_t *)start_ptr) + btd->offset;
  750         base_ptr = (const char *)doe_ptr;
  751     }
  752     else
  753     {
  754         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  755                                 "checking absolute offset %d\n", btd->offset););
  756         search_start = btd->offset;
  757         base_ptr = start_ptr;
  758     }
  759 
  760     if( search_start < 0 )
  761     {
  762         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  763                                 "[*] byte test bounds check failed..\n"););
  764         PREPROC_PROFILE_END(byteTestPerfStats);
  765         return rval;
  766     }
  767 
  768     base_ptr = base_ptr + btd->offset;
  769 
  770     /* Use byte_order_func to determine endianess, if present */
  771     if (btd->byte_order_func)
  772     {
  773         offset = (int32_t) ((const uint8_t *)base_ptr - p->data);
  774         btd->endianess = btd->byte_order_func(p, offset);
  775         if (btd->endianess == -1)
  776         {
  777             PREPROC_PROFILE_END(byteTestPerfStats);
  778             return DETECTION_OPTION_NO_MATCH;
  779         }
  780     }
  781 
  782     /* both of these functions below perform their own bounds checking within
  783      * byte_extract.c
  784      */
  785 
  786     if(!btd->data_string_convert_flag)
  787     {
  788         if(byte_extract(btd->endianess, btd->bytes_to_compare,
  789                         (const uint8_t *)base_ptr, (const uint8_t *)start_ptr, (const uint8_t *)end_ptr, &value))
  790         {
  791             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  792                                     "Byte Extraction Failed\n"););
  793 
  794             PREPROC_PROFILE_END(byteTestPerfStats);
  795             return rval;
  796         }
  797         payload_bytes_grabbed = (int)btd->bytes_to_compare;
  798     }
  799     else
  800     {
  801         payload_bytes_grabbed = string_extract(
  802                 btd->bytes_to_compare, btd->base,
  803                 (const uint8_t *)base_ptr, (const uint8_t *)start_ptr,
  804                 (const uint8_t *)end_ptr, &value);
  805 
  806         if ( payload_bytes_grabbed < 0 )
  807         {
  808             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  809                                     "String Extraction Failed\n"););
  810 
  811             PREPROC_PROFILE_END(byteTestPerfStats);
  812             return rval;
  813         }
  814 
  815     }
  816 
  817     if(btd->bitmask_val != 0 )
  818     {
  819         int num_tailing_zeros_bitmask = getNumberTailingZerosInBitmask(btd->bitmask_val);
  820         value = value & btd->bitmask_val ;
  821         if ( value && num_tailing_zeros_bitmask )
  822         {
  823             value = value >> num_tailing_zeros_bitmask;
  824         }
  825     }
  826 
  827     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  828         "Grabbed %d bytes at offset %d cmp_value = 0x%08X(%u) value = 0x%08X(%u)\n",
  829         payload_bytes_grabbed, btd->offset, btd->cmp_value,btd->cmp_value,value, value); );
  830 
  831     switch(btd->operator)
  832     {
  833         case BT_LESS_THAN: if(value < btd->cmp_value)
  834                                success = 1;
  835                            break;
  836 
  837         case BT_EQUALS: if(value == btd->cmp_value)
  838                             success = 1;
  839                         break;
  840 
  841         case BT_GREATER_THAN: if(value > btd->cmp_value)
  842                                   success = 1;
  843                               break;
  844 
  845         case BT_AND: if ((value & btd->cmp_value) > 0)
  846                          success = 1;
  847                      break;
  848 
  849         case BT_XOR: if ((value ^ btd->cmp_value) > 0)
  850                         success = 1;
  851                     break;
  852 
  853         case BT_GREATER_THAN_EQUAL: if (value >= btd->cmp_value)
  854                                         success = 1;
  855                                     break;
  856 
  857         case BT_LESS_THAN_EQUAL: if (value <= btd->cmp_value)
  858                                         success = 1;
  859                                  break;
  860 
  861         case BT_CHECK_ALL: if ((value & btd->cmp_value) == btd->cmp_value)
  862                                success = 1;
  863                            break;
  864 
  865         case BT_CHECK_ATLEASTONE: if ((value & btd->cmp_value) != 0)
  866                                       success = 1;
  867                                   break;
  868 
  869         case BT_CHECK_NONE: if ((value & btd->cmp_value) == 0)
  870                                 success = 1;
  871                             break;
  872     }
  873 
  874     if (btd->not_flag)
  875     {
  876         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  877                     "checking for not success...flag\n"););
  878         if (!success)
  879         {
  880             rval = DETECTION_OPTION_MATCH;
  881         }
  882     }
  883     else if (success)
  884     {
  885         rval = DETECTION_OPTION_MATCH;
  886     }
  887 
  888     /* if the test isn't successful, this function *must* return 0 */
  889     PREPROC_PROFILE_END(byteTestPerfStats);
  890     return rval;
  891 }
  892 
  893 static void ByteTestOverrideCleanup(int signal, void *data)
  894 {
  895     if (byteTestOverrideFuncs != NULL)
  896         ByteTestOverrideFuncsFree();
  897 }
  898