From: Victor Julien Date: Sun, 6 Aug 2023 07:40:37 +0000 (+0200) Subject: threshold: fix multi-tenant file parsing X-Git-Tag: suricata-7.0.1~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f052b524bc0b91e80da46af2ecccffe7a5fdfcf2;p=thirdparty%2Fsuricata.git threshold: fix multi-tenant file parsing Switch to DetectParseRegex and use a local pcre2_match_data to avoid concurrency issues. Bug: #6247. --- diff --git a/src/suricata.c b/src/suricata.c index ccf37c3881..d436b0ba7d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -409,7 +409,6 @@ static void GlobalsDestroy(SCInstance *suri) LuajitFreeStatesPool(); #endif DetectParseFreeRegexes(); - SCThresholdConfGlobalFree(); SCPidfileRemove(suri->pid_filename); SCFree(suri->pid_filename); diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index f8593c9ea3..f19e8108d7 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation +/* Copyright (C) 2007-2023 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -90,104 +90,30 @@ static FILE *g_ut_threshold_fp = NULL; #define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config" #endif -static pcre2_code *regex_base = NULL; -static pcre2_match_data *regex_base_match = NULL; - -static pcre2_code *regex_threshold = NULL; -static pcre2_match_data *regex_threshold_match = NULL; - -static pcre2_code *regex_rate = NULL; -static pcre2_match_data *regex_rate_match = NULL; - -static pcre2_code *regex_suppress = NULL; -static pcre2_match_data *regex_suppress_match = NULL; +static DetectParseRegex *regex_base = NULL; +static DetectParseRegex *regex_threshold = NULL; +static DetectParseRegex *regex_rate = NULL; +static DetectParseRegex *regex_suppress = NULL; static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd); void SCThresholdConfGlobalInit(void) { - int en; - PCRE2_SIZE eo; - int opts = 0; - PCRE2_UCHAR errbuffer[256]; - - regex_base = pcre2_compile( - (PCRE2_SPTR8)DETECT_BASE_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + regex_base = DetectSetupPCRE2(DETECT_BASE_REGEX, 0); if (regex_base == NULL) { - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - FatalError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - DETECT_BASE_REGEX, (int)eo, errbuffer); + FatalError("classification base regex setup failed"); } - regex_base_match = pcre2_match_data_create_from_pattern(regex_base, NULL); - - regex_threshold = pcre2_compile( - (PCRE2_SPTR8)DETECT_THRESHOLD_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + regex_threshold = DetectSetupPCRE2(DETECT_THRESHOLD_REGEX, 0); if (regex_threshold == NULL) { - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - FatalError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - DETECT_THRESHOLD_REGEX, (int)eo, errbuffer); + FatalError("classification threshold regex setup failed"); } - regex_threshold_match = pcre2_match_data_create_from_pattern(regex_threshold, NULL); - - regex_rate = pcre2_compile( - (PCRE2_SPTR8)DETECT_RATE_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + regex_rate = DetectSetupPCRE2(DETECT_RATE_REGEX, 0); if (regex_rate == NULL) { - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - FatalError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - DETECT_RATE_REGEX, (int)eo, errbuffer); + FatalError("classification rate_filter regex setup failed"); } - regex_rate_match = pcre2_match_data_create_from_pattern(regex_rate, NULL); - - regex_suppress = pcre2_compile( - (PCRE2_SPTR8)DETECT_SUPPRESS_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + regex_suppress = DetectSetupPCRE2(DETECT_SUPPRESS_REGEX, 0); if (regex_suppress == NULL) { - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - FatalError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - DETECT_SUPPRESS_REGEX, (int)eo, errbuffer); - } - regex_suppress_match = pcre2_match_data_create_from_pattern(regex_suppress, NULL); -} - -void SCThresholdConfGlobalFree(void) -{ - if (regex_base != NULL) { - pcre2_code_free(regex_base); - regex_base = NULL; - } - if (regex_base_match != NULL) { - pcre2_match_data_free(regex_base_match); - regex_base_match = NULL; - } - - if (regex_threshold != NULL) { - pcre2_code_free(regex_threshold); - regex_threshold = NULL; - } - if (regex_threshold_match != NULL) { - pcre2_match_data_free(regex_threshold_match); - regex_threshold_match = NULL; - } - - if (regex_rate != NULL) { - pcre2_code_free(regex_rate); - regex_rate = NULL; - } - if (regex_rate_match != NULL) { - pcre2_match_data_free(regex_rate_match); - regex_rate_match = NULL; - } - - if (regex_suppress != NULL) { - pcre2_code_free(regex_suppress); - regex_suppress = NULL; - } - if (regex_suppress_match != NULL) { - pcre2_match_data_free(regex_suppress_match); - regex_suppress_match = NULL; + FatalError("classification suppress regex setup failed"); } } @@ -661,10 +587,11 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 if (de_ctx == NULL) return -1; - ret = pcre2_match( - regex_base, (PCRE2_SPTR8)rawstr, strlen(rawstr), 0, 0, regex_base_match, NULL); + pcre2_match_data *regex_base_match = NULL; + ret = DetectParsePcreExec(regex_base, ®ex_base_match, rawstr, 0, 0); if (ret < 4) { SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rawstr); + pcre2_match_data_free(regex_base_match); goto error; } @@ -674,6 +601,7 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 regex_base_match, 1, (PCRE2_UCHAR8 *)th_rule_type, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); goto error; } @@ -682,6 +610,7 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 ret = pcre2_substring_copy_bynumber(regex_base_match, 2, (PCRE2_UCHAR8 *)th_gid, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); goto error; } @@ -689,6 +618,7 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 ret = pcre2_substring_copy_bynumber(regex_base_match, 3, (PCRE2_UCHAR8 *)th_sid, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); goto error; } @@ -697,8 +627,11 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 regex_base_match, 4, (PCRE2_UCHAR8 **)&rule_extend, ©len); if (ret < 0) { SCLogError("pcre2_substring_get_bynumber failed"); + pcre2_match_data_free(regex_base_match); goto error; } + pcre2_match_data_free(regex_base_match); + regex_base_match = NULL; /* get type of rule */ if (strcasecmp(th_rule_type,"event_filter") == 0) { @@ -719,45 +652,48 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 case THRESHOLD_TYPE_EVENT_FILTER: case THRESHOLD_TYPE_THRESHOLD: if (strlen(rule_extend) > 0) { - ret = pcre2_match(regex_threshold, (PCRE2_SPTR8)rule_extend, strlen(rule_extend), 0, - 0, regex_threshold_match, NULL); + pcre2_match_data *match = NULL; + + ret = DetectParsePcreExec(regex_threshold, &match, rule_extend, 0, 0); if (ret < 4) { SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rule_extend); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_type); - ret = pcre2_substring_copy_bynumber( - regex_threshold_match, 1, (PCRE2_UCHAR8 *)th_type, ©len); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_type, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_track); - ret = pcre2_substring_copy_bynumber( - regex_threshold_match, 2, (PCRE2_UCHAR8 *)th_track, ©len); + ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_track, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_count); - ret = pcre2_substring_copy_bynumber( - regex_threshold_match, 3, (PCRE2_UCHAR8 *)th_count, ©len); + ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_count, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber( - regex_threshold_match, 4, (PCRE2_UCHAR8 *)th_seconds, ©len); + ret = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)th_seconds, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } + pcre2_match_data_free(match); if (strcasecmp(th_type,"limit") == 0) parsed_type = TYPE_LIMIT; @@ -776,28 +712,30 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 break; case THRESHOLD_TYPE_SUPPRESS: if (strlen(rule_extend) > 0) { - ret = pcre2_match(regex_suppress, (PCRE2_SPTR8)rule_extend, strlen(rule_extend), 0, - 0, regex_suppress_match, NULL); + pcre2_match_data *match = NULL; + ret = DetectParsePcreExec(regex_suppress, &match, rule_extend, 0, 0); if (ret < 2) { SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rule_extend); + pcre2_match_data_free(match); goto error; } /* retrieve the track mode */ copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber( - regex_suppress_match, 1, (PCRE2_UCHAR8 *)th_track, ©len); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } /* retrieve the IP; use "get" for heap allocation */ - ret = pcre2_substring_get_bynumber( - regex_suppress_match, 2, (PCRE2_UCHAR8 **)&th_ip, ©len); + ret = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&th_ip, ©len); if (ret < 0) { SCLogError("pcre2_substring_get_bynumber failed"); + pcre2_match_data_free(match); goto error; } + pcre2_match_data_free(match); } else { parsed_track = TRACK_RULE; } @@ -805,53 +743,56 @@ static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint3 break; case THRESHOLD_TYPE_RATE: if (strlen(rule_extend) > 0) { - ret = pcre2_match(regex_rate, (PCRE2_SPTR8)rule_extend, strlen(rule_extend), 0, 0, - regex_rate_match, NULL); + pcre2_match_data *match = NULL; + ret = DetectParsePcreExec(regex_rate, &match, rule_extend, 0, 0); if (ret < 5) { SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rule_extend); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_track); - ret = pcre2_substring_copy_bynumber( - regex_rate_match, 1, (PCRE2_UCHAR8 *)th_track, ©len); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_count); - ret = pcre2_substring_copy_bynumber( - regex_rate_match, 2, (PCRE2_UCHAR8 *)th_count, ©len); + ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_count, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber( - regex_rate_match, 3, (PCRE2_UCHAR8 *)th_seconds, ©len); + ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_seconds, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_new_action); ret = pcre2_substring_copy_bynumber( - regex_rate_match, 4, (PCRE2_UCHAR8 *)th_new_action, ©len); + match, 4, (PCRE2_UCHAR8 *)th_new_action, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } copylen = sizeof(th_timeout); - ret = pcre2_substring_copy_bynumber( - regex_rate_match, 5, (PCRE2_UCHAR8 *)th_timeout, ©len); + ret = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)th_timeout, ©len); if (ret < 0) { SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); goto error; } + pcre2_match_data_free(match); /* TODO: implement option "apply_to" */ diff --git a/src/util-threshold-config.h b/src/util-threshold-config.h index 982bf3e1c9..ff0eadcf31 100644 --- a/src/util-threshold-config.h +++ b/src/util-threshold-config.h @@ -30,6 +30,5 @@ int SCThresholdConfInitContext(DetectEngineCtx *); void SCThresholdConfRegisterTests(void); void SCThresholdConfGlobalInit(void); -void SCThresholdConfGlobalFree(void); #endif /* __UTIL_THRESHOLD_CONFIG_H__ */