Hello, The following patch adds support for unlimited rule size and unlimited `content' option size (was limited to 2Kb). Please disregard the previous patch I've sent.
-- /Dmitry <[EMAIL PROTECTED]>
Index: detection-plugins/sp_pattern_match.c =================================================================== --- detection-plugins/sp_pattern_match.c (revision 13692) +++ detection-plugins/sp_pattern_match.c (revision 13697) @@ -1264,16 +1264,15 @@ ***************************************************************************/ static void ParsePattern(char *rule, OptTreeNode * otn, int type) { - unsigned char tmp_buf[2048]; + unsigned char *pattern; /* got enough ptrs for you? */ char *start_ptr; char *end_ptr; char *idx; - char *dummy_idx; - char *dummy_end; + char *pat_end; char hex_buf[3]; - u_int dummy_size = 0; + u_int pat_size = 0; int size; int hexmode = 0; int hexsize = 0; @@ -1283,9 +1282,6 @@ int exception_flag = 0; PatternMatchData *ds_idx; - /* clear out the temp buffer */ - bzero(tmp_buf, 2048); - if(rule == NULL) { FatalError("%s(%d) => ParsePattern Got Null " @@ -1338,9 +1334,17 @@ /* set all the pointers to the appropriate places... */ idx = start_ptr; + /* allocate memory for the resulting pattern */ + pattern = malloc((size+1) * sizeof(char)); + if(pattern == NULL) + { + FatalError("%s(%d) => could not allocate %d bytes of memory for " + "pattern\n", file_name, file_line, size * sizeof(char)); + } + pattern[size] = 0; + /* set the indexes into the temp buffer */ - dummy_idx = tmp_buf; - dummy_end = (dummy_idx + size); + pat_end = (pat_end + size); /* why is this buffer so small? */ bzero(hex_buf, 3); @@ -1388,8 +1392,8 @@ { DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "literal set, Clearing\n");); literal = 0; - tmp_buf[dummy_size] = start_ptr[cnt]; - dummy_size++; + pattern[pat_size] = start_ptr[cnt]; + pat_size++; } break; @@ -1406,9 +1410,9 @@ else { DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Clearing literal\n");); - tmp_buf[dummy_size] = start_ptr[cnt]; + pattern[pat_size] = start_ptr[cnt]; literal = 0; - dummy_size++; + pat_size++; } break; @@ -1435,21 +1439,12 @@ hex_buf[1] = *idx; pending--; - if(dummy_idx < dummy_end) - { - tmp_buf[dummy_size] = (u_char) - strtol(hex_buf, (char **) NULL, 16)&0xFF; + pattern[pat_size] = (u_char) + strtol(hex_buf, (char **) NULL, 16)&0xFF; - dummy_size++; - bzero(hex_buf, 3); - memset(hex_buf, '0', 2); - } - else - { - FatalError("ParsePattern() dummy " - "buffer overflow, make a smaller " - "pattern please! (Max size = 2048)\n"); - } + pat_size++; + bzero(hex_buf, 3); + memset(hex_buf, '0', 2); } } else @@ -1469,16 +1464,8 @@ { if(*idx >= 0x1F && *idx <= 0x7e) { - if(dummy_idx < dummy_end) - { - tmp_buf[dummy_size] = start_ptr[cnt]; - dummy_size++; - } - else - { - FatalError("%s(%d)=> ParsePattern() " - "dummy buffer overflow!\n", file_name, file_line); - } + pattern[pat_size] = start_ptr[cnt]; + pat_size++; if(literal) { @@ -1489,8 +1476,8 @@ { if(literal) { - tmp_buf[dummy_size] = start_ptr[cnt]; - dummy_size++; + pattern[pat_size] = start_ptr[cnt]; + pat_size++; DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Clearing literal\n");); literal = 0; } @@ -1506,7 +1493,6 @@ break; } - dummy_idx++; idx++; cnt++; } @@ -1528,15 +1514,22 @@ while(ds_idx->next != NULL) ds_idx = ds_idx->next; - if((ds_idx->pattern_buf = (char *) calloc(dummy_size+1, sizeof(char))) - == NULL) + if(size == pat_size) { - FatalError("ParsePattern() pattern_buf malloc failed!\n"); + ds_idx->pattern_buf = pattern; } + else + { + if((ds_idx->pattern_buf = (char *) malloc((pat_size+1) * sizeof(char))) + == NULL) + { + FatalError("ParsePattern() pattern_buf malloc failed!\n"); + } + memcpy(ds_idx->pattern_buf, pattern, pat_size+1); + free(pattern); + } - memcpy(ds_idx->pattern_buf, tmp_buf, dummy_size); - - ds_idx->pattern_size = dummy_size; + ds_idx->pattern_size = pat_size; ds_idx->search = uniSearch; make_precomp(ds_idx); Index: parser.c =================================================================== --- parser.c (revision 13692) +++ parser.c (revision 13697) @@ -137,13 +137,9 @@ void ParseRulesFile(char *file, int inclevel) { FILE *thefp; /* file pointer for the rules file */ - char buf[STD_BUF]; /* file read buffer */ - char *index; /* buffer indexing pointer */ char *stored_file_name = file_name; int stored_file_line = file_line; - char *saved_line = NULL; - int continuation = 0; - char *new_line = NULL; + char *line; struct stat file_stat; /* for include path testing */ if(inclevel == 0) @@ -208,83 +204,14 @@ file_name); } - /* clear the line buffer */ - bzero((char *) buf, STD_BUF); - - /* loop thru each file line and send it to the rule parser */ - while((fgets(buf, STD_BUF, thefp)) != NULL) + while((line = ReadLine(thefp)) != NULL) { - /* - * inc the line counter so the error messages know which line to - * bitch about - */ - file_line++; + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, + "[*] Processing rule: %s\n", line);); - index = buf; - -#ifdef DEBUG2 - LogMessage("Got line %s (%d): %s\n", file_name, file_line, buf); -#endif - /* advance through any whitespace at the beginning of the line */ - while(*index == ' ' || *index == '\t') - index++; - - /* if it's not a comment or a <CR>, send it to the parser */ - if((*index != '#') && (*index != 0x0a) && (*index != ';') && - (index != NULL)) - { - if(continuation == 1) - { - new_line = (char *) calloc((strlen(saved_line) + strlen(index) - +1), sizeof(char)); - strncat(new_line, saved_line, strlen(saved_line)); - strncat(new_line, index, strlen(index)); - free(saved_line); - saved_line = NULL; - index = new_line; - - if(strlen(index) > PARSERULE_SIZE) - { - FatalError("Please don't try to overflow the parser, " - "that's not very nice of you... (%d-byte " - "limit on rule size)\n", PARSERULE_SIZE); - } - - DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n", - new_line);); - } - - /* check for a '\' continuation character at the end of the line - * if it's there we need to get the next line in the file - */ - if(ContinuationCheck(index) == 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, - "[*] Processing rule: %s\n", index);); - - ParseRule(thefp, index, inclevel); - - if(new_line != NULL) - { - free(new_line); - new_line = NULL; - continuation = 0; - } - } - else - { - /* save the current line */ - saved_line = strdup(index); - - /* set the flag to let us know the next line is - * a continuation line - */ - continuation = 1; - } - } - - bzero((char *) buf, STD_BUF); + ParseRule(thefp, line, inclevel); + free(line); } if(file_name) @@ -323,36 +250,6 @@ return; } - - -int ContinuationCheck(char *rule) -{ - char *idx; /* indexing var for moving around on the string */ - - idx = rule + strlen(rule) - 1; - - DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n", - *idx);); - - while(isspace((int)*idx)) - { - idx--; - } - - if(*idx == '\\') - { - DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, " - "clearing char and returning 1\n");); - - /* clear the '\' so there isn't a problem on the appended string */ - *idx = '\x0'; - return 1; - } - - return 0; -} - - int CheckRule(char *str) { int len; @@ -476,7 +373,7 @@ char **toks; /* dbl ptr for mSplit call, holds rule tokens */ int num_toks; /* holds number of tokens found by mSplit */ int rule_type; /* rule type enumeration variable */ - char rule[PARSERULE_SIZE]; + char *rule; int protocol = 0; char *tmp; RuleTreeNode proto_node; @@ -485,11 +382,8 @@ /* chop off the <CR/LF> from the string */ strip(prule); - /* expand all variables */ - bzero((void *)rule, sizeof(rule)); + rule = ExpandVars(prule); - strncpy(rule, ExpandVars(prule), PARSERULE_SIZE-1); - /* break out the tokens from the rule string */ toks = mSplit(rule, " ", 10, &num_toks, 0); @@ -515,7 +409,7 @@ * any drop rules in the configuration file */ if (!InlineMode()) { - return; + goto cleanup; } break; @@ -526,7 +420,7 @@ * any sdrop rules in the configuration file */ if (!InlineMode()) { - return; + goto cleanup; } break; @@ -537,7 +431,7 @@ * any reject rules in the configuration file */ if (!InlineMode()) { - return; + goto cleanup; } break; #endif /* GIDS */ @@ -571,25 +465,25 @@ ParseRulesFile(tmp, inclevel + 1); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_VAR: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Variable\n");); VarDefine(toks[1], toks[2]); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_PREPROCESS: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Preprocessor\n");); ParsePreprocessor(rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_OUTPUT: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n");); ParseOutputPlugin(rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_ACTIVATE: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Activation rule\n");); @@ -603,25 +497,25 @@ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n");); ParseConfig(rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_DECLARE: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type declaration\n");); ParseRuleTypeDeclaration(rule_file, rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_THRESHOLD: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Threshold\n");); ParseSFThreshold(rule_file, rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_SUPPRESS: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Suppress\n");); ParseSFSuppress(rule_file, rule); mSplitFree(&toks, num_toks); - return; + goto cleanup; case RULE_UNKNOWN: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Unknown rule type, might be declared\n");); @@ -645,7 +539,7 @@ default: DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Invalid input: %s\n", prule);); mSplitFree(&toks, num_toks); - return; + goto cleanup; } if(num_toks < 7) @@ -661,7 +555,7 @@ " at the end of the line, make sure there are no\n" " carriage returns before the end of this line)\n", file_name, file_line); - return; + goto cleanup; } if (rule_type == RULE_UNKNOWN) @@ -833,6 +727,10 @@ mSplitFree(&toks, num_toks); +cleanup: + if(rule != prule) + free(rule); + return; } @@ -2902,21 +2800,28 @@ ***************************************************************************/ char *ExpandVars(char *string) { - static char estring[PARSERULE_SIZE]; + char *line = NULL; char rawvarname[128], varname[128], varaux[128], varbuffer[128], varmodifier, *varcontents; int varname_completed, c, i, j, iv, jv, l_string, name_only; int quote_toggle = 0; + size_t line_len, + string_len; if(!string || !*string || !strchr(string, '$')) return(string); - bzero((char *) estring, sizeof(estring)); + string_len = strlen(string); + line_len = string_len + STD_BUF; + /* allocate more than the original string. + * on variable expansion, increase string_len and make sure that + * line_len is always more or equal string_len */ + line = malloc(line_len + 1); i = j = 0; l_string = strlen(string); DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string);); - while(i < l_string && j < sizeof(estring) - 1) + while(i < l_string) { c = string[i++]; @@ -2924,116 +2829,119 @@ { /* added checks to make sure that we are inside a quoted string */ - quote_toggle ^= 1; + quote_toggle = !quote_toggle; + line[j++] = c; + continue; } - if(c == '$' && !quote_toggle) - { - bzero((char *) rawvarname, sizeof(rawvarname)); - varname_completed = 0; - name_only = 1; - iv = i; - jv = 0; + if(c != '$' || quote_toggle) + { + line[j++] = c; + continue; + } - if(string[i] == '(') - { - name_only = 0; - iv = i + 1; - } + bzero((char *) rawvarname, sizeof(rawvarname)); + varname_completed = 0; + name_only = 1; + iv = i; + jv = 0; - while(!varname_completed - && iv < l_string - && jv < sizeof(rawvarname) - 1) - { - c = string[iv++]; + if(string[i] == '(') + { + name_only = 0; + iv = i + 1; + } - if((name_only && !(isalnum(c) || c == '_')) - || (!name_only && c == ')')) - { - varname_completed = 1; + while(!varname_completed + && iv < l_string + && jv < sizeof(rawvarname) - 1) + { + c = string[iv++]; - if(name_only) - iv--; - } - else - { - rawvarname[jv++] = c; - } - } + if((name_only && !(isalnum(c) || c == '_')) + || (!name_only && c == ')')) + { + varname_completed = 1; - if(varname_completed || iv == l_string) - { - char *p; + if(name_only) + iv--; + } + else + { + rawvarname[jv++] = c; + } + } - i = iv; + if(varname_completed || iv == l_string) + { + char *p; - varcontents = NULL; + i = iv; - bzero((char *) varname, sizeof(varname)); - bzero((char *) varaux, sizeof(varaux)); - varmodifier = ' '; + varcontents = NULL; - if((p = strchr(rawvarname, ':'))) - { - strncpy(varname, rawvarname, p - rawvarname); + bzero((char *) varname, sizeof(varname)); + bzero((char *) varaux, sizeof(varaux)); + varmodifier = ' '; - if(strlen(p) >= 2) - { - varmodifier = *(p + 1); - strcpy(varaux, p + 2); - } - } - else - strcpy(varname, rawvarname); + if((p = strchr(rawvarname, ':'))) + { + strncpy(varname, rawvarname, p - rawvarname); - bzero((char *) varbuffer, sizeof(varbuffer)); + if(strlen(p) >= 2) + { + varmodifier = *(p + 1); + strcpy(varaux, p + 2); + } + } + else + strcpy(varname, rawvarname); - varcontents = VarGet(varname); + bzero((char *) varbuffer, sizeof(varbuffer)); - switch(varmodifier) - { - case '-': - if(!varcontents || !strlen(varcontents)) - varcontents = varaux; - break; + varcontents = VarGet(varname); - case '?': - if(!varcontents || !strlen(varcontents)) - { - ErrorMessage("%s(%d): ", file_name, file_line); + switch(varmodifier) + { + case '-': + if(!varcontents || !strlen(varcontents)) + varcontents = varaux; + break; - if(strlen(varaux)) - FatalError("%s\n", varaux); - else - FatalError("Undefined variable \"%s\"\n", varname); - } - break; - } + case '?': + if(!varcontents || !strlen(varcontents)) + { + ErrorMessage("%s(%d): ", file_name, file_line); - if(varcontents) - { - int l_varcontents = strlen(varcontents); + if(strlen(varaux)) + FatalError("%s\n", varaux); + else + FatalError("Undefined variable \"%s\"\n", varname); + } + break; + } - iv = 0; + if(varcontents) + { + int l_varcontents = strlen(varcontents); + string_len += l_varcontents; - while(iv < l_varcontents && j < sizeof(estring) - 1) - estring[j++] = varcontents[iv++]; - } - } - else - { - estring[j++] = '$'; - } - } - else - { - estring[j++] = c; - } + if(string_len > line_len) + line = realloc(line, (line_len += STD_BUF) + 1); + memcpy(line + j, varcontents, l_varcontents); + j += l_varcontents; + } + } + else + { + line[j++] = '$'; + } } - DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring);); + line[j] = 0; + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", line);); - return(estring); + return line; } @@ -4194,40 +4102,85 @@ return; } -/* adapted from ParseRuleFule in rules.c */ -char *ReadLine(FILE * file) +char *ReadLine(FILE *in) { - char buf[STD_BUF]; - char *index; + size_t filledLen = 0, + len = 0, + lineSize = 0; + char *line = NULL, + *pos; - bzero((char *) buf, STD_BUF); - - /* - * Read a line from file and return it. Skip over lines beginning with #, - * ;, or a newline - */ - while((fgets(buf, STD_BUF, file)) != NULL) +again: + for (;;) { - file_line++; - index = buf; + /* allocate buffer */ + if (len - filledLen < STD_BUF) + { + line = realloc(line, (len += STD_BUF) + 1); + if (len != STD_BUF) + line[len - 1] = 0; + else + *line = 0; + } + if (fgets(line + filledLen, len - filledLen + 1, in) == NULL || + line[len - 1] == 0 || line[len - 1] == '\n') + { + /* no characters read? */ + if (*line == 0) + { + free(line); + return NULL; + } + + file_line++; #ifdef DEBUG2 - LogMessage("Got line %s (%d): %s\n", file_name, file_line, buf); + LogMessage("Got line %s (%d): %s\n", file_name, file_line, line + lineSize); #endif - /* if it's not a comment or a <CR>, we return it */ - if((*index != '#') && (*index != 0x0a) && (*index != ';') - && (index != NULL)) - { - /* advance through any whitespace at the beginning of ther line */ - while(isspace((int) *index)) - ++index; - /* return a copy of the line */ - return strdup(index); - } + /* if the line ends with a `\' */ + pos = line + strlen(line) - 1; + if (*pos == '\\') + FatalError("Line %d ends with a `\', but no next line is " + "present\n", file_line); + + for (; line + lineSize < pos && isspace((unsigned char) *pos); pos--); + + /* found non-space is backslash? */ + if (*pos == '\\') + { + *(pos + 1) = 0; + filledLen = pos - line; + lineSize = filledLen; + continue; + } + + break; + } + + + filledLen = len; } - return NULL; + /* find first non-space character */ + for (pos = line; isspace((unsigned char) *pos); pos++); + /* is it a comment? */ + if (*pos == '#' || *pos == ';' || *pos == 0) + { + lineSize = filledLen = 0; + *line = 0; + goto again; + } + + /* strip whitespace at the beginning of the line if present */ + if (line == pos) + return line; + else + { + char *copy = strdup(pos); + free(line); + return copy; + } } /*