From 342059835fe7ec0079ac91a152a0abab516b184f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 May 2017 20:34:07 +0200 Subject: [PATCH] detect-parse: improve common parser In preparation of turning input to keyword parsers to const add options to the common rule parser to enforce and strip double quotes and parse negation support. At registration, the keyword can register 3 extra flags: SIGMATCH_QUOTES_MANDATORY: value to keyword must be quoted SIGMATCH_QUOTES_OPTIONAL: value to keyword may be quoted SIGMATCH_HANDLE_NEGATION: leading ! is parsed In all cases leading spaces are removed. If the 'quote' flags are set, the quotes are removed from the input as well. --- src/detect-content.c | 302 ++++++------------------------ src/detect-content.h | 6 +- src/detect-fileext.c | 23 ++- src/detect-filemagic.c | 24 ++- src/detect-filename.c | 23 ++- src/detect-flowvar.c | 12 +- src/detect-msg.c | 47 +---- src/detect-parse.c | 88 ++++++++- src/detect-pcre.c | 51 +++-- src/detect-replace.c | 12 +- src/detect-ssh-proto-version.c | 1 + src/detect-ssh-software-version.c | 1 + src/detect-tls.c | 57 ++---- src/detect-uricontent.c | 1 + src/detect.h | 17 +- 15 files changed, 264 insertions(+), 401 deletions(-) diff --git a/src/detect-content.c b/src/detect-content.c index 64904b0168..687360a622 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -59,6 +59,7 @@ void DetectContentRegister (void) sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests; + sigmatch_table[DETECT_CONTENT].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); } /** @@ -73,48 +74,20 @@ void DetectContentRegister (void) * \retval 0 ok */ int DetectContentDataParse(const char *keyword, const char *contentstr, - uint8_t **pstr, uint16_t *plen, uint32_t *flags) + uint8_t **pstr, uint16_t *plen) { char *str = NULL; - uint16_t len; - uint16_t pos = 0; - uint16_t slen = 0; + size_t slen = 0; slen = strlen(contentstr); if (slen == 0) { return -1; } + uint8_t buffer[slen + 1]; + strlcpy((char *)&buffer, contentstr, slen + 1); + str = (char *)buffer; - /* skip the first spaces */ - while (pos < slen && isspace((unsigned char)contentstr[pos])) - pos++; - - if (contentstr[pos] == '!') { - *flags = DETECT_CONTENT_NEGATED; - pos++; - } else - *flags = 0; - - if (contentstr[pos] == '\"' && ((slen - pos) <= 1)) - goto error; - - if (!(contentstr[pos] == '\"' && contentstr[slen - 1] == '\"')) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "%s keyword arguments " - "should be always enclosed in double quotes. Invalid " - "content keyword passed in this rule - \"%s\"", - keyword, contentstr); - goto error; - } - - if ((str = SCStrdup(contentstr + pos + 1)) == NULL) - goto error; - str[strlen(str) - 1] = '\0'; - - len = strlen(str); - if (len == 0) - goto error; - - SCLogDebug("\"%s\", len %" PRIu32 "", str, len); + SCLogDebug("\"%s\", len %" PRIuMAX, str, (uintmax_t)slen); //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); char converted = 0; @@ -127,7 +100,7 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t binpos = 0; uint16_t bin_count = 0; - for (i = 0, x = 0; i < len; i++) { + for (i = 0, x = 0; i < slen; i++) { // SCLogDebug("str[%02u]: %c", i, str[i]); if (str[i] == '|') { bin_count++; @@ -199,17 +172,22 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, } if (converted) { - len = x; + slen = x; } } - *plen = len; - *pstr = (uint8_t *)str; - return 0; + if (slen) { + uint8_t *ptr = SCCalloc(1, slen); + if (ptr == NULL) { + return -1; + } + memcpy(ptr, str, slen); + *plen = (uint16_t)slen; + *pstr = ptr; + return 0; + } error: - if (str != NULL) - SCFree(str); return -1; } /** @@ -217,15 +195,14 @@ error: * \initonly */ DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, - char *contentstr) + const char *contentstr) { DetectContentData *cd = NULL; uint8_t *content = NULL; uint16_t len = 0; - uint32_t flags = 0; int ret; - ret = DetectContentDataParse("content", contentstr, &content, &len, &flags); + ret = DetectContentDataParse("content", contentstr, &content, &len); if (ret == -1) { return NULL; } @@ -238,9 +215,6 @@ DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, memset(cd, 0, sizeof(DetectContentData) + len); - if (flags == DETECT_CONTENT_NEGATED) - cd->flags |= DETECT_CONTENT_NEGATED; - cd->content = (uint8_t *)cd + sizeof(DetectContentData); memcpy(cd->content, content, len); cd->content_len = len; @@ -265,16 +239,9 @@ DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, } DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, - char *contentstr) + const char *contentstr) { - char str[strlen(contentstr) + 3]; // 2 for quotes, 1 for \0 - - str[0] = '\"'; - memcpy(str + 1, contentstr, strlen(contentstr)); - str[strlen(contentstr) + 1] = '\"'; - str[strlen(contentstr) + 2] = '\0'; - - return DetectContentParse(spm_global_thread_ctx, str); + return DetectContentParse(spm_global_thread_ctx, contentstr); } /** @@ -381,6 +348,10 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) cd = DetectContentParse(de_ctx->spm_global_thread_ctx, contentstr); if (cd == NULL) goto error; + if (s->init_data->negated == true) { + cd->flags |= DETECT_CONTENT_NEGATED; + } + DetectContentPrint(cd); int sm_list = s->init_data->list; @@ -432,8 +403,8 @@ static int DetectContentParseTest01 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"abc\\:def\""; - char *teststringparsed = "abc:def"; + const char *teststring = "abc\\:def"; + const char *teststringparsed = "abc:def"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -463,8 +434,8 @@ static int DetectContentParseTest02 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"abc\\;def\""; - char *teststringparsed = "abc;def"; + const char *teststring = "abc\\;def"; + const char *teststringparsed = "abc;def"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -494,8 +465,8 @@ static int DetectContentParseTest03 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"abc\\\"def\""; - char *teststringparsed = "abc\"def"; + const char *teststring = "abc\\\"def"; + const char *teststringparsed = "abc\"def"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -525,8 +496,8 @@ static int DetectContentParseTest04 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"abc\\\\def\""; - char *teststringparsed = "abc\\def"; + const char *teststring = "abc\\\\def"; + const char *teststringparsed = "abc\\def"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -557,7 +528,7 @@ static int DetectContentParseTest05 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"abc\\def\""; + const char *teststring = "abc\\def"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -582,8 +553,8 @@ static int DetectContentParseTest06 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"a|42|c|44|e|46|\""; - char *teststringparsed = "abcdef"; + const char *teststring = "a|42|c|44|e|46|"; + const char *teststringparsed = "abcdef"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -614,7 +585,7 @@ static int DetectContentParseTest07 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"\""; + const char *teststring = ""; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -637,7 +608,7 @@ static int DetectContentParseTest08 (void) { int result = 1; DetectContentData *cd = NULL; - char *teststring = "\"\""; + const char *teststring = ""; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); @@ -925,168 +896,18 @@ static int DetectContentLongPatternMatchTest11() static int DetectContentParseTest09(void) { - int result = 0; - DetectContentData *cd = NULL; - char *teststring = "!\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (cd->flags & DETECT_CONTENT_NEGATED) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseTest10(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = "!\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (cd->flags & DETECT_CONTENT_NEGATED) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest11(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = "\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (!(cd->flags & DETECT_CONTENT_NEGATED)) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest12(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = "\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (!(cd->flags & DETECT_CONTENT_NEGATED)) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest13(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = "!\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (cd->flags & DETECT_CONTENT_NEGATED) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest14(void) -{ - int result = 0; DetectContentData *cd = NULL; - char *teststring = " \"!boo\""; + const char *teststring = "boo"; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); FAIL_IF(spm_global_thread_ctx == NULL); cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (!(cd->flags & DETECT_CONTENT_NEGATED)) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest15(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = " !\"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - if (cd->flags & DETECT_CONTENT_NEGATED) - result = 1; - - DetectContentFree(cd); - } - SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; -} - -static int DetectContentParseNegTest16(void) -{ - int result = 0; - DetectContentData *cd = NULL; - char *teststring = " \"boo\""; - - uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); - SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); - FAIL_IF(spm_global_thread_ctx == NULL); - - cd = DetectContentParse(spm_global_thread_ctx, teststring); - if (cd != NULL) { - result = (cd->content_len == 3 && memcmp(cd->content,"boo",3) == 0); - DetectContentFree(cd); - } + FAIL_IF_NULL(cd); + DetectContentFree(cd); SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); - return result; + PASS; } /** @@ -1131,7 +952,7 @@ static int DetectContentParseTest18(void) s->alproto = ALPROTO_DCERPC; - result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); + result &= (DetectContentSetup(de_ctx, s, "one") == 0); result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -1140,7 +961,7 @@ static int DetectContentParseTest18(void) if (s == NULL) return 0; - result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); + result &= (DetectContentSetup(de_ctx, s, "one") == 0); result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: @@ -2164,16 +1985,14 @@ static int DetectContentParseTest41(void) { int result = 1; DetectContentData *cd = NULL; - int patlen = 257; + int patlen = 255; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (unlikely(teststring == NULL)) return 0; int idx = 0; - teststring[idx++] = '\"'; - for (int i = 0; i < (patlen - 2); idx++, i++) { + for (int i = 0; i < patlen; idx++, i++) { teststring[idx] = 'a'; } - teststring[idx++] = '\"'; teststring[idx++] = '\0'; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); @@ -2199,16 +2018,14 @@ static int DetectContentParseTest42(void) { int result = 1; DetectContentData *cd = NULL; - int patlen = 258; + int patlen = 256; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (unlikely(teststring == NULL)) return 0; int idx = 0; - teststring[idx++] = '\"'; - for (int i = 0; i < (patlen - 2); idx++, i++) { + for (int i = 0; i < patlen; idx++, i++) { teststring[idx] = 'a'; } - teststring[idx++] = '\"'; teststring[idx++] = '\0'; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); @@ -2231,20 +2048,18 @@ static int DetectContentParseTest43(void) { int result = 1; DetectContentData *cd = NULL; - int patlen = 260; + int patlen = 258; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (unlikely(teststring == NULL)) return 0; int idx = 0; - teststring[idx++] = '\"'; teststring[idx++] = '|'; teststring[idx++] = '4'; teststring[idx++] = '6'; teststring[idx++] = '|'; - for (int i = 0; i < (patlen - 6); idx++, i++) { + for (int i = 0; i < (patlen - 4); idx++, i++) { teststring[idx] = 'a'; } - teststring[idx++] = '\"'; teststring[idx++] = '\0'; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); @@ -2270,20 +2085,18 @@ static int DetectContentParseTest44(void) { int result = 1; DetectContentData *cd = NULL; - int patlen = 261; + int patlen = 259; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (unlikely(teststring == NULL)) return 0; int idx = 0; - teststring[idx++] = '\"'; teststring[idx++] = '|'; teststring[idx++] = '4'; teststring[idx++] = '6'; teststring[idx++] = '|'; - for (int i = 0; i < (patlen - 6); idx++, i++) { + for (int i = 0; i < (patlen - 4); idx++, i++) { teststring[idx] = 'a'; } - teststring[idx++] = '\"'; teststring[idx++] = '\0'; uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); @@ -2859,13 +2672,6 @@ static void DetectContentRegisterTests(void) UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07); UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08); UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09); - UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10); - UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11); - UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12); - UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13); - UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14); - UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15); - UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16); UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17); UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18); UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19); diff --git a/src/detect-content.h b/src/detect-content.h index 81bd2a1fa3..fd21706774 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -106,11 +106,11 @@ typedef struct DetectContentData_ { void DetectContentRegister (void); uint32_t DetectContentMaxId(DetectEngineCtx *); DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, - char *contentstr); + const char *contentstr); int DetectContentDataParse(const char *keyword, const char *contentstr, - uint8_t **pstr, uint16_t *plen, uint32_t *flags); + uint8_t **pstr, uint16_t *plen); DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, - char *contentstr); + const char *contentstr); int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr); void DetectContentPrint(DetectContentData *); diff --git a/src/detect-fileext.c b/src/detect-fileext.c index a052d97d75..5483901c21 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -70,6 +70,7 @@ void DetectFileextRegister(void) sigmatch_table[DETECT_FILEEXT].Setup = DetectFileextSetup; sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; sigmatch_table[DETECT_FILEEXT].RegisterTests = DetectFileextRegisterTests; + sigmatch_table[DETECT_FILEEXT].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION; g_file_match_list_id = DetectBufferTypeRegister("files"); @@ -139,7 +140,7 @@ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval pointer to DetectFileextData on success * \retval NULL on failure */ -static DetectFileextData *DetectFileextParse (char *str) +static DetectFileextData *DetectFileextParse (const char *str, bool negate) { DetectFileextData *fileext = NULL; @@ -150,13 +151,17 @@ static DetectFileextData *DetectFileextParse (char *str) memset(fileext, 0x00, sizeof(DetectFileextData)); - if (DetectContentDataParse("fileext", str, &fileext->ext, &fileext->len, &fileext->flags) == -1) { + if (DetectContentDataParse("fileext", str, &fileext->ext, &fileext->len) == -1) { goto error; } uint16_t u; for (u = 0; u < fileext->len; u++) fileext->ext[u] = tolower(fileext->ext[u]); + if (negate) { + fileext->flags |= DETECT_CONTENT_NEGATED; + } + SCLogDebug("flags %02X", fileext->flags); if (fileext->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated fileext"); @@ -198,7 +203,7 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) DetectFileextData *fileext= NULL; SigMatch *sm = NULL; - fileext = DetectFileextParse(str); + fileext = DetectFileextParse(str, s->init_data->negated); if (fileext == NULL) goto error; @@ -245,9 +250,9 @@ static void DetectFileextFree(void *ptr) /** * \test DetectFileextTestParse01 */ -int DetectFileextTestParse01 (void) +static int DetectFileextTestParse01 (void) { - DetectFileextData *dfd = DetectFileextParse("\"doc\""); + DetectFileextData *dfd = DetectFileextParse("doc", false); if (dfd != NULL) { DetectFileextFree(dfd); return 1; @@ -258,11 +263,11 @@ int DetectFileextTestParse01 (void) /** * \test DetectFileextTestParse02 */ -int DetectFileextTestParse02 (void) +static int DetectFileextTestParse02 (void) { int result = 0; - DetectFileextData *dfd = DetectFileextParse("\"tar.gz\""); + DetectFileextData *dfd = DetectFileextParse("tar.gz", false); if (dfd != NULL) { if (dfd->len == 6 && memcmp(dfd->ext, "tar.gz", 6) == 0) { result = 1; @@ -277,11 +282,11 @@ int DetectFileextTestParse02 (void) /** * \test DetectFileextTestParse03 */ -int DetectFileextTestParse03 (void) +static int DetectFileextTestParse03 (void) { int result = 0; - DetectFileextData *dfd = DetectFileextParse("\"pdf\""); + DetectFileextData *dfd = DetectFileextParse("pdf", false); if (dfd != NULL) { if (dfd->len == 3 && memcmp(dfd->ext, "pdf", 3) == 0) { result = 1; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 34f6c6fca0..eeb3805bfc 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -71,6 +71,7 @@ void DetectFilemagicRegister(void) sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetupNoSupport; + sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; } #else /* HAVE_MAGIC */ @@ -94,6 +95,7 @@ void DetectFilemagicRegister(void) sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests; + sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; g_file_match_list_id = DetectBufferTypeRegister("files"); @@ -239,7 +241,7 @@ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval filemagic pointer to DetectFilemagicData on success * \retval NULL on failure */ -static DetectFilemagicData *DetectFilemagicParse (char *str) +static DetectFilemagicData *DetectFilemagicParse (const char *str, bool negate) { DetectFilemagicData *filemagic = NULL; @@ -250,7 +252,7 @@ static DetectFilemagicData *DetectFilemagicParse (char *str) memset(filemagic, 0x00, sizeof(DetectFilemagicData)); - if (DetectContentDataParse ("filemagic", str, &filemagic->name, &filemagic->len, &filemagic->flags) == -1) { + if (DetectContentDataParse ("filemagic", str, &filemagic->name, &filemagic->len) == -1) { goto error; } @@ -259,6 +261,10 @@ static DetectFilemagicData *DetectFilemagicParse (char *str) goto error; } + if (negate) { + filemagic->flags |= DETECT_CONTENT_NEGATED; + } + SCLogDebug("flags %02X", filemagic->flags); if (filemagic->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated filemagic"); @@ -361,7 +367,7 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st DetectFilemagicData *filemagic = NULL; SigMatch *sm = NULL; - filemagic = DetectFilemagicParse(str); + filemagic = DetectFilemagicParse(str, s->init_data->negated); if (filemagic == NULL) goto error; @@ -416,9 +422,9 @@ static void DetectFilemagicFree(void *ptr) /** * \test DetectFilemagicTestParse01 */ -int DetectFilemagicTestParse01 (void) +static int DetectFilemagicTestParse01 (void) { - DetectFilemagicData *dnd = DetectFilemagicParse("\"secret.pdf\""); + DetectFilemagicData *dnd = DetectFilemagicParse("secret.pdf", false); if (dnd != NULL) { DetectFilemagicFree(dnd); return 1; @@ -429,11 +435,11 @@ int DetectFilemagicTestParse01 (void) /** * \test DetectFilemagicTestParse02 */ -int DetectFilemagicTestParse02 (void) +static int DetectFilemagicTestParse02 (void) { int result = 0; - DetectFilemagicData *dnd = DetectFilemagicParse("\"backup.tar.gz\""); + DetectFilemagicData *dnd = DetectFilemagicParse("backup.tar.gz", false); if (dnd != NULL) { if (dnd->len == 13 && memcmp(dnd->name, "backup.tar.gz", 13) == 0) { result = 1; @@ -448,11 +454,11 @@ int DetectFilemagicTestParse02 (void) /** * \test DetectFilemagicTestParse03 */ -int DetectFilemagicTestParse03 (void) +static int DetectFilemagicTestParse03 (void) { int result = 0; - DetectFilemagicData *dnd = DetectFilemagicParse("\"cmd.exe\""); + DetectFilemagicData *dnd = DetectFilemagicParse("cmd.exe", false); if (dnd != NULL) { if (dnd->len == 7 && memcmp(dnd->name, "cmd.exe", 7) == 0) { result = 1; diff --git a/src/detect-filename.c b/src/detect-filename.c index d7ccde6201..840df3a31f 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -71,6 +71,7 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].Setup = DetectFilenameSetup; sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; + sigmatch_table[DETECT_FILENAME].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION; DetectAppLayerInspectEngineRegister("files", ALPROTO_HTTP, SIG_FLAG_TOSERVER, HTP_REQUEST_BODY, @@ -155,7 +156,7 @@ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval filename pointer to DetectFilenameData on success * \retval NULL on failure */ -static DetectFilenameData *DetectFilenameParse (char *str) +static DetectFilenameData *DetectFilenameParse (const char *str, bool negate) { DetectFilenameData *filename = NULL; @@ -166,7 +167,7 @@ static DetectFilenameData *DetectFilenameParse (char *str) memset(filename, 0x00, sizeof(DetectFilenameData)); - if (DetectContentDataParse ("filename", str, &filename->name, &filename->len, &filename->flags) == -1) { + if (DetectContentDataParse ("filename", str, &filename->name, &filename->len) == -1) { goto error; } @@ -175,6 +176,10 @@ static DetectFilenameData *DetectFilenameParse (char *str) goto error; } + if (negate) { + filename->flags |= DETECT_CONTENT_NEGATED; + } + SCLogDebug("flags %02X", filename->flags); if (filename->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated filename"); @@ -215,7 +220,7 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str DetectFilenameData *filename = NULL; SigMatch *sm = NULL; - filename = DetectFilenameParse(str); + filename = DetectFilenameParse(str, s->init_data->negated); if (filename == NULL) goto error; @@ -264,9 +269,9 @@ static void DetectFilenameFree(void *ptr) /** * \test DetectFilenameTestParse01 */ -int DetectFilenameTestParse01 (void) +static int DetectFilenameTestParse01 (void) { - DetectFilenameData *dnd = DetectFilenameParse("\"secret.pdf\""); + DetectFilenameData *dnd = DetectFilenameParse("secret.pdf", false); if (dnd != NULL) { DetectFilenameFree(dnd); return 1; @@ -277,11 +282,11 @@ int DetectFilenameTestParse01 (void) /** * \test DetectFilenameTestParse02 */ -int DetectFilenameTestParse02 (void) +static int DetectFilenameTestParse02 (void) { int result = 0; - DetectFilenameData *dnd = DetectFilenameParse("\"backup.tar.gz\""); + DetectFilenameData *dnd = DetectFilenameParse("backup.tar.gz", false); if (dnd != NULL) { if (dnd->len == 13 && memcmp(dnd->name, "backup.tar.gz", 13) == 0) { result = 1; @@ -296,11 +301,11 @@ int DetectFilenameTestParse02 (void) /** * \test DetectFilenameTestParse03 */ -int DetectFilenameTestParse03 (void) +static int DetectFilenameTestParse03 (void) { int result = 0; - DetectFilenameData *dnd = DetectFilenameParse("\"cmd.exe\""); + DetectFilenameData *dnd = DetectFilenameParse("cmd.exe", false); if (dnd != NULL) { if (dnd->len == 7 && memcmp(dnd->name, "cmd.exe", 7) == 0) { result = 1; diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index bd7ff4038c..e7f13b6fdf 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -125,7 +125,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws const char *str_ptr; uint8_t *content = NULL; uint16_t contentlen = 0; - uint32_t contentflags = 0; + uint32_t contentflags = s->init_data->negated ? DETECT_CONTENT_NEGATED : 0; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { @@ -147,7 +147,15 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws } varcontent = (char *)str_ptr; - res = DetectContentDataParse("flowvar", varcontent, &content, &contentlen, &contentflags); + if (strlen(varcontent) >= 2) { + if (varcontent[0] == '"') + varcontent++; + if (varcontent[strlen(varcontent)-1] == '"') + varcontent[strlen(varcontent)-1] = '\0'; + } + SCLogDebug("varcontent %s", varcontent); + + res = DetectContentDataParse("flowvar", varcontent, &content, &contentlen); if (res == -1) goto error; diff --git a/src/detect-msg.c b/src/detect-msg.c index 314a2f21b5..fb3d241107 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -45,40 +45,18 @@ void DetectMsgRegister (void) sigmatch_table[DETECT_MSG].Setup = DetectMsgSetup; sigmatch_table[DETECT_MSG].Free = NULL; sigmatch_table[DETECT_MSG].RegisterTests = DetectMsgRegisterTests; + sigmatch_table[DETECT_MSG].flags = SIGMATCH_QUOTES_MANDATORY; } static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) { - char *str = NULL; - uint16_t len; - uint16_t pos = 0; - uint16_t slen = 0; - - slen = strlen(msgstr); + size_t slen = strlen(msgstr); if (slen == 0) - goto error; - - /* skip the first spaces */ - while (pos < slen && isspace((unsigned char)msgstr[pos])) - pos++; - - /* Strip leading and trailing "s. */ - if (msgstr[pos] == '\"') { - str = SCStrdup(msgstr + pos + 1); - if (unlikely(str == NULL)) - goto error; - if (strlen(str) && str[strlen(str) - 1] == '\"') { - str[strlen(str)-1] = '\0'; - } - } else { - SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr); - goto error; - } - - len = strlen(str); - if (len == 0) - goto error; + return -1; + char input[slen + 1]; + strlcpy(input, msgstr, slen + 1); + char *str = input; char converted = 0; { @@ -86,7 +64,7 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) uint8_t escape = 0; /* it doesn't matter if we need to escape or not we remove the extra "\" to mimic snort */ - for (i = 0, x = 0; i < len; i++) { + for (i = 0, x = 0; i < slen; i++) { //printf("str[%02u]: %c\n", i, str[i]); if(!escape && str[i] == '\\') { escape = 1; @@ -119,22 +97,17 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) #endif if (converted) { - len = x; - str[len] = '\0'; + slen = x; + str[slen] = '\0'; } } - s->msg = SCMalloc(len + 1); + s->msg = SCStrdup(str); if (s->msg == NULL) goto error; - - strlcpy(s->msg, str, len + 1); - - SCFree(str); return 0; error: - SCFree(str); return -1; } diff --git a/src/detect-parse.c b/src/detect-parse.c index f2d34f36a6..6239d5d92c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -679,32 +679,100 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, goto error; } } + s->init_data->negated = false; /* Validate double quoting, trimming trailing white space along the way. */ if (strlen(optvalue) > 0) { size_t ovlen = strlen(optvalue); - if (ovlen && optvalue[0] == '"') { + char *ptr = optvalue; + + /* skip leading whitespace */ + while (ovlen > 0) { + if (!isblank(*ptr)) + break; + ptr++; + ovlen--; + } + if (ovlen == 0) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting or malformed option to %s keyword: \'%s\'", + optname, optstr); + goto error; + } + + /* see if value is negated */ + if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') { + s->init_data->negated = true; + ptr++; + ovlen--; + } + /* skip more whitespace */ + while (ovlen > 0) { + if (!isblank(*ptr)) + break; + ptr++; + ovlen--; + } + if (ovlen == 0) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting or malformed option to %s keyword: \'%s\'", + optname, optstr); + goto error; + } + /* if quoting is mandatory, enforce it */ + if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formattingto %s keyword: " + "value must be double quoted \'%s\'", optname, optstr); + goto error; + } + + if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY)) + && ovlen && *ptr == '"') + { for (; ovlen > 0; ovlen--) { - if (isblank(optvalue[ovlen - 1])) { - optvalue[ovlen - 1] = '\0'; + if (isblank(ptr[ovlen - 1])) { + ptr[ovlen - 1] = '\0'; } else { break; } } - if (ovlen && optvalue[ovlen - 1] != '"') { + if (ovlen && ptr[ovlen - 1] != '"') { SCLogError(SC_ERR_INVALID_SIGNATURE, "bad option value formatting (possible missing semicolon) " "for keyword %s: \'%s\'", optname, optvalue); goto error; } + if (ovlen > 1) { + /* strip leading " */ + ptr++; + ovlen--; + ptr[ovlen - 1] = '\0'; + ovlen--; + } + if (ovlen == 0) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "bad input " + "for keyword %s: \'%s\'", optname, optvalue); + goto error; + } + } else { + if (*ptr == '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, "quotes on %s keyword that doesn't support them: \'%s\'", + optname, optstr); + goto error; + } + } + /* setup may or may not add a new SigMatch to the list */ + if (st->Setup(de_ctx, s, ptr) < 0) { + SCLogDebug("\"%s\" failed to setup", st->name); + goto error; + } + } else { + /* setup may or may not add a new SigMatch to the list */ + if (st->Setup(de_ctx, s, NULL) < 0) { + SCLogDebug("\"%s\" failed to setup", st->name); + goto error; } } - - /* setup may or may not add a new SigMatch to the list */ - if (st->Setup(de_ctx, s, strlen(optvalue) ? optvalue : NULL) < 0) { - SCLogDebug("\"%s\" failed to setup", st->name); - goto error; - } + s->init_data->negated = false; if (ret == 4) { return 1; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 3d9f4b76f2..95fce0e8e6 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -92,6 +92,7 @@ void DetectPcreRegister (void) sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup; sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; + sigmatch_table[DETECT_PCRE].flags = (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION); intmax_t val = 0; @@ -306,8 +307,8 @@ static int DetectPcreHasUpperCase(const char *re) return 0; } -static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int *sm_list, - char *capture_names, size_t capture_names_size) +static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, const char *regexstr, int *sm_list, + char *capture_names, size_t capture_names_size, bool negate) { int ec; const char *eb; @@ -319,18 +320,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int check_host_header = 0; - char op_str[64] = ""; - uint8_t negate = 0; - - while (*regexstr != '\0' && isspace((unsigned char)*regexstr)) { - regexstr++; - } - - if (*regexstr == '!') { - negate = 1; - regexstr++; - } int cut_capture = 0; char *fcap = strstr(regexstr, "flow:"); @@ -670,14 +660,14 @@ error: /** \internal * \brief check if we need to extract capture settings and set them up if needed */ -static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, +static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, char *capture_names) { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; memset(&ov, 0, sizeof(ov)); char type_str[16] = ""; - char *orig_right_edge = regexstr + strlen(regexstr); + const char *orig_right_edge = regexstr + strlen(regexstr); char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL }; int name_idx = 0; int capture_cnt = 0; @@ -811,7 +801,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst int parsed_sm_list = DETECT_SM_LIST_NOTSET; char capture_names[1024] = ""; - pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, capture_names, sizeof(capture_names)); + pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, + capture_names, sizeof(capture_names), s->init_data->negated); if (pd == NULL) goto error; if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0) @@ -906,12 +897,12 @@ static int DetectPcreParseTest01 (void) { int result = 1; DetectPcreData *pd = NULL; - char *teststring = "/blah/7"; + const char *teststring = "/blah/7"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -930,7 +921,7 @@ static int DetectPcreParseTest02 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -949,7 +940,7 @@ static int DetectPcreParseTest03 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -968,7 +959,7 @@ static int DetectPcreParseTest04 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -988,7 +979,7 @@ static int DetectPcreParseTest05 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -1008,7 +999,7 @@ static int DetectPcreParseTest06 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -1028,7 +1019,7 @@ static int DetectPcreParseTest07 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -1048,7 +1039,7 @@ static int DetectPcreParseTest08 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -1068,7 +1059,7 @@ static int DetectPcreParseTest09 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -3400,24 +3391,24 @@ static int DetectPcreParseHttpHost(void) FAIL_IF(de_ctx == NULL); - pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0); + pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0, false); FAIL_IF(pd == NULL); DetectPcreFree(pd); list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0); + pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0, false); FAIL_IF(pd != NULL); /* Uppercase meta characters are valid. */ list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0); + pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0, false); FAIL_IF(pd == NULL); DetectPcreFree(pd); /* This should not parse as the first \ escapes the second \, then * we have a D. */ list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0); + pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0, false); FAIL_IF(pd != NULL); DetectEngineCtxFree(de_ctx); diff --git a/src/detect-replace.c b/src/detect-replace.c index 17f0561505..e4392f3d64 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -69,26 +69,26 @@ void DetectReplaceRegister (void) sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup; sigmatch_table[DETECT_REPLACE].Free = NULL; sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests; + sigmatch_table[DETECT_REPLACE].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); } int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) { uint8_t *content = NULL; uint16_t len = 0; - uint32_t flags = 0; SigMatch *pm = NULL; DetectContentData *ud = NULL; - int ret = DetectContentDataParse("replace", replacestr, &content, &len, &flags); - if (ret == -1) - goto error; - - if (flags & DETECT_CONTENT_NEGATED) { + if (s->init_data->negated) { SCLogError(SC_ERR_INVALID_VALUE, "Can't negate replacement string: %s", replacestr); goto error; } + int ret = DetectContentDataParse("replace", replacestr, &content, &len); + if (ret == -1) + goto error; + switch (run_mode) { case RUNMODE_NFQ: case RUNMODE_IPFW: diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 0099eabdf1..26ec15113a 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -80,6 +80,7 @@ void DetectSshVersionRegister(void) sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].flags = SIGMATCH_QUOTES_OPTIONAL; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 85d5769271..cd1dbfe5dc 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -94,6 +94,7 @@ void DetectSshSoftwareVersionRegister(void) sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].flags = SIGMATCH_QUOTES_OPTIONAL; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); diff --git a/src/detect-tls.c b/src/detect-tls.c index 222e4f9335..7e2b2a46bf 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -64,8 +64,8 @@ * \brief Regex for parsing "id" option, matching number or "number" */ -#define PARSE_REGEX "^\\s*(\\!*)\\s*([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$" -#define PARSE_REGEX_FINGERPRINT "^\\s*(\\!*)\\s*([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$" +#define PARSE_REGEX "^([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$" +#define PARSE_REGEX_FINGERPRINT "^([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$" static pcre *subject_parse_regex; static pcre_extra *subject_parse_regex_study; @@ -122,6 +122,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; sigmatch_table[DETECT_AL_TLS_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; + sigmatch_table[DETECT_AL_TLS_SUBJECT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; @@ -130,6 +131,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; @@ -138,6 +140,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store"; sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store"; @@ -228,7 +231,7 @@ static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval id_d pointer to DetectTlsData on success * \retval NULL on failure */ -static DetectTlsData *DetectTlsSubjectParse (char *str) +static DetectTlsData *DetectTlsSubjectParse (const char *str, bool negate) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 @@ -242,21 +245,15 @@ static DetectTlsData *DetectTlsSubjectParse (char *str) ret = pcre_exec(subject_parse_regex, subject_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 3) { + if (ret != 2) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.subject option"); goto error; } - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } - if (str_ptr[0] == '!') + if (negate) flag = DETECT_CONTENT_NEGATED; - pcre_free_substring(str_ptr); - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); + res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -322,7 +319,7 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) return -1; - tls = DetectTlsSubjectParse(str); + tls = DetectTlsSubjectParse(str, s->init_data->negated); if (tls == NULL) goto error; @@ -434,7 +431,7 @@ static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx * \retval id_d pointer to DetectTlsData on success * \retval NULL on failure */ -static DetectTlsData *DetectTlsIssuerDNParse(char *str) +static DetectTlsData *DetectTlsIssuerDNParse(const char *str, bool negate) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 @@ -447,22 +444,15 @@ static DetectTlsData *DetectTlsIssuerDNParse(char *str) ret = pcre_exec(issuerdn_parse_regex, issuerdn_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); - - if (ret != 3) { + if (ret != 2) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.issuerdn option"); goto error; } - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } - if (str_ptr[0] == '!') + if (negate) flag = DETECT_CONTENT_NEGATED; - pcre_free_substring(str_ptr); - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); + res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -529,7 +519,7 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) return -1; - tls = DetectTlsIssuerDNParse(str); + tls = DetectTlsIssuerDNParse(str, s->init_data->negated); if (tls == NULL) goto error; @@ -574,7 +564,7 @@ static void DetectTlsIssuerDNFree(void *ptr) * \retval pointer to DetectTlsData on success * \retval NULL on failure */ -static DetectTlsData *DetectTlsFingerprintParse (char *str) +static DetectTlsData *DetectTlsFingerprintParse (const char *str, bool negate) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 @@ -587,22 +577,15 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) ret = pcre_exec(fingerprint_parse_regex, fingerprint_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); - - if (ret != 3) { + if (ret != 2) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.fingerprint option"); goto error; } - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } - if (str_ptr[0] == '!') + if (negate) flag = DETECT_CONTENT_NEGATED; - pcre_free_substring(str_ptr); - res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); + res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -726,7 +709,7 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) return -1; - tls = DetectTlsFingerprintParse(str); + tls = DetectTlsFingerprintParse(str, s->init_data->negated); if (tls == NULL) goto error; diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index c4518a6515..6da1b6a565 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -73,6 +73,7 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; sigmatch_table[DETECT_URICONTENT].RegisterTests = DetectUricontentRegisterTests; + sigmatch_table[DETECT_URICONTENT].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); } diff --git a/src/detect.h b/src/detect.h index 7752d229a8..8f68e22b07 100644 --- a/src/detect.h +++ b/src/detect.h @@ -360,6 +360,10 @@ typedef struct SignatureInitData_ { /** Number of sigmatches. Used for assigning SigMatch::idx */ uint16_t sm_cnt; + /** option was prefixed with '!'. Only set for sigmatches that + * have the SIGMATCH_HANDLE_NEGATION flag set. */ + bool negated; + /* used to hold flags that are used during init */ uint32_t init_flags; /* coccinelle: SignatureInitData:init_flags:SIG_FLAG_INIT_ */ @@ -1108,7 +1112,18 @@ typedef struct SigGroupHead_ { #define SIGMATCH_NOT_BUILT (1 << 3) /** sigmatch may have options, so the parser should be ready to * deal with both cases */ -#define SIGMATCH_OPTIONAL_OPT (1 << 4) +#define SIGMATCH_OPTIONAL_OPT (1 << 4) +/** input may be wrapped in double quotes. They will be stripped before + * input data is passed to keyword parser */ +#define SIGMATCH_QUOTES_OPTIONAL (1 << 5) +/** input MUST be wrapped in double quotes. They will be stripped before + * input data is passed to keyword parser. Missing double quotes lead to + * error and signature invalidation. */ +#define SIGMATCH_QUOTES_MANDATORY (1 << 6) +/** negation parsing is handled by the rule parser. Signature::init_data::negated + * will be set to true or false prior to calling the keyword parser. Exclamation + * mark is stripped from the input to the keyword parser. */ +#define SIGMATCH_HANDLE_NEGATION (1 << 7) enum DetectEngineTenantSelectors { -- 2.47.2