]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
firewall: apply action again for stateful matches
authorVictor Julien <vjulien@oisf.net>
Tue, 29 Apr 2025 12:45:47 +0000 (14:45 +0200)
committerVictor Julien <victor@inliniac.net>
Sat, 3 May 2025 06:19:39 +0000 (08:19 +0200)
For "stateful rules", don't drop packets after the initial match as long
as the tx state doesn't change.

An example of how this could happen was:

        accept:hook ssh:request_started any any -> any any (alert; sid:2000;)
        accept:hook ssh:request_banner_wait_eol any any -> any any (alert; sid:2001;)
        accept:hook ssh:request_banner_done any any -> any any (        \
                ssh.software; content:"OpenSSH_8.2p1"; alert; sid:2002;)

As the ssh session reached the request_banner_done state, it would
remain in this state. So additional packets would again review the rules
for this state. The rule 2002 is stored in the tx state as fully
matched, and would be skipped for the additional packets. This meant
that the `accept:hook` action was not applied and the default drop
policy was triggered.

This is addressed by updating the stateful logic:

If an accept rule has the DE_STATE_FLAG_FULL_INSPECT flag set, and the
tx progress is not progressed beyond the rule, apply the rule accept
acction.

src/detect.c

index 3f83aab01d8c5a9e4afc46a14ae533916d635027..ffa1ee09cdec0804b63b563d7d4b05295cca2362 100644 (file)
@@ -1867,8 +1867,29 @@ static void DetectRunTx(ThreadVars *tv,
                     tx.tx_ptr, tx.tx_id, s->id, s->num, inspect_flags ? *inspect_flags : 0);
 
             if (inspect_flags) {
-                if (*inspect_flags & (DE_STATE_FLAG_FULL_INSPECT|DE_STATE_FLAG_SIG_CANT_MATCH)) {
-                    SCLogDebug("%p/%"PRIu64" inspecting: sid %u (%u), flags %08x ALREADY COMPLETE",
+                if (*inspect_flags & DE_STATE_FLAG_FULL_INSPECT) {
+                    SCLogDebug("%p/%" PRIu64
+                               " inspecting: sid %u (%u), flags %08x DE_STATE_FLAG_FULL_INSPECT",
+                            tx.tx_ptr, tx.tx_id, s->id, s->num, *inspect_flags);
+
+                    /* if we're still in the same progress state as an earlier full
+                     * match, we need to apply the same accept */
+                    if (have_fw_rules && (s->flags & SIG_FLAG_FIREWALL) &&
+                            (s->action & ACTION_ACCEPT) && s->app_progress_hook == tx.tx_progress) {
+                        const bool fw_accept_to_packet = ApplyAcceptToPacket(total_txs, &tx, s);
+                        break_out_of_app_filter = ApplyAccept(p, flow_flags, s, &tx, tx_end_state,
+                                fw_next_progress_missing, &tx_fw_verdict, &skip_fw_hook,
+                                &skip_before_progress);
+                        if (fw_accept_to_packet)
+                            DetectRunAppendDefaultAccept(det_ctx, p);
+                        if (break_out_of_app_filter)
+                            break;
+                    }
+                    continue;
+                }
+                if (*inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
+                    SCLogDebug("%p/%" PRIu64
+                               " inspecting: sid %u (%u), flags %08x DE_STATE_FLAG_SIG_CANT_MATCH",
                             tx.tx_ptr, tx.tx_id, s->id, s->num, *inspect_flags);
                     continue;
                 }