* [PATCH net v3] ipv6: fix dead half of the MTU guard in __ip6_append_data()
@ 2026-10-30 8:48 bo cao
2026-10-30 8:53 ` netdev-bot+sinfo
0 siblings, 1 reply; 3+ messages in thread
From: bo cao @ 2026-10-30 8:48 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, pabeni, dsahern, edumazet, idosch, horms, stable,
linux-kernel
The second half of the MTU guard in __ip6_append_data() has been dead
code since the initial git import:
if (mtu <= fragheaderlen ||
((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr))
goto emsgsize;
(x & ~7) is unsigned and >= 0, and fragheaderlen is at least
sizeof(struct ipv6hdr) = 40 > sizeof(struct frag_hdr) = 8, so the
second condition can never be true.
For mtu - fragheaderlen in [1,7], (x & ~7) == 0, so
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - 8
underflows below fragheaderlen. Every later bound computed as
maxfraglen - fragheaderlen then wraps to 0xfffffff8, in particular the
datalen clamp inside the fragment loop, which never fires and lets
fraglen = datalen + fragheaderlen escape the MTU constraint.
With MSG_MORE on an egress device without NETIF_F_SG, alloclen = mtu
while skb_put() is called with the unclamped fraglen, so a single
sendmsg() on a raw IPv6 socket with a 1240-byte HOPOPTS cmsg and
IPV6_MTU = fragheaderlen + 1 triggers:
skbuff: skb_over_panic: len:61280 put:61280 ...
kernel BUG at net/core/skbuff.c
skb_put __ip6_append_data ip6_append_data rawv6_sendmsg
The same re-lowering exists with a transport-mode xfrm bundle: ESP/AH
bytes counted in rt->dst.header_len are not part of fragheaderlen
(ESP lacks XFRM_TYPE_NON_FRAGMENT), and ip6_append_data_mtu()
subtracts dst.header_len from mtu for the first fragment, so after
the entry guard passes, the recomputed maxfraglen can be pushed below
fragheaderlen the same way.
Replace the dead expression with a single check that requires room
for at least one 8-octet payload block after the fragment header,
matching the minimum ip6_fragment() already enforces:
reserved_headerlen = fragheaderlen;
if (!skb && !(rt->dst.flags & DST_XFRM_TUNNEL))
reserved_headerlen += rt->dst.header_len;
if (mtu < reserved_headerlen + sizeof(struct frag_hdr) + 8)
goto emsgsize;
For the transport-mode xfrm case, pre-reserving dst.header_len in the
entry check makes the later ip6_append_data_mtu() recompute safe: the
subtracted mtu still satisfies the same minimum, so the recomputed
maxfraglen cannot drop below fragheaderlen either. The check runs
before any zerocopy uarg is allocated, so the emsgsize path needs no
cleanup.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: bo cao <treebacker@foxmail.com>
---
Changes in v3: collapse the fix into the entry check of
__ip6_append_data() and leave ip6_append_data_mtu() unchanged, as
suggested in review of v2; this also removes the emsgsize cleanup
hazard for the zerocopy uarg and the separate maxfraglen check.
---
net/ipv6/ip6_output.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 25fe0ba98b1a..936dad85f1c9 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1477,7 +1477,7 @@ static int __ip6_append_data(struct sock *sk,
bool paged, hold_tskey = false, extra_uref = false;
struct ipv6_txoptions *opt = v6_cork->opt;
int csummode = CHECKSUM_NONE;
- unsigned int maxnonfragsize, headersize;
+ unsigned int maxnonfragsize, headersize, reserved_headerlen;
unsigned int wmem_alloc_delta = 0;
skb = skb_peek_tail(queue);
@@ -1499,8 +1499,11 @@ static int __ip6_append_data(struct sock *sk,
(opt ? opt->opt_flen + opt->opt_nflen : 0) +
rt->rt6i_nfheader_len;
- if (mtu <= fragheaderlen ||
- ((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr))
+ reserved_headerlen = fragheaderlen;
+ if (!skb && !(rt->dst.flags & DST_XFRM_TUNNEL))
+ reserved_headerlen += rt->dst.header_len;
+
+ if (mtu < reserved_headerlen + sizeof(struct frag_hdr) + 8)
goto emsgsize;
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH net v3] ipv6: fix dead half of the MTU guard in __ip6_append_data()
2026-10-30 8:48 [PATCH net v3] ipv6: fix dead half of the MTU guard in __ip6_append_data() bo cao
@ 2026-10-30 8:53 ` netdev-bot+sinfo
2026-10-30 8:57 ` bo cao
0 siblings, 1 reply; 3+ messages in thread
From: netdev-bot+sinfo @ 2026-10-30 8:53 UTC (permalink / raw)
To: bo cao
Cc: netdev, davem, kuba, pabeni, dsahern, edumazet, idosch, horms,
stable, linux-kernel
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v3] ipv6: fix dead half of the MTU guard in __ip6_append_data()
2026-10-30 8:53 ` netdev-bot+sinfo
@ 2026-10-30 8:57 ` bo cao
0 siblings, 0 replies; 3+ messages in thread
From: bo cao @ 2026-10-30 8:57 UTC (permalink / raw)
To: netdev-bot+sinfo
Cc: davem, dsahern, edumazet, horms, idosch, kuba, linux-kernel,
netdev, pabeni, stable
The issue was found during an LLM-assisted source audit of the IPv6
fragmentation path (manual code inspection with an LLM's help, not a
production hit or a syzbot report).
It was then verified at runtime with a standalone reproducer: a
single sendmsg() on a raw IPv6 socket with a 1240-byte HOPOPTS cmsg
and IPV6_MTU set to fragheaderlen + 1 triggers the skb_over_panic()
described in the commit message (tested on 6.x, MSG_MORE on a device
without NETIF_F_SG). The xfrm transport-mode variant from the v2
discussion was identified the same way, by inspection of the
ip6_append_data_mtu() recompute path.
bo cao
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-30 8:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 8:48 [PATCH net v3] ipv6: fix dead half of the MTU guard in __ip6_append_data() bo cao
2026-10-30 8:53 ` netdev-bot+sinfo
2026-10-30 8:57 ` bo cao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox