]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: conntrack: tcp: do not force CLOSE on invalid-seq RST without direction...
authorHamza Mahfooz <hamzamahfooz@linux.microsoft.com>
Mon, 11 May 2026 14:43:14 +0000 (10:43 -0400)
committerFlorian Westphal <fw@strlen.de>
Fri, 22 May 2026 10:27:55 +0000 (12:27 +0200)
An unintended behavior in the TCP conntrack state machine allows a
connection to be forced into the CLOSE state using an RST packet with an
invalid sequence number.

Specifically, after a SYN packet is observed, an RST with an invalid SEQ
can transition the conntrack entry to TCP_CONNTRACK_CLOSE, regardless of
whether the RST corresponds to the expected reply direction. The relevant
code path assumes the RST is a response to an outgoing SYN, but does not
validate packet direction or ensure that a matching SYN was actually sent
in the opposite direction.

As a result, a crafted packet sequence consisting of a SYN followed by an
invalid-sequence RST can prematurely terminate an active NAT entry. This
makes connection teardown easier than intended.

So, tighten the state transition logic to ensure that RST-triggered
CLOSE transitions only occur when the RST is a valid response to a
previously observed SYN in the correct direction.

Cc: stable@vger.kernel.org
Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.")
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
net/netfilter/nf_conntrack_proto_tcp.c

index b67426c2189b2d8a02e7caa26e848b539379a8cd..e99ab1e88e9f8ff3aa3b4f1eaf8e70a20dc6b8da 100644 (file)
@@ -1221,7 +1221,8 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
                        new_state = old_state;
                }
                if (((test_bit(IPS_SEEN_REPLY_BIT, &ct->status)
-                        && ct->proto.tcp.last_index == TCP_SYN_SET)
+                        && ct->proto.tcp.last_index == TCP_SYN_SET
+                        && ct->proto.tcp.last_dir != dir)
                        || (!test_bit(IPS_ASSURED_BIT, &ct->status)
                            && ct->proto.tcp.last_index == TCP_ACK_SET))
                    && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {