diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 1175743c28..b2b20d08f4 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -662,6 +662,8 @@ has values which can be managed by the user. grouping: tcp-priority-ports: 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080 udp-priority-ports: 53, 135, 5060 + flowbits: + max-per-signature: 8 At all of these options, you can add (or change) a value. Most signatures have the adjustment to focus on one direction, meaning @@ -714,6 +716,11 @@ The engine shall then try to club the rules that use the ports defined in groups of their own and put them on top of the list of rules to be matched against traffic on "priority". +The ``flowbits`` option carries flowbits detection specific settings. With +``max-per-signature`` setting, it is possible to define how many times flowbits +keyword can be seen in any one signature. This does not include ``flowbits:noalert;``. +Minimum value allowed is 1 and the default is 8. + *Example 4 Detection-engine grouping tree* .. image:: suricata-yaml/grouping_tree.png diff --git a/src/detect-engine.c b/src/detect-engine.c index f44b57f00f..237372db84 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -95,6 +95,8 @@ #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000 +#define DEFAULT_MAX_FLOWBITS_PER_SIGNATURE 8 + static int DetectEngineCtxLoadConf(DetectEngineCtx *); static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, @@ -2369,6 +2371,34 @@ static void InjectPackets( } } +static void DetectEngineLoadFlowbitSettings(DetectEngineCtx *de_ctx) +{ + de_ctx->max_flowbits = DEFAULT_MAX_FLOWBITS_PER_SIGNATURE; + char varname[128] = "detect.flowbits.max-per-signature"; + if (strlen(de_ctx->config_prefix) > 0) { + snprintf(varname, sizeof(varname), "%s.detect.flowbits.max-per-signature", + de_ctx->config_prefix); + } + const char *str; + if (SCConfGet(varname, &str) == 1) { + uint8_t val = 0; + int ret = StringParseUint8(&val, 10, 0, str); + if (ret > 0) { + if (val > 0) { + de_ctx->max_flowbits = val; + } else { + SCLogWarning("Invalid setting for flowbits.max-per-signature %d, resetting to the " + "default", + val); + } + } else { + SCLogWarning( + "Invalid setting for flowbits.max-per-signature, resetting to the default"); + } + } + SCLogConfig("Setting flowbits.max-per-signature to %d", de_ctx->max_flowbits); +} + /** \internal * \brief Update detect threads with new detect engine * @@ -3158,6 +3188,8 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } } + DetectEngineLoadFlowbitSettings(de_ctx); + de_ctx->prefilter_setting = DETECT_PREFILTER_MPM; const char *pf_setting = NULL; if (SCConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) { @@ -4088,7 +4120,6 @@ static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *fil SCLogError("Loading signatures failed."); goto error; } - DetectEngineAddToMaster(de_ctx); return 0; @@ -4998,6 +5029,7 @@ int DetectEngineReload(const SCInstance *suri) DetectEngineDeReference(&old_de_ctx); return -1; } + if (SigLoadSignatures(new_de_ctx, suri->sig_file, suri->sig_file_exclusive) != 0) { DetectEngineCtxFree(new_de_ctx); diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index c0060f35e1..a9671f9bbe 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -450,6 +450,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst DETECT_SM_LIST_MATCH) == NULL) { goto error; } + s->init_data->total_flowbits++; break; case DETECT_FLOWBITS_CMD_SET: @@ -459,6 +460,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst DETECT_SM_LIST_POSTMATCH) == NULL) { goto error; } + s->init_data->total_flowbits++; break; // suppress coverity warning as scan-build-7 warns w/o this. diff --git a/src/detect-parse.c b/src/detect-parse.c index 404811de79..2bcff76f07 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -2940,6 +2940,19 @@ static bool SigValidateProtoPkthdr(const Signature *s) return true; } +static bool SigValidateFlowbitUse(DetectEngineCtx *de_ctx, const Signature *s) +{ + DEBUG_VALIDATE_BUG_ON(de_ctx->max_flowbits == 0); + + if (s->init_data->total_flowbits > de_ctx->max_flowbits) { + SCLogError( + "rule %u: too many flowbits (max %u per signature)", s->id, de_ctx->max_flowbits); + return false; + } + + return true; +} + /** * \internal * \brief validate and consolidate parsed signature @@ -2987,6 +3000,10 @@ static int SigValidateConsolidate( SCReturnInt(0); } + if (!SigValidateFlowbitUse(de_ctx, s)) { + SCReturnInt(0); + } + if (DetectProtoFinalizeSignature(s) != 0) SCReturnInt(0); diff --git a/src/detect.h b/src/detect.h index db5c692d72..285d8ee65e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -632,6 +632,10 @@ typedef struct SignatureInitData_ { int list; bool list_set; + /* Total number of times flowbits keyword is referenced in this signature (flowbits:noalert; not + * included) */ + uint16_t total_flowbits; + DetectEngineTransforms transforms; /** rule protocol settings */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 876dcf93e6..6ce30560aa 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1895,6 +1895,9 @@ detect: include-rules: false # very verbose include-mpm-stats: false + flowbits: + max-per-signature: 8 # maximum number of flowbits keyword usage per signature, minimum value allowed is 1 + # Select the multi pattern algorithm you want to run for scan/search the # in the engine. #