"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/detection-plugins/sp_isdataat.c" (16 Oct 2020, 12628 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_isdataat.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) 1998-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 /* sp_isdataat
   23  *
   24  * Purpose:
   25  *    Test a specific byte to see if there is data.  (Basicly, rule keyword
   26  *    into inBounds)
   27  *
   28  * Arguments:
   29  *    <int>         byte location to check if there is data
   30  *    ["relative"]  look for byte location relative to the end of the last
   31  *                  pattern match
   32  *    ["rawbytes"]  force use of the non-normalized buffer.
   33  *
   34  * Sample:
   35  *   alert tcp any any -> any 110 (msg:"POP3 user overflow"; \
   36  *      content:"USER"; isdataat:30,relative; content:!"|0a|"; within:30;)
   37  */
   38 
   39 #ifdef HAVE_CONFIG_H
   40 #include "config.h"
   41 #endif
   42 
   43 #include <sys/types.h>
   44 #include <stdlib.h>
   45 #include <ctype.h>
   46 #ifdef HAVE_STRINGS_H
   47 #include <strings.h>
   48 #endif
   49 #include <errno.h>
   50 
   51 #include "sf_types.h"
   52 #include "snort_bounds.h"
   53 #include "rules.h"
   54 #include "treenodes.h"
   55 #include "decode.h"
   56 #include "plugbase.h"
   57 #include "parser.h"
   58 #include "snort_debug.h"
   59 #include "util.h"
   60 #include "mstring.h"
   61 
   62 #include "snort.h"
   63 #include "profiler.h"
   64 #include "sp_isdataat.h"
   65 #include "sp_byte_extract.h"
   66 #include "sp_byte_math.h"
   67 #ifdef PERF_PROFILING
   68 PreprocStats isDataAtPerfStats;
   69 extern PreprocStats ruleOTNEvalPerfStats;
   70 #endif
   71 
   72 #include "sfhashfcn.h"
   73 #include "detection_options.h"
   74 #include "detection_util.h"
   75 
   76 extern char *file_name;  /* this is the file name from rules.c, generally used
   77                             for error messages */
   78 
   79 extern int file_line;    /* this is the file line number from rules.c that is
   80                             used to indicate file lines for error messages */
   81 
   82 void IsDataAtInit(struct _SnortConfig *, char *, OptTreeNode *, int);
   83 void IsDataAtParse(char *, IsDataAtData *, OptTreeNode *);
   84 int  IsDataAt(void *option_data, Packet *p);
   85 
   86 uint32_t IsDataAtHash(void *d)
   87 {
   88     uint32_t a,b,c;
   89     IsDataAtData *data = (IsDataAtData *)d;
   90 
   91     a = data->offset;
   92     b = data->flags;
   93     c = RULE_OPTION_TYPE_IS_DATA_AT;
   94 
   95     mix(a,b,c);
   96 
   97     a += data->offset_var;
   98 
   99     final(a,b,c);
  100 
  101     return c;
  102 }
  103 
  104 int IsDataAtCompare(void *l, void *r)
  105 {
  106     IsDataAtData *left = (IsDataAtData *)l;
  107     IsDataAtData *right = (IsDataAtData *)r;
  108 
  109     if (!left || !right)
  110         return DETECTION_OPTION_NOT_EQUAL;
  111 
  112     if (( left->offset == right->offset) &&
  113         ( left->flags == right->flags) &&
  114         ( left->offset_var == right->offset_var) )
  115     {
  116         return DETECTION_OPTION_EQUAL;
  117     }
  118 
  119     return DETECTION_OPTION_NOT_EQUAL;
  120 }
  121 
  122 /****************************************************************************
  123  *
  124  * Function: SetupIsDataAt()
  125  *
  126  * Purpose: Load 'er up
  127  *
  128  * Arguments: None.
  129  *
  130  * Returns: void function
  131  *
  132  ****************************************************************************/
  133 void SetupIsDataAt(void)
  134 {
  135     /* map the keyword to an initialization/processing function */
  136     RegisterRuleOption("isdataat", IsDataAtInit, NULL, OPT_TYPE_DETECTION, NULL);
  137 #ifdef PERF_PROFILING
  138     RegisterPreprocessorProfile("isdataat", &isDataAtPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
  139 #endif
  140 
  141     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: IsDataAt Setup\n"););
  142 }
  143 
  144 
  145 /****************************************************************************
  146  *
  147  * Function: IsDataAt(struct _SnortConfig *, char *, OptTreeNode *, int protocol)
  148  *
  149  * Purpose: Generic rule configuration function.  Handles parsing the rule
  150  *          information and attaching the associated detection function to
  151  *          the OTN.
  152  *
  153  * Arguments: data => rule arguments/data
  154  *            otn => pointer to the current rule option list node
  155  *            protocol => protocol the rule is on (we don't care in this case)
  156  *
  157  * Returns: void function
  158  *
  159  ****************************************************************************/
  160 void IsDataAtInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
  161 {
  162     IsDataAtData *idx;
  163     OptFpList *fpl;
  164     void *idx_dup;
  165 
  166     /* allocate the data structure and attach it to the
  167        rule's data struct list */
  168     idx = (IsDataAtData *) SnortAlloc(sizeof(IsDataAtData));
  169 
  170     if(idx == NULL)
  171     {
  172         FatalError("%s(%d): Unable to allocate IsDataAt data node\n",
  173                 file_name, file_line);
  174     }
  175 
  176     /* this is where the keyword arguments are processed and placed into the
  177        rule option's data structure */
  178     IsDataAtParse(data, idx, otn);
  179 
  180     if (add_detection_option(sc, RULE_OPTION_TYPE_IS_DATA_AT, (void *)idx, &idx_dup) == DETECTION_OPTION_EQUAL)
  181     {
  182         free(idx);
  183         idx = idx_dup;
  184      }
  185 
  186     fpl = AddOptFuncToList(IsDataAt, otn);
  187     fpl->type = RULE_OPTION_TYPE_IS_DATA_AT;
  188 
  189     /* attach it to the context node so that we can call each instance
  190      * individually
  191      */
  192     fpl->context = (void *) idx;
  193 
  194     if (idx->flags & ISDATAAT_RELATIVE_FLAG)
  195         fpl->isRelative = 1;
  196 }
  197 
  198 
  199 
  200 /****************************************************************************
  201  *
  202  * Function: IsDataAt(char *, IsDataAtData *, OptTreeNode *)
  203  *
  204  * Purpose: This is the function that is used to process the option keyword's
  205  *          arguments and attach them to the rule's data structures.
  206  *
  207  * Arguments: data => argument data
  208  *            idx => pointer to the processed argument storage
  209  *            otn => pointer to the current rule's OTN
  210  *
  211  * Returns: void function
  212  *
  213  ****************************************************************************/
  214 void IsDataAtParse(char *data, IsDataAtData *idx, OptTreeNode *otn)
  215 {
  216     char **toks;
  217     int num_toks;
  218     int i;
  219     char *cptr;
  220     char *endp;
  221     char *offset;
  222     if(!data)
  223     {
  224         FatalError("%s (%d): Bad arguments to IsDataAt: (null)\n", file_name,file_line);
  225     }
  226 
  227     toks = mSplit(data, ",", ISDATAAT_MAX_ARG, &num_toks, 0);
  228     if(num_toks > ISDATAAT_MAX_ARG || num_toks < 1)
  229     {
  230         FatalError("%s (%d): Bad arguments to IsDataAt: %s\n", file_name,
  231                 file_line, data);
  232     }
  233     offset = toks[0];
  234     if(*offset == '!')
  235     {
  236         idx->flags |= ISDATAAT_NOT_FLAG;
  237         offset++;
  238         while(isspace((int)*offset)) {offset++;}
  239     }
  240 
  241     /* set how many bytes to process from the packet */
  242     if (isdigit(offset[0]) || offset[0] == '-')
  243     {
  244         idx->offset = strtol(offset, &endp, 10);
  245         idx->offset_var = -1;
  246 
  247         if(offset == endp)
  248         {
  249             FatalError("%s(%d): Unable to parse as byte value %s\n",
  250                        file_name, file_line, toks[0]);
  251         }
  252 
  253         if(idx->offset > 65535)
  254         {
  255             FatalError("%s(%d): IsDataAt offset greater than max IPV4 packet size",
  256                     file_name, file_line);
  257         }
  258     }
  259     else
  260     {
  261         idx->offset_var = find_value(offset);
  262         if (idx->offset_var == BYTE_EXTRACT_NO_VAR)
  263         {
  264             ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "isdataat", toks[0]);
  265         }
  266     }
  267 
  268     for (i=1; i< num_toks; i++)
  269     {
  270         cptr = toks[i];
  271 
  272         while(isspace((int)*cptr)) {cptr++;}
  273 
  274         if(!strcasecmp(cptr, "relative"))
  275         {
  276             /* the offset is relative to the last pattern match */
  277             idx->flags |= ISDATAAT_RELATIVE_FLAG;
  278         }
  279         else if(!strcasecmp(cptr, "rawbytes"))
  280         {
  281             /* the offset is to be applied to the non-normalized buffer */
  282             idx->flags |= ISDATAAT_RAWBYTES_FLAG;
  283         }
  284         else
  285         {
  286             FatalError("%s(%d): unknown modifier \"%s\"\n",
  287                     file_name, file_line, toks[1]);
  288         }
  289     }
  290 
  291     mSplitFree(&toks,num_toks);
  292 }
  293 
  294 
  295 /****************************************************************************
  296  *
  297  * Function: IsDataAt(char *, OptTreeNode *, OptFpList *)
  298  *
  299  * Purpose: Use this function to perform the particular detection routine
  300  *          that this rule keyword is supposed to encompass.
  301  *
  302  * Arguments: p => pointer to the decoded packet
  303  *            otn => pointer to the current rule's OTN
  304  *            fp_list => pointer to the function pointer list
  305  *
  306  * Returns: If the detection test fails, this function *must* return a zero!
  307  *          On success, it calls the next function in the detection list
  308  *
  309  ****************************************************************************/
  310 int IsDataAt(void *option_data, Packet *p)
  311 {
  312     IsDataAtData *isdata = (IsDataAtData *)option_data;
  313     int rval = DETECTION_OPTION_NO_MATCH;
  314     int dsize;
  315     const uint8_t *base_ptr, *end_ptr, *start_ptr;
  316     int search_start = 0;
  317     PROFILE_VARS;
  318 
  319     PREPROC_PROFILE_START(isDataAtPerfStats);
  320 
  321     if (!isdata)
  322     {
  323         PREPROC_PROFILE_END(isDataAtPerfStats);
  324         return rval;
  325     }
  326 
  327     /* Get values from byte_math/byte_extract variables, if present. */
  328     if (isdata->offset_var >= 0 )
  329     {
  330         if(isdata->offset_var == BYTE_MATH_VAR_INDEX )
  331         {
  332             isdata->offset = (int32_t) bytemath_variable;
  333         }
  334         else if(isdata->offset_var == COMMON_VAR_INDEX )
  335         {
  336             isdata->offset = (int32_t) common_var;
  337         }
  338         else if (isdata->offset_var < NUM_BYTE_EXTRACT_VARS)
  339         { 
  340             GetByteExtractValue(&(isdata->offset), isdata->offset_var);
  341         }
  342     }
  343 
  344 
  345     if (isdata->flags & ISDATAAT_RAWBYTES_FLAG)
  346     {
  347         /* Rawbytes specified, force use of that buffer */
  348         dsize = p->dsize;
  349         start_ptr = p->data;
  350         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  351                     "Using RAWBYTES buffer!\n"););
  352     }
  353     else if (Is_DetectFlag(FLAG_ALT_DETECT))
  354     {
  355         dsize = DetectBuffer.len;
  356         start_ptr = DetectBuffer.data;
  357         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  358                 "Using Alternative Detect buffer!\n"););
  359     }
  360     else if(Is_DetectFlag(FLAG_ALT_DECODE))
  361     {
  362         /* If normalized buffer available, use it... */
  363         dsize = DecodeBuffer.len;
  364         start_ptr = DecodeBuffer.data;
  365         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  366                     "Using Alternative Decode buffer!\n"););
  367     }
  368     else
  369     {
  370         if(IsLimitedDetect(p))
  371             dsize = p->alt_dsize;
  372         else
  373             dsize = p->dsize;
  374         start_ptr = p->data;
  375     }
  376 
  377     base_ptr = start_ptr;
  378     end_ptr = start_ptr + dsize;
  379 
  380     if((isdata->flags & ISDATAAT_RELATIVE_FLAG) && doe_ptr)
  381     {
  382         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  383                                 "Checking relative offset!\n"););
  384 
  385        /*  Because doe_ptr can be "end" in the last match,
  386         *  use end + 1 for upper bound
  387         *  Bound checked also after offset is applied
  388         *
  389         */
  390         if(!inBounds(start_ptr, end_ptr + 1, doe_ptr))
  391         {
  392             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  393                                     "[*] isdataat bounds check failed..\n"););
  394             PREPROC_PROFILE_END(isDataAtPerfStats);
  395             return rval;
  396         }
  397 
  398         search_start = ( doe_ptr - start_ptr ) + isdata->offset;
  399         base_ptr = doe_ptr;
  400     }
  401     else
  402     {
  403         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  404                                 "checking absolute offset %d\n", isdata->offset););
  405         search_start = isdata->offset;
  406         base_ptr = start_ptr;
  407     }
  408 
  409     if ( search_start < 0 )
  410     {
  411         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  412                                 "[*] isdataat bounds check failed..\n"););
  413         PREPROC_PROFILE_END(isDataAtPerfStats);
  414         return rval;
  415     }
  416 
  417     base_ptr = base_ptr + isdata->offset;
  418 
  419     if(inBounds(start_ptr, end_ptr, base_ptr))
  420     {
  421         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  422                     "[*] IsDataAt succeeded!  there is data...\n"););
  423         rval = DETECTION_OPTION_MATCH;
  424     }
  425 
  426     if (isdata->flags & ISDATAAT_NOT_FLAG)
  427     {
  428         rval = !rval;
  429     }
  430 
  431 
  432     /* otherwise dump */
  433     PREPROC_PROFILE_END(isDataAtPerfStats);
  434     return rval;
  435 }