Skip to content

Commit

Permalink
detect/dataset: delay set operation after signature full match
Browse files Browse the repository at this point in the history
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: OISF#5576
  • Loading branch information
regit authored and catenacyber committed Sep 3, 2024
1 parent 685baa9 commit 884a327
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 21 deletions.
105 changes: 90 additions & 15 deletions src/detect-dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,91 @@
#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"
#include "util-misc.h"
#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";
sigmatch_table[DETECT_DATASET].desc = "match sticky buffer against datasets (experimental)";
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;
}

/*
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/detect-dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 9 additions & 6 deletions src/detect.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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)
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 884a327

Please sign in to comment.