From 59d08a717e0529e54cad81fd138ee2d545213f63 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Sep 2026 07:35:23 +0000 Subject: [PATCH] detect: make the completion state final at the end state eof is C > P, so an engine registered at a parser's completion state never becomes complete: there is no next state to enter. A firewall rule hooking such a state (e.g. tls:client_finished) stayed pending forever and was optimistically accepted. Treat progress == engine progress == tx end state as complete. This also finalizes the buffer engines' eof on completion-state buffers, so absent and bsize decisions now happen there, and it covers every parser whose engine progress equals its completion state (dns, ntp, quic, rdp-style two-state protocols), not only the firewall path that motivated the change. Ticket: #8944. --- src/detect-engine.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 39715e8119..d99b220eef 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2186,7 +2186,30 @@ static bool DetectTxCompleted( // the DNS tx from DetectGetInnerTx is always complete return true; } // else - return AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress; + const int progress = AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags); + if (progress < 0) { + return false; + } + if (progress > engine->progress) { + return true; + } + if (progress < engine->progress) { + return false; + } + /* An engine registered at the completion state has no P + 1; its data is + * final once the tx reached that state. For the buffer engines this is the + * engine's eof, so absent/bsize are decided; for the firewall checks it is + * the point where the verdict can no longer change. + * AppLayerParserGetStateProgress() returns the end progress for disrupted + * flows, so progress == end stays a valid finality signal there. */ + const AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, txv); + uint8_t tx_end_state; + if (txd != NULL && txd->tx_type != 0) { + tx_end_state = (flags & STREAM_TOSERVER) ? txd->tx_type_eop_ts : txd->tx_type_eop_tc; + } else { + tx_end_state = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); + } + return progress == tx_end_state; } /**