Skip to content

Commit 2036a86

Browse files
committed
detect/sigorder: resolve flowbit dependencies
before adding them to the Detection Context's signature list. The de_ctx->sig_list serves as a sorted signature list that is later passed on to the grouping fns. If no property of high value changes the order of the signatures, the order coming from de_ctx->sig_list is final. Add the appropriate calls to resolve flowbit dependencies before adding them to the sig_list. This is especially important for flowbits with complex ordering involved. Bug 7771 Bug 7638
1 parent e552e5e commit 2036a86

1 file changed

Lines changed: 218 additions & 6 deletions

File tree

src/detect-engine-sigorder.c

Lines changed: 218 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "action-globals.h"
4141
#include "flow-util.h"
4242
#include "util-validate.h"
43+
#include "rust.h"
4344

4445
#define DETECT_FLOWVAR_NOT_USED 1
4546
#define DETECT_FLOWVAR_TYPE_READ 2
@@ -546,6 +547,13 @@ static int SCSigLessThan(SCSigSignatureWrapper *sw1,
546547

547548
funcs = funcs->next;
548549
}
550+
551+
// Special handling for flowbits, do not touch the order if the comparison fn
552+
// calculates two signatures to be equal
553+
if ((sw1->user[DETECT_SIGORDER_FLOWBITS] > DETECT_FLOWBITS_NOT_USED) &&
554+
(sw1->user[DETECT_SIGORDER_FLOWBITS] == sw2->user[DETECT_SIGORDER_FLOWBITS]))
555+
return 0;
556+
549557
// They are equal, so use sid as the final decider.
550558
return sw1->sig->id < sw2->sig->id;
551559
}
@@ -621,6 +629,113 @@ static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw,
621629
return result;
622630
}
623631

