Thread (2 messages) 2 messages, 2 authors, 2d ago

[PATCH net 2/2] net/ipv4: fail append when the moved fraggap exceeds the fragment data

flat view
WARM2d

From: tencentos_secure(TencentOS安全公共邮箱) <hidden>
Date: 2026-10-26 11:23:57
Subsystem: networking [general], networking [ipv4/ipv6], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds

When the first fragment of a cork is already at maxfraglen, the next
__ip_append_data() iteration relays the previous fragment's tail,
fraggap = skb_prev->len - maxfraglen, into the new skb. The moved
fraggap is charged against datalen by computing

	copy = datalen - transhdrlen - fraggap - pagedlen;

but once datalen is capped at maxfraglen - fragheaderlen it can become
smaller than transhdrlen + fraggap. Then copy goes negative: no payload
is copied and the iteration makes no progress. Worse, in the paged
branch (MSG_SPLICE_PAGES / MSG_ZEROCOPY / GSO) pagedlen = datalen -
transhdrlen - fraggap additionally wraps unsigned, breaking the
alloclen + pagedlen == fraglen invariant that commit eca856950f7c
("ipv4: account for fraggap on the paged allocation path") relies
on; the loop then either queues skbs with garbage tail accounting
(silent packet corruption) or, when maxfraglen == fragheaderlen,
never makes progress and grinds on until -ENOBUFS.

Reject such an append before any allocation: if the moved tail
(transhdrlen + fraggap) cannot fit in the fragment's datalen, the
iteration cannot make progress, so fail with -EINVAL. This covers all
three alloclen branches, including the paged one. With the preceding
fix fraggap is bounded by the alignment slop, but the condition stays
reachable with extreme geometries (e.g. an effective mtu too small for
fragheaderlen + transhdrlen), so pin the geometry explicitly, as
__ip6_append_data() has done since commit 232cd35d0804 ("ipv6: fix
out of bound writes in __ip6_append_data()").

This cannot reject a send that would otherwise succeed: the guard only
fires when transhdrlen + fraggap > datalen, which is exactly when copy
would come out negative, or, on the paged branch, when pagedlen would
wrap.  No send can get past an iteration with a negative copy -- no
payload is copied, so the loop makes no progress.  All callers flush
the cork on append error, and returning -EINVAL in mid-cork state
already happens in this function (MSG_ZEROCOPY ubuf mismatch).

Fixes: 353e5c9abd90 ("ipv4: Fix IPsec slowpath fragmentation problem")
Reported-by: TencentOS Corvus AI <redacted>
Cc: <redacted>
Signed-off-by: Anakin Zhang <redacted>
---
 net/ipv4/ip_output.c | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b84d56c..5db8b06 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1105,6 +1105,11 @@ alloc_new_skb:
 			fraglen = datalen + fragheaderlen;
 			pagedlen = 0;
 
+			if (unlikely(transhdrlen + fraggap > datalen)) {
+				err = -EINVAL;
+				goto error;
+			}
+
 			alloc_extra = hh_len + 15;
 			alloc_extra += exthdrlen;
 
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help