From 884a327117b88ab660347a89fb681bc04610e895 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 28 Oct 2022 07:37:55 +0200 Subject: [PATCH] detect/dataset: delay set operation after signature full match The set operation of dataset keyword was done even if signature did not fully match. This patch changes the behavior of the dataset keyword to do a match and a post match for the set operation. The postmatch retrieves the data and set it in the buffer. Increases postmatch capability to do applayertxmatch, and this get the data from a tx buffer. Ticket: #5576 --- src/detect-dataset.c | 105 ++++++++++++++++++++++++++++++++++++------- src/detect-dataset.h | 2 + src/detect.c | 15 ++++--- 3 files changed, 101 insertions(+), 21 deletions(-) diff --git a/src/detect-dataset.c b/src/detect-dataset.c index 1fc145267fd3..7c496d098444 100644 --- a/src/detect-dataset.c +++ b/src/detect-dataset.c @@ -34,6 +34,7 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" #include "util-debug.h" #include "util-print.h" @@ -41,11 +42,74 @@ #include "util-path.h" #include "util-conf.h" -int DetectDatasetMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); static int DetectDatasetSetup (DetectEngineCtx *, Signature *, const char *); void DetectDatasetFree (DetectEngineCtx *, void *); +static int DetectDatasetTxMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectDatasetData *sd = (DetectDatasetData *)ctx; + // This is only run for DETECT_SM_LIST_POSTMATCH + DEBUG_VALIDATE_BUG_ON(sd->cmd != DETECT_DATASET_CMD_SET); + + DetectEngineAppInspectionEngine *a = s->app_inspect; + while (a != NULL) { + if (a->sm_list == sd->list && a->alproto == f->alproto) { + if (a->v2.Callback == DetectEngineInspectBufferGeneric) { + const InspectionBuffer *buffer = + a->v2.GetData(det_ctx, a->v2.transforms, f, flags, txv, sd->list); + if (buffer != NULL && buffer->inspect != NULL) { + DatasetAdd(sd->set, buffer->inspect, buffer->inspect_len); + } + } else if (a->v2.Callback == DetectEngineInspectMultiBufferGeneric) { + uint32_t local_id = 0; + while (1) { + InspectionBuffer *buffer = a->v2.GetMultiData( + det_ctx, a->v2.transforms, f, flags, txv, sd->list, local_id); + if (buffer == NULL || buffer->inspect == NULL) + break; + const bool match = + DetectEngineContentInspectionBuffer(det_ctx->de_ctx, det_ctx, s, a->smd, + NULL, f, buffer, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + // only add the ones that match other content + DatasetAdd(sd->set, buffer->inspect, buffer->inspect_len); + } + local_id++; + } + } + return 0; + } + a = a->next; + } + return 0; +} + +static int DetectDatasetMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectDatasetData *sd = (DetectDatasetData *)ctx; + // This is only run for DETECT_SM_LIST_POSTMATCH + DEBUG_VALIDATE_BUG_ON(sd->cmd != DETECT_DATASET_CMD_SET); + + DetectEnginePktInspectionEngine *e = s->pkt_inspect; + while (e) { + if (e->sm_list == sd->list) { + if (e->v1.Callback == DetectEngineInspectPktBufferGeneric) { + const InspectionBuffer *buffer = + e->v1.GetData(det_ctx, e->v1.transforms, p, sd->list); + if (buffer != NULL && buffer->inspect != NULL) { + DatasetAdd(sd->set, buffer->inspect, buffer->inspect_len); + } + } + return 0; + } + e = e->next; + } + // return value is unused for postmatch functions + return 0; +} + void DetectDatasetRegister (void) { sigmatch_table[DETECT_DATASET].name = "dataset"; @@ -53,6 +117,8 @@ void DetectDatasetRegister (void) sigmatch_table[DETECT_DATASET].url = "/rules/dataset-keywords.html#dataset"; sigmatch_table[DETECT_DATASET].Setup = DetectDatasetSetup; sigmatch_table[DETECT_DATASET].Free = DetectDatasetFree; + sigmatch_table[DETECT_DATASET].AppLayerTxMatch = DetectDatasetTxMatch; + sigmatch_table[DETECT_DATASET].Match = DetectDatasetMatch; } /* @@ -67,29 +133,25 @@ int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, if (data == NULL || data_len == 0) return 0; + int r = DatasetLookup(sd->set, data, data_len); + SCLogDebug("r %d", r); switch (sd->cmd) { case DETECT_DATASET_CMD_ISSET: { - //PrintRawDataFp(stdout, data, data_len); - int r = DatasetLookup(sd->set, data, data_len); - SCLogDebug("r %d", r); if (r == 1) return 1; break; } case DETECT_DATASET_CMD_ISNOTSET: { - //PrintRawDataFp(stdout, data, data_len); - int r = DatasetLookup(sd->set, data, data_len); - SCLogDebug("r %d", r); if (r < 1) return 1; break; } case DETECT_DATASET_CMD_SET: { - //PrintRawDataFp(stdout, data, data_len); - int r = DatasetAdd(sd->set, data, data_len); - if (r == 1) - return 1; - break; + if (r == 1) { + /* Do not match if data is already in set */ + return 0; + } + return 1; } default: abort(); @@ -416,8 +478,21 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst SCLogDebug("cmd %s, name %s", cmd_str, strlen(name) ? name : "(none)"); - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ + if (cmd == DETECT_DATASET_CMD_SET) { + // for set operation, we need one match, and one postmatch + DetectDatasetData *scd = SCCalloc(1, sizeof(DetectDatasetData)); + if (unlikely(scd == NULL)) + goto error; + + scd->set = set; + scd->cmd = cmd; + scd->list = list; + if (SigMatchAppendSMToList(de_ctx, s, DETECT_DATASET, (SigMatchCtx *)scd, + DETECT_SM_LIST_POSTMATCH) == NULL) { + SCFree(scd); + goto error; + } + } if (SigMatchAppendSMToList(de_ctx, s, DETECT_DATASET, (SigMatchCtx *)cd, list) == NULL) { goto error; diff --git a/src/detect-dataset.h b/src/detect-dataset.h index 4dae4a4a1715..72bc196d1bee 100644 --- a/src/detect-dataset.h +++ b/src/detect-dataset.h @@ -34,6 +34,8 @@ typedef struct DetectDatasetData_ { Dataset *set; uint8_t cmd; + // for postmatch to retrieve the buffer + int list; } DetectDatasetData; int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, diff --git a/src/detect.c b/src/detect.c index 70612516fbd3..7f6ff14f7374 100644 --- a/src/detect.c +++ b/src/detect.c @@ -188,9 +188,8 @@ static void DetectRun(ThreadVars *th_v, SCReturn; } -static void DetectRunPostMatch(ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s) +static void DetectRunPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv) { /* run the packet match functions */ const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; @@ -201,6 +200,10 @@ static void DetectRunPostMatch(ThreadVars *tv, while (1) { KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].AppLayerTxMatch != NULL) { + sigmatch_table[smd->type].AppLayerTxMatch( + det_ctx, f, flags, alstate, txv, s, smd->ctx); + } (void)sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx); KEYWORD_PROFILING_END(det_ctx, smd->type, 1); if (smd->is_last) @@ -811,7 +814,7 @@ static inline void DetectRulePacketRules( #ifdef PROFILE_RULES smatch = true; #endif - DetectRunPostMatch(tv, det_ctx, p, s); + DetectRunPostMatch(tv, det_ctx, p, s, NULL, 0, NULL, NULL); uint64_t txid = PACKET_ALERT_NOTX; if ((alert_flags & PACKET_ALERT_FLAG_STREAM_MATCH) || @@ -1594,7 +1597,7 @@ static void DetectRunTx(ThreadVars *tv, alstate, &tx, s, inspect_flags, can, scratch); if (r == 1) { /* match */ - DetectRunPostMatch(tv, det_ctx, p, s); + DetectRunPostMatch(tv, det_ctx, p, s, f, flow_flags, alstate, tx.tx_ptr); const uint8_t alert_flags = (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_TX); SCLogDebug("%p/%"PRIu64" sig %u (%u) matched", tx.tx_ptr, tx.tx_id, s->id, s->num); @@ -1753,7 +1756,7 @@ static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin r = DetectRunFrameInspectRule(tv, det_ctx, s, f, p, frames, frame); if (r == true) { /* match */ - DetectRunPostMatch(tv, det_ctx, p, s); + DetectRunPostMatch(tv, det_ctx, p, s, NULL, 0, NULL, NULL); uint8_t alert_flags = (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_FRAME); det_ctx->frame_id = frame->id;