[PATCH net-next 6/9] net: skbuff: don't BUG() on a bad csum_start in skb_copy_and_csum_dev()

From: Josef Bacik

Date: Tue Oct 06 2026 - 13:15:42 EST


skb_copy_and_csum_dev() copies everything up to the checksum start out
of the linear area, and BUG()s if the checksum start is past the end of
the linear area. It misses the other direction: a CHECKSUM_PARTIAL skb
that has been pulled past its csum_start gives a negative offset, which
gets past the check and becomes a ~4GB copy. It also trusts
csum_offset when it stores the folded checksum. So far
skb_copy_and_csum_bits() BUG()ing on a short skb has covered for that,
but once it returns instead, a bad csum_offset would write past the end
of the caller's buffer.

The function returns void and its callers are drivers copying a frame
into a bounce buffer just before handing it to the hardware. There's
nothing for them to back out of, so check both ends of csum_start and
that the checksum field fits in the frame, warn once and copy the whole
frame with skb_copy_bits() without filling in the checksum. The frame
goes out with a bad checksum and is dropped by the receiver. If even
that copy fails, zero the buffer so the driver doesn't send stale bytes.

Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
net/core/skbuff.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4070e0c25f63..c8c2c0319b87 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3971,7 +3971,17 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
else
csstart = skb_headlen(skb);

- BUG_ON(csstart > skb_headlen(skb));
+ if (WARN_ON_ONCE(csstart < 0 || csstart > skb_headlen(skb) ||
+ (skb->ip_summed == CHECKSUM_PARTIAL &&
+ csstart + skb->csum_offset + sizeof(__sum16) >
+ skb->len))) {
+ /* Send the frame without the checksum filled in, or send
+ * zeroes if we can't even copy it.
+ */
+ if (skb_copy_bits(skb, 0, to, skb->len))
+ memset(to, 0, skb->len);
+ return;
+ }

skb_copy_from_linear_data(skb, to, csstart);


--
2.55.0