632+
static SCSigSignatureWrapper *SCSigResolveFlowbitDependencies(SCSigSignatureWrapper *arg_sw)
633+
{
634+
uint32_t sig_cnt = 0;
635+
uint32_t *sorted_siids = NULL;
636+
SCSigSignatureWrapper *sw = arg_sw;
637+
638+
void *graph = SCCreateDirectedGraph();
639+
640+
while (sw != NULL) {
641+
Signature *s = sw->sig;
642+
int64_t sidx = SCCreateNodeEdgeDirectedGraph(graph, s->iid, false /* Signature type node */,
643+
false /* does not matter */, UINT32_MAX /* no signature index in graph yet */);
644+
if (sidx < 0) {
645+
goto error;
646+
}
647+
DEBUG_VALIDATE_BUG_ON(sidx > UINT32_MAX);
648+
SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH];
649+
DetectFlowbitsData *fbd = NULL;
650+
int64_t nidx = 0;
651+
652+
while (sm != NULL) {
653+
if (sm->type != DETECT_FLOWBITS) {
654+
sm = sm->next;
655+
continue;
656+
}
657+
fbd = (DetectFlowbitsData *)sm->ctx;
658+
nidx = SCCreateNodeEdgeDirectedGraph(graph, fbd->idx, true /* Flowbit type node */,
659+
false /* READ cmd */, (uint32_t)sidx);
660+
if (nidx < 0) {
661+
goto error;
662+
}
663+
sm = sm->next;
664+
}
665+
666+
sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH];
667+
668+
while (sm != NULL) {
669+
if (sm->type != DETECT_FLOWBITS) {
670+
sm = sm->next;
671+
continue;
672+
}
673+
fbd = (DetectFlowbitsData *)sm->ctx;
674+
nidx = SCCreateNodeEdgeDirectedGraph(graph, fbd->idx, true /* Flowbit type node */,
675+
true /* WRITE cmd */, (uint32_t)sidx);
676+
if (nidx < 0) {
677+
goto error;
678+
}
679+
sm = sm->next;
680+
}
681+
682+
sw = sw->next;
683+
sig_cnt++;
684+
}
685+
686+
DEBUG_VALIDATE_BUG_ON(sig_cnt == 0);
687+
688+
sorted_siids = SCCalloc(sig_cnt, sizeof(uint32_t));
689+
if (sorted_siids == NULL) {
690+
goto error;
691+
}
692+
if (SCResolveFlowbitDependencies(graph, sorted_siids, sig_cnt) < 0) {
693+
goto error;
694+
}
695+
696+
SCSigSignatureWrapper *fin = NULL;
697+
SCSigSignatureWrapper *tmp = NULL;
698+
SCSigSignatureWrapper *prev = NULL;
699+
700+
for (uint32_t i = 0; i < sig_cnt; i++) {
701+
sw = arg_sw;
702+
while (sw != NULL) {
703+
if (sorted_siids[i] == sw->sig->iid) {
704+
if (tmp) {
705+
prev->next = sw->next;
706+
sw->next = NULL;
707+
tmp->next = sw;
708+
} else {
709+
tmp = sw;
710+
fin = tmp;
711+
}
712+
}
713+
prev = sw;
714+
sw = sw->next;
715+
}
716+
}
717+
718+
#ifdef DEBUG
719+
tmp = fin;
720+
while (tmp != NULL) {
721+
SCLogDebug("sid: %d, iid: %d", tmp->sig->id, tmp->sig->iid);
722+
tmp = tmp->next;
723+
}
724+
#endif
725+
726+
SCFree(sorted_siids); /* No longer needed */
727+
SCFreeDirectedGraph(graph);
728+
return fin;
729+
730+
error:
731+
SCLogError("Error resolving flowbit dependencies; rolling back to original order");
732+
if (sorted_siids != NULL) {
733+
SCFree(sorted_siids);
734+
}
735+
SCFreeDirectedGraph(graph);
736+
return arg_sw;
737+
}
738+
624739
/**
625740
* \brief Orders an incoming Signature based on its action
626741
*
@@ -631,6 +746,7 @@ static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw,
631746
static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1,
632747
SCSigSignatureWrapper *sw2)
633748
{
749+
SCLogDebug("Comparing by Action sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
634750
return ActionOrderVal(sw2->sig->action) - ActionOrderVal(sw1->sig->action);
635751
}
636752

@@ -644,6 +760,7 @@ static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1,
644760
static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1,
645761
SCSigSignatureWrapper *sw2)
646762
{
763+
SCLogDebug("Comparing by Flowbits sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
647764
return sw1->user[DETECT_SIGORDER_FLOWBITS] - sw2->user[DETECT_SIGORDER_FLOWBITS];
648765
}
649766

@@ -657,6 +774,7 @@ static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1,
657774
static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1,
658775
SCSigSignatureWrapper *sw2)
659776
{
777+
SCLogDebug("Comparing by Flowvar sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
660778
return sw1->user[DETECT_SIGORDER_FLOWVAR] - sw2->user[DETECT_SIGORDER_FLOWVAR];
661779
}
662780

@@ -670,12 +788,14 @@ static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1,
670788
static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1,
671789
SCSigSignatureWrapper *sw2)
672790
{
791+
SCLogDebug("Comparing by Pktvar sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
673792
return sw1->user[DETECT_SIGORDER_PKTVAR] - sw2->user[DETECT_SIGORDER_PKTVAR];
674793
}
675794

676795
static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1,
677796
SCSigSignatureWrapper *sw2)
678797
{
798+
SCLogDebug("Comparing by Flowint sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
679799
return sw1->user[DETECT_SIGORDER_FLOWINT] - sw2->user[DETECT_SIGORDER_FLOWINT];
680800
}
681801

@@ -689,6 +809,7 @@ static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1,
689809
static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1,
690810
SCSigSignatureWrapper *sw2)
691811
{
812+
SCLogDebug("Comparing by Hostbits sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
692813
return sw1->user[DETECT_SIGORDER_HOSTBITS] - sw2->user[DETECT_SIGORDER_HOSTBITS];
693814
}
694815

@@ -702,6 +823,7 @@ static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1,
702823
static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1,
703824
SCSigSignatureWrapper *sw2)
704825
{
826+
SCLogDebug("Comparing by IPPair sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
705827
return sw1->user[DETECT_SIGORDER_IPPAIRBITS] - sw2->user[DETECT_SIGORDER_IPPAIRBITS];
706828
}
707829

@@ -715,6 +837,7 @@ static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1,
715837
static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1,
716838
SCSigSignatureWrapper *sw2)
717839
{
840+
SCLogDebug("Comparing by Priority sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
718841
if (sw1->sig->prio > sw2->sig->prio) {
719842
return -1;
720843
} else if (sw1->sig->prio < sw2->sig->prio) {
@@ -725,6 +848,7 @@ static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1,
725848

726849
static int SCSigOrderByIId(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2)
727850
{
851+
SCLogDebug("Comparing by IID sid1: %d and sid2: %d", sw1->sig->id, sw2->sig->id);
728852
if (sw1->sig->iid > sw2->sig->iid) {
729853
return -1;
730854
} else if (sw1->sig->iid < sw2->sig->iid) {
@@ -810,12 +934,29 @@ void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
810934

811935
SCLogDebug("ordering signatures in memory");
812936
SCSigSignatureWrapper *sigw = NULL;
813-
SCSigSignatureWrapper *td_sigw_list = NULL; /* unified td list */
937+
SCSigSignatureWrapper *td_sigw_list_start = NULL; /* unified td list */
938+
SCSigSignatureWrapper *td_sigw_list_end = NULL; /* unified td list */
939+
940+
SCSigSignatureWrapper *s_fb_sigw_list_start = NULL; /* SET flowbits */
941+
SCSigSignatureWrapper *r_fb_sigw_list_start = NULL; /* READ flowbits */
942+
SCSigSignatureWrapper *sr_fb_sigw_list_start = NULL; /* SET_READ flowbits */
943+
944+
SCSigSignatureWrapper *s_fb_sigw_list_end = NULL; /* SET flowbits */
945+
// SCSigSignatureWrapper *r_fb_sigw_list_end = NULL; /* READ flowbits */
946+
SCSigSignatureWrapper *sr_fb_sigw_list_end = NULL; /* SET_READ flowbits */
814947

815948
SCSigSignatureWrapper *fw_pf_sigw_list = NULL; /* hook: packet_filter */
816949
SCSigSignatureWrapper *fw_af_sigw_list = NULL; /* hook: app_filter */
817950

818951
Signature *sig = de_ctx->sig_list;
952+
953+
#ifdef DEBUG
954+
SCLogDebug(">>>>>>>>>>>>>>>BEGIN");
955+
for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
956+
SCLogDebug("sid: %d; iid: %d", s->id, s->iid);
957+
}
958+
SCLogDebug(">>>>>>>>>>>>>>>END");
959+
#endif
819960
while (sig != NULL) {
820961
sigw = SCSigAllocSignatureWrapper(sig);
821962
/* Push signature wrapper onto a list, order doesn't matter here. */
@@ -829,8 +970,25 @@ void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
829970
fw_af_sigw_list = sigw;
830971
}
831972
} else {
832-
sigw->next = td_sigw_list;
833-
td_sigw_list = sigw;
973+
if (sigw->user[DETECT_SIGORDER_FLOWBITS] != DETECT_FLOWBITS_NOT_USED) {
974+
if (sigw->user[DETECT_SIGORDER_FLOWBITS] == DETECT_FLOWBITS_TYPE_SET_READ) {
975+
sigw->next = sr_fb_sigw_list_start;
976+
sr_fb_sigw_list_start = sigw;
977+
} else if (sigw->user[DETECT_SIGORDER_FLOWBITS] == DETECT_FLOWBITS_TYPE_READ) {
978+
sigw->next = r_fb_sigw_list_start;
979+
r_fb_sigw_list_start = sigw;
980+
} else if (sigw->user[DETECT_SIGORDER_FLOWBITS] == DETECT_FLOWBITS_TYPE_SET) {
981+
sigw->next = s_fb_sigw_list_start;
982+
if (!s_fb_sigw_list_end)
983+
s_fb_sigw_list_end = sigw;
984+
s_fb_sigw_list_start = sigw;
985+
}
986+
} else {
987+
sigw->next = td_sigw_list_start;
988+
if (!td_sigw_list_end)
989+
td_sigw_list_end = sigw;
990+
td_sigw_list_start = sigw;
991+
}
834992
}
835993
sig = sig->next;
836994
}
@@ -846,10 +1004,64 @@ void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
8461004
SCSigOrderFunc OrderFn = { .SWCompare = SCSigOrderByAppFirewall, .next = NULL };
8471005
fw_af_sigw_list = SCSigOrder(fw_af_sigw_list, &OrderFn);
8481006
}
849-
if (td_sigw_list) {
1007+
if (sr_fb_sigw_list_start) {
1008+
/* Resolve any complex dependencies, if possible, or error out early on */
1009+
sr_fb_sigw_list_start = SCSigResolveFlowbitDependencies(sr_fb_sigw_list_start);
1010+
SCSigSignatureWrapper *tmp = sr_fb_sigw_list_start;
1011+
while (tmp != NULL) {
1012+
sr_fb_sigw_list_end = tmp;
1013+
tmp = tmp->next;
1014+
}
1015+
}
1016+
/* Merge the flowbit lists into the generic thread detection list */
1017+
SCSigSignatureWrapper *tmp = NULL;
1018+
if (s_fb_sigw_list_end) {
1019+
s_fb_sigw_list_end->next = sr_fb_sigw_list_start;
1020+
tmp = s_fb_sigw_list_start;
1021+
}
1022+
if (sr_fb_sigw_list_end) {
1023+
sr_fb_sigw_list_end->next = r_fb_sigw_list_start;
1024+
if (!tmp)
1025+
tmp = sr_fb_sigw_list_start;
1026+
}
1027+
if (r_fb_sigw_list_start) {
1028+
if (!sr_fb_sigw_list_start && s_fb_sigw_list_end)
1029+
s_fb_sigw_list_end->next = r_fb_sigw_list_start;
1030+
if (!tmp)
1031+
tmp = r_fb_sigw_list_start;
1032+
}
1033+
1034+
#ifdef DEBUG
1035+
SCSigSignatureWrapper *tmp2 = tmp;
1036+
SCLogDebug(">>>>>>>>>>>>>>>BEGIN");
1037+
while (tmp2 != NULL) {
1038+
SCLogDebug("tmp sid: %d, iid: %d", tmp2->sig->id, tmp2->sig->iid);
1039+
tmp2 = tmp2->next;
1040+
}
1041+
SCLogDebug(">>>>>>>>>>>>>>>END");
1042+
#endif
1043+
1044+
if (td_sigw_list_end) {
1045+
td_sigw_list_end->next = tmp;
1046+
/* Sort the list */
1047+
td_sigw_list_start = SCSigOrder(td_sigw_list_start, de_ctx->sc_sig_order_funcs);
1048+
} else if (tmp) {
1049+
td_sigw_list_start = tmp;
8501050
/* Sort the list */
851-
td_sigw_list = SCSigOrder(td_sigw_list, de_ctx->sc_sig_order_funcs);
1051+
td_sigw_list_start = SCSigOrder(td_sigw_list_start, de_ctx->sc_sig_order_funcs);
8521052
}
1053+
1054+
#ifdef DEBUG
1055+
SCLogDebug("POST MERGE SORT");
1056+
tmp2 = td_sigw_list_start;
1057+
SCLogDebug(">>>>>>>>>>>>>>>BEGIN");
1058+
while (tmp2 != NULL) {
1059+
SCLogDebug("tmp sid: %d, iid: %d", tmp2->sig->id, tmp2->sig->iid);
1060+
tmp2 = tmp2->next;
1061+
}
1062+
SCLogDebug(">>>>>>>>>>>>>>>END");
1063+
#endif
1064+
8531065
/* Recreate the sig list in order */
8541066
de_ctx->sig_list = NULL;
8551067

@@ -888,7 +1100,7 @@ void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
8881100
SCFree(sigw_to_free);
8891101
}
8901102
/* threat detect list for hook app_td */
891-
for (sigw = td_sigw_list; sigw != NULL;) {
1103+
for (sigw = td_sigw_list_start; sigw != NULL;) {
8921104
sigw->sig->next = NULL;
8931105
if (de_ctx->sig_list == NULL) {
8941106
/* First entry on the list */

0 commit comments

Comments
 (0)