diff --git a/src/detect-parse.c b/src/detect-parse.c index b94d54dd6cd0..493bee10ea9f 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -845,7 +845,8 @@ int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) return -1; } -static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, size_t output_size) +static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, + size_t output_size, bool requires) { SigTableElmt *st = NULL; char *optname = NULL; @@ -899,6 +900,12 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, } optname = optstr; + if (requires) { + if (strcmp(optname, "requires")) { + goto finish; + } + } + /* Call option parsing */ st = SigTableGet(optname); if (st == NULL || st->Setup == NULL) { @@ -1038,6 +1045,7 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, } s->init_data->negated = false; +finish: if (strlen(optend) > 0) { strlcpy(output, optend, output_size); return 1; @@ -1323,9 +1331,11 @@ static inline int SigParseList(char **input, char *output, /** * \internal * \brief split a signature string into a few blocks for further parsing + * + * \param scan_only just scan, don't validate */ -static int SigParseBasics(DetectEngineCtx *de_ctx, - Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction) +static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, + SignatureParser *parser, uint8_t addrs_direction, bool scan_only) { char *index, dup[DETECT_MAX_RULE_SIZE]; @@ -1370,6 +1380,10 @@ static int SigParseBasics(DetectEngineCtx *de_ctx, } strlcpy(parser->opts, index, sizeof(parser->opts)); + if (scan_only) { + return 0; + } + /* Parse Action */ if (SigParseAction(s, parser->action) < 0) goto error; @@ -1431,12 +1445,13 @@ static inline bool CheckAscii(const char *str) * \param s memory structure to store the signature in * \param sigstr the raw signature as a null terminated string * \param addrs_direction direction (for bi-directional sigs) + * \param require only scan rule for requires * * \param -1 parse error * \param 0 ok */ -static int SigParse(DetectEngineCtx *de_ctx, Signature *s, - const char *sigstr, uint8_t addrs_direction, SignatureParser *parser) +static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, + uint8_t addrs_direction, SignatureParser *parser, bool requires) { SCEnter(); @@ -1450,12 +1465,7 @@ static int SigParse(DetectEngineCtx *de_ctx, Signature *s, SCReturnInt(-1); } - s->sig_str = SCStrdup(sigstr); - if (unlikely(s->sig_str == NULL)) { - SCReturnInt(-1); - } - - int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction); + int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires); if (ret < 0) { SCLogDebug("SigParseBasics failed"); SCReturnInt(-1); @@ -1467,21 +1477,27 @@ static int SigParse(DetectEngineCtx *de_ctx, Signature *s, char input[buffer_size]; char output[buffer_size]; memset(input, 0x00, buffer_size); - memcpy(input, parser->opts, strlen(parser->opts)+1); + memcpy(input, parser->opts, strlen(parser->opts) + 1); /* loop the option parsing. Each run processes one option * and returns the rest of the option string through the * output variable. */ do { memset(output, 0x00, buffer_size); - ret = SigParseOptions(de_ctx, s, input, output, buffer_size); + ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires); if (ret == 1) { memcpy(input, output, buffer_size); } } while (ret == 1); + + if (ret < 0) { + /* Suricata didn't meet the rule requirements, skip. */ + goto end; + } } +end: DetectIPProtoRemoveAllSMs(de_ctx, s); SCReturnInt(ret); @@ -2142,17 +2158,33 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, if (sig == NULL) goto error; + sig->sig_str = SCStrdup(sigstr); + if (unlikely(sig->sig_str == NULL)) { + goto error; + } + /* default gid to 1 */ sig->gid = 1; - int ret = SigParse(de_ctx, sig, sigstr, dir, &parser); + /* We do a first parse of the rule in a requires, or scan-only + * mode. Syntactic errors will be picked up here, but the only + * part of the rule that is validated completely is the "requires" + * keyword. */ + int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true); if (ret == -4) { /* Rule requirements not met. */ de_ctx->sigerror_silent = true; de_ctx->sigerror_ok = true; de_ctx->sigerror_requires = true; goto error; - } else if (ret == -3) { + } else if (ret < 0) { + goto error; + } + + /* Now completely parse the rule. */ + ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false); + BUG_ON(ret == -4); + if (ret == -3) { de_ctx->sigerror_silent = true; de_ctx->sigerror_ok = true; goto error;