detect: require both halves of a bidirectional rule before matching

A transactional ('=>') rule keeps the engines of both directions in a
single progress sorted list. While the toserver pass runs it steps over
the toclient engines, and the only thing that kept it from declaring a
full match was

    if (direction == 0 && engine->next == NULL) { break; }

so it worked only when a toclient engine happened to be the last entry.
Engines are sorted by progress across both directions, so a rule whose
toserver buffer has the higher progress value ends with a toserver
engine: the loop steps over the toclient engine, runs the toserver
engine, falls off the end of the list with total_matches set and reports
a full match. The toclient condition is then silently ignored, and the
rule fires on the request alone. For 'http.host' (p2) and 'http.stat_msg'
(p1) the list is

    http_host/toserver/http2/p1 | http_stat_msg/toclient/http2/p0 |
    http_stat_msg/toclient/http/p1 | http_host/toserver/http/p2

and a response of "200 OK" still alerts on a content:"ZZZZZZ" in
http.stat_msg.

Track the skip instead of the list position: remember that an engine of
the other direction was stepped over un-inspected and require that to be
clear before setting DE_STATE_FLAG_FULL_INSPECT. The decision is now the
same for every list layout, and for the layout that already worked (the
toclient engine last) it changes nothing beyond 'engine' being NULL
rather than non-NULL at the end of the loop: neither sets FULL_INSPECT,
and both leave the toserver flags to be stored for the toclient pass,
which appends them for both directions (DetectRunStoreStateTx).

Ticket: #9087.
pull/16325/head
Victor Julien 4 weeks ago
parent bc48b4f44c
commit c4c778035e

@ -1316,6 +1316,7 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx,
uint16_t file_no_match = 0;
bool mpm_before_progress = false; // is mpm engine before progress?
bool mpm_in_progress = false; // is mpm engine in a buffer we will revisit?
bool other_dir_pending = false; // engine of the other direction left to inspect?
TRACE_SID_TXS(s->id, tx, "starting %s", direction ? "toclient" : "toserver");
@ -1478,10 +1479,12 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx,
// for transactional rules, the engines on the opposite direction
// are ordered by progress on the different side
// so we have a two mixed-up lists, and we skip the elements
if (direction == 0 && engine->next == NULL) {
// do not match yet on request only
break;
}
//
// The engine is only inspected in the other direction, so a full
// match must wait for it regardless of where it sits in the list.
// Only reachable while inspecting toserver: in the toclient
// direction the branch above runs the toserver engines as well.
other_dir_pending = true;
engine = engine->next;
continue;
}
@ -1492,7 +1495,7 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx,
inspect_flags, total_matches, engine);
bool full_match = false;
if (engine == NULL && total_matches) {
if (engine == NULL && total_matches && !other_dir_pending) {
inspect_flags |= DE_STATE_FLAG_FULL_INSPECT;
TRACE_SID_TXS(s->id, tx, "MATCH");
full_match = true;

Loading…
Cancel
Save