requires: pre-scan rule for requires expressions

Add a "pre-scan" rule parse that will check for requires statement. It
will return a special error code (-4) if the requires fails due to
missing requirements.

Syntactic errors will also abort parsing here.

Feature: #5972
pull/10076/head
Jason Ish 3 years ago committed by Victor Julien
parent 5d5b0509a5
commit 435c03172e

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

Loading…
Cancel
Save