Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [PATCH net] netfilter: nf_reject: validate TCP header length before sending resets
@ 2026-11-02 15:56 zhangmh25
  2026-11-02 22:28 ` Pablo Neira Ayuso
  2026-11-03 15:57 ` netdev-bot+sashiko
  0 siblings, 2 replies; 3+ messages in thread
From: zhangmh25 @ 2026-11-02 15:56 UTC (permalink / raw)
  To: netfilter-devel; +Cc: netdev, pablo, coreteam, stable, zhangmh25, jianjun

From: Minghao Zhang <zhangmh25@mails.tsinghua.edu.cn>

The TCP header validation in both nf_reject_ip_tcphdr_get() and
nf_reject_ip6_tcphdr_get() checks that the TCP segment is at least
sizeof(struct tcphdr) long, but does not verify that the header
length claimed via the data offset is actually present in the packet.
A peer can send a TCP packet claiming a 60-byte header although only
the fixed 20-byte header is present.

The reset generation then computes the ACK number using the claimed
header length, and the subtraction of the data offset from the TCP
segment length underflows, producing a wrapped ACK value in the
generated RST. For a 20-byte segment with doff = 15, ACK bit clear,
sequence number 0, SYN and FIN clear, the RST carries ack_seq
0xffffffd8 instead of a meaningful value.

Reject TCP headers whose data offset is smaller than the fixed header
or exceeds the available TCP segment length. This prevents generating
resets with an ACK number derived from an invalid TCP header length.

Found during a systematic audit of TCP header validation in the
netfilter reject paths. Tested in network namespaces with nftables
"reject with tcp reset" rules: on both IPv4 and IPv6, a probe with
doff = 15 produced an RST with a wrapped ack_seq; with the fix no
RST is generated for such packets, while probes with well-formed
headers still get a correct RST.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Fixes: 764d8a9f2407 ("[NETFILTER]: Add IPv6 REJECT target")
Reported-by: Minghao Zhang <zhangmh25@mails.tsinghua.edu.cn>
Reported-by: Jianjun Chen <jianjun@tsinghua.edu.cn>
Cc: stable@vger.kernel.org
Signed-off-by: Minghao Zhang <zhangmh25@mails.tsinghua.edu.cn>
---
 net/ipv4/netfilter/nf_reject_ipv4.c | 5 +++++
 net/ipv6/netfilter/nf_reject_ipv6.c | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
index 59ec465a9..0e8823a7d 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -189,6 +189,11 @@ nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
 	if (oth == NULL)
 		return NULL;
 
+	/* Reject invalid or truncated TCP headers. */
+	if (oth->doff < sizeof(struct tcphdr) / 4 ||
+	    oldskb->len - ip_hdrlen(oldskb) < (oth->doff << 2))
+		return NULL;
+
 	/* No RST for RST. */
 	if (oth->rst)
 		return NULL;
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
index 07cdaa10d..9dc112e50 100644
--- a/net/ipv6/netfilter/nf_reject_ipv6.c
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -223,6 +223,11 @@ nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
 	if (otcph == NULL)
 		return NULL;
 
+	/* Reject invalid or truncated TCP headers. */
+	if (otcph->doff < sizeof(struct tcphdr) / 4 ||
+	    *otcplen < (otcph->doff << 2))
+		return NULL;
+
 	/* No RST for RST. */
 	if (otcph->rst) {
 		pr_debug("RST is set\n");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-03 15:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 15:56 [PATCH net] netfilter: nf_reject: validate TCP header length before sending resets zhangmh25
2026-11-02 22:28 ` Pablo Neira Ayuso
2026-11-03 15:57 ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox