* [PATCH net-next 1/9] net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-07 14:50 ` Willem de Bruijn
2026-10-06 17:10 ` [PATCH net-next 2/9] net: skbuff: don't BUG() on bad arguments to pskb_expand_head() Josef Bacik
` (8 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
When skb_copy_and_csum_bits() reaches unreadable frags it returns 0
after copying only the linear part, and the rest of the caller's buffer
is left as it was. The callers copy into a buffer that is about to go
out on the wire: an ICMP error quoting the offending packet, or a
driver's TX bounce buffer in skb_copy_and_csum_dev(). Neither buffer
is zeroed beforehand, so whatever was in memory there gets sent.
Zero the part of the buffer we didn't fill. The checksum is already
wrong in this case, so the packet still gets dropped by the receiver,
it just doesn't carry anything it shouldn't. Only zero for a positive
@len, a negative one from a broken caller must not turn into a huge
memset().
Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5c4024a03e10..512ff9cfa269 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3633,8 +3633,12 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
pos = copy;
}
- if (!skb_frags_readable(skb))
+ if (!skb_frags_readable(skb)) {
+ /* Don't hand the caller a buffer with stale bytes in it. */
+ if (len > 0)
+ memset(to, 0, len);
return 0;
+ }
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH net-next 1/9] net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits()
2026-10-06 17:10 ` [PATCH net-next 1/9] net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits() Josef Bacik
@ 2026-10-07 14:50 ` Willem de Bruijn
0 siblings, 0 replies; 14+ messages in thread
From: Willem de Bruijn @ 2026-10-07 14:50 UTC (permalink / raw)
To: Josef Bacik, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Kaiyuan Zhang, Mina Almasry,
Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
Josef Bacik wrote:
> When skb_copy_and_csum_bits() reaches unreadable frags it returns 0
> after copying only the linear part, and the rest of the caller's buffer
> is left as it was. The callers copy into a buffer that is about to go
> out on the wire: an ICMP error quoting the offending packet, or a
> driver's TX bounce buffer in skb_copy_and_csum_dev(). Neither buffer
> is zeroed beforehand, so whatever was in memory there gets sent.
>
> Zero the part of the buffer we didn't fill. The checksum is already
> wrong in this case, so the packet still gets dropped by the receiver,
> it just doesn't carry anything it shouldn't. Only zero for a positive
> @len, a negative one from a broken caller must not turn into a huge
> memset().
>
> Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
> Assisted-by: LLM
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
This should be a stand-alone fix sent to net (and stable)?
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next 2/9] net: skbuff: don't BUG() on bad arguments to pskb_expand_head()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 1/9] net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-07 14:51 ` Willem de Bruijn
2026-10-06 17:10 ` [PATCH net-next 3/9] net: skbuff: don't BUG() on a bad frag_list layout in skb_segment() Josef Bacik
` (7 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
pskb_expand_head() BUG()s if it is handed a negative nhead or a shared
skb. Both are bugs in the caller, and both keep getting hit: commit
2cbb259ec4f8 ("bpf: Reject negative head_room in __bpf_skb_change_head")
and commit 64e6a754d33d ("llc: do not use skb_get() before
dev_queue_xmit()") each fixed a crash here that took down the whole box.
The function already returns an error that every caller has to handle,
and at this point it hasn't touched the skb. Warn once and return
-EINVAL instead of crashing. Anybody running with panic_on_warn, which
includes syzbot, still stops right here.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 512ff9cfa269..5d856948cef9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2303,9 +2303,11 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
u8 *data;
int i;
- BUG_ON(nhead < 0);
+ if (WARN_ON_ONCE(nhead < 0))
+ return -EINVAL;
- BUG_ON(skb_shared(skb));
+ if (WARN_ON_ONCE(skb_shared(skb)))
+ return -EINVAL;
skb_zcopy_downgrade_managed(skb);
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH net-next 2/9] net: skbuff: don't BUG() on bad arguments to pskb_expand_head()
2026-10-06 17:10 ` [PATCH net-next 2/9] net: skbuff: don't BUG() on bad arguments to pskb_expand_head() Josef Bacik
@ 2026-10-07 14:51 ` Willem de Bruijn
0 siblings, 0 replies; 14+ messages in thread
From: Willem de Bruijn @ 2026-10-07 14:51 UTC (permalink / raw)
To: Josef Bacik, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Kaiyuan Zhang, Mina Almasry,
Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
Josef Bacik wrote:
> pskb_expand_head() BUG()s if it is handed a negative nhead or a shared
> skb. Both are bugs in the caller, and both keep getting hit: commit
> 2cbb259ec4f8 ("bpf: Reject negative head_room in __bpf_skb_change_head")
> and commit 64e6a754d33d ("llc: do not use skb_get() before
> dev_queue_xmit()") each fixed a crash here that took down the whole box.
>
> The function already returns an error that every caller has to handle,
> and at this point it hasn't touched the skb. Warn once and return
> -EINVAL instead of crashing. Anybody running with panic_on_warn, which
> includes syzbot, still stops right here.
>
> Assisted-by: LLM
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> net/core/skbuff.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 512ff9cfa269..5d856948cef9 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -2303,9 +2303,11 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
> u8 *data;
> int i;
>
> - BUG_ON(nhead < 0);
> + if (WARN_ON_ONCE(nhead < 0))
> + return -EINVAL;
Another option besides WARN_ON_ONCE or even DEBUG_NET_WARN_ON_ONCE
when returning an error is a net_warn_ratelimited for such cases.
>
> - BUG_ON(skb_shared(skb));
> + if (WARN_ON_ONCE(skb_shared(skb)))
> + return -EINVAL;
>
> skb_zcopy_downgrade_managed(skb);
>
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next 3/9] net: skbuff: don't BUG() on a bad frag_list layout in skb_segment()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 1/9] net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits() Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 2/9] net: skbuff: don't BUG() on bad arguments to pskb_expand_head() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 4/9] net: skbuff: don't BUG() when skb_copy_bits() fails in copy helpers Josef Bacik
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_segment()'s frag_list walk assumes the GRO-shaped layout it expects
and BUG()s when the layout doesn't match. Anybody who can get a
malformed GSO skb to a segmentation point gets to crash the box. Most
recently commit d5dc1e69fd72 ("inet: frags: strip GSO state from
fragments before reassembly") fixed one that an unprivileged user could
trigger with two writes to a tap device in their own user namespace.
commit 3382a1ed7f77 ("net: fix udp gso skb_segment after pull from
frag_list") fixed another.
skb_segment() already has an error path for a bad layout: the
too-many-frags check sets -EINVAL and frees the partial segment list.
Warn once and take that path for the four layout checks. The packet
gets dropped, which is what should happen to a packet we can't segment.
The one check that runs after skb_clone() and before the clone is
linked into the segment list frees the clone itself.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5d856948cef9..405d27e9bc9d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4916,7 +4916,10 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) {
- BUG_ON(skb_headlen(list_skb) > len);
+ if (WARN_ON_ONCE(skb_headlen(list_skb) > len)) {
+ err = -EINVAL;
+ goto err;
+ }
nskb = skb_clone(list_skb, GFP_ATOMIC);
if (unlikely(!nskb))
@@ -4929,7 +4932,11 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
pos += skb_headlen(list_skb);
while (pos < offset + len) {
- BUG_ON(i >= nfrags);
+ if (WARN_ON_ONCE(i >= nfrags)) {
+ kfree_skb(nskb);
+ err = -EINVAL;
+ goto err;
+ }
size = skb_frag_size(frag);
if (pos + size > offset + len)
@@ -5036,9 +5043,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & SKBFL_SHARED_FRAG;
if (!skb_headlen(list_skb)) {
- BUG_ON(!nfrags);
+ if (WARN_ON_ONCE(!nfrags)) {
+ err = -EINVAL;
+ goto err;
+ }
} else {
- BUG_ON(!list_skb->head_frag);
+ if (WARN_ON_ONCE(!list_skb->head_frag)) {
+ err = -EINVAL;
+ goto err;
+ }
/* to make room for head_frag. */
i--;
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 4/9] net: skbuff: don't BUG() when skb_copy_bits() fails in copy helpers
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (2 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 3/9] net: skbuff: don't BUG() on a bad frag_list layout in skb_segment() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 5/9] net: skbuff: don't BUG() on leftover length in skb_checksum() and friends Josef Bacik
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_copy(), skb_copy_expand() and skb_try_coalesce() all BUG() if
skb_copy_bits() fails. skb_copy_bits() only fails when the skb's
lengths don't add up, which is a bug somewhere else, usually in a
driver building the skb.
Each of these functions already has a failure return its callers handle:
- skb_copy() and skb_copy_expand() free the new skb and return NULL,
as they do when the allocation fails.
- skb_try_coalesce() returns false and the caller keeps the skbs
separate. Copy into the tailroom before skb_put() so that @to is
untouched on failure.
Warn once and take those returns.
__pskb_pull_tail() has the same BUG_ON(), but several of its callers
can't otherwise fail and don't check its return, so it's left for a
separate change that fixes them first.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 405d27e9bc9d..6cd7135e0dce 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2201,7 +2201,11 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
/* Set the tail pointer and length */
skb_put(n, skb->len);
- BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+ if (WARN_ON_ONCE(skb_copy_bits(skb, -headerlen, n->head,
+ headerlen + skb->len))) {
+ kfree_skb(n);
+ return NULL;
+ }
skb_copy_header(n, skb);
return n;
@@ -2541,8 +2545,12 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
head_copy_off = newheadroom - head_copy_len;
/* Copy the linear header and data. */
- BUG_ON(skb_copy_bits(skb, -head_copy_len, n->head + head_copy_off,
- skb->len + head_copy_len));
+ if (WARN_ON_ONCE(skb_copy_bits(skb, -head_copy_len,
+ n->head + head_copy_off,
+ skb->len + head_copy_len))) {
+ kfree_skb(n);
+ return NULL;
+ }
skb_copy_header(n, skb);
@@ -6229,8 +6237,13 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
return false;
if (len <= skb_tailroom(to) && skb_frags_readable(from)) {
- if (len)
- BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));
+ if (len) {
+ if (WARN_ON_ONCE(skb_copy_bits(from, 0,
+ skb_tail_pointer(to),
+ len)))
+ return false;
+ skb_put(to, len);
+ }
*delta_truesize = 0;
return true;
}
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 5/9] net: skbuff: don't BUG() on leftover length in skb_checksum() and friends
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (3 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 4/9] net: skbuff: don't BUG() when skb_copy_bits() fails in copy helpers Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 6/9] net: skbuff: don't BUG() on a bad csum_start in skb_copy_and_csum_dev() Josef Bacik
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_checksum(), skb_crc32c() and __skb_to_sgvec() walk the head, frags
and frag_list and BUG() if they run out of skb before they run out of
@len. By then nothing has been read past the end of the skb. The walk
stopped at the end of the data, and the check only tells us the caller
asked for a range the skb doesn't have. commit 06a0afcfe2f5 ("xfrm: do
pskb_pull properly in __xfrm_transport_prep") fixed one such caller that
crashed in __skb_to_sgvec().
Warn once and return what each function already returns when it can't
do the work:
- __skb_to_sgvec() returns -EINVAL. Every skb_to_sgvec() caller has
checked for a negative return since it learned to return -EMSGSIZE.
- skb_checksum() and skb_crc32c() return 0, as they already do for
unreadable frags. The resulting checksum is wrong, so the packet
fails verification on receive or goes out with a bad checksum on
transmit, rather than taking the machine down.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 6cd7135e0dce..4070e0c25f63 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3613,7 +3613,8 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
}
start = end;
}
- BUG_ON(len);
+ if (WARN_ON_ONCE(len))
+ return 0;
return csum;
}
@@ -3778,7 +3779,8 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
}
start = end;
}
- BUG_ON(len);
+ if (WARN_ON_ONCE(len))
+ return 0;
return crc;
}
@@ -5333,7 +5335,8 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
}
start = end;
}
- BUG_ON(len);
+ if (WARN_ON_ONCE(len))
+ return -EINVAL;
return elt;
}
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 6/9] net: skbuff: don't BUG() on a bad csum_start in skb_copy_and_csum_dev()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (4 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 5/9] net: skbuff: don't BUG() on leftover length in skb_checksum() and friends Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 7/9] net: skbuff: don't BUG() on leftover length in skb_copy_and_csum_bits() Josef Bacik
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
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@toxicpanda.com>
---
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
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 7/9] net: skbuff: don't BUG() on leftover length in skb_copy_and_csum_bits()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (5 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 6/9] net: skbuff: don't BUG() on a bad csum_start in skb_copy_and_csum_dev() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 8/9] net: skbuff: don't BUG() on a missing head_frag in skb_zerocopy() Josef Bacik
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_copy_and_csum_bits() has the same check as skb_checksum(): it BUG()s
if it runs out of skb before it runs out of @len. This one gets hit:
commit 7d63b6712538 ("icmp: guard against too small mtu") and commit
f99cd56230f5 ("net: Remove acked SYN flag from packet in the transmit
queue correctly") each fixed a crash here from icmp_glue_bits().
It can't just return, though. Its callers copy into a buffer that is
about to go out on the wire, an ICMP error quoting the offending packet
for example, so bailing out early would send whatever was left in the
rest of that buffer.
Warn once, zero the part of the buffer we didn't fill and return 0. As
with skb_checksum(), the checksum is wrong and the packet gets dropped
by whoever receives it. @len is an int, so only zero when it is
positive; a negative @len from a broken caller must not turn into a
huge memset().
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c8c2c0319b87..e29eda2eaf3f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3709,7 +3709,12 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
}
start = end;
}
- BUG_ON(len);
+ if (WARN_ON_ONCE(len)) {
+ /* Don't hand the caller a buffer with stale bytes in it. */
+ if (len > 0)
+ memset(to, 0, len);
+ return 0;
+ }
return csum;
}
EXPORT_SYMBOL(skb_copy_and_csum_bits);
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 8/9] net: skbuff: don't BUG() on a missing head_frag in skb_zerocopy()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (6 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 7/9] net: skbuff: don't BUG() on leftover length in skb_copy_and_csum_bits() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-06 17:10 ` [PATCH net-next 9/9] net: skbuff: remove the BUG_ON()s from skb_shift() Josef Bacik
2026-10-07 14:48 ` [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Willem de Bruijn
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_zerocopy() BUG()s if @from has no head_frag and the caller passed
hlen == 0, meaning the caller didn't ask for the head to be copied and
the head can't be referenced as a page either. The check runs before
anything is touched, and skb_zerocopy() already documents -EFAULT for
bad skb geometry. Warn once and return that.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e29eda2eaf3f..8c6a45a20eb0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3906,7 +3906,8 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
struct page *page;
unsigned int offset;
- BUG_ON(!from->head_frag && !hlen);
+ if (WARN_ON_ONCE(!from->head_frag && !hlen))
+ return -EFAULT;
/* dont bother with small payloads */
if (len <= skb_tailroom(to))
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 9/9] net: skbuff: remove the BUG_ON()s from skb_shift()
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (7 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 8/9] net: skbuff: don't BUG() on a missing head_frag in skb_zerocopy() Josef Bacik
@ 2026-10-06 17:10 ` Josef Bacik
2026-10-07 14:48 ` [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Willem de Bruijn
9 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2026-10-06 17:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kaiyuan Zhang, Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
skb_shift() has two BUG_ON()s. The first fires if the caller asks to
shift more than @skb holds. Nothing has been touched yet, and returning
0 already means "shifted nothing", which the TCP callers handle by
falling back. Warn once and return 0.
The second fires if the frags run out before @shiftlen does, but it
only checks after the shift has been committed to both skbs, when
there's nothing left to back out to. The loop that builds the new frag
layout only writes @tgt's frag slots past its nr_frags, and the one
branch that modifies @skb's frags also finishes the shift. So if the
loop ends with bytes still left to shift, nothing visible has changed
yet. That's the same state the MAX_SKB_FRAGS bail-out inside the loop
returns 0 from. Move the check up to just before the commit, warn once
and return 0 there.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
net/core/skbuff.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 8c6a45a20eb0..59f74850150b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4321,7 +4321,8 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
int from, to, merge, todo;
skb_frag_t *fragfrom, *fragto;
- BUG_ON(shiftlen > skb->len);
+ if (WARN_ON_ONCE(shiftlen > skb->len))
+ return 0;
if (skb_headlen(skb))
return 0;
@@ -4401,6 +4402,12 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
}
}
+ /* The frags ran out before shiftlen did. Nothing has been committed
+ * yet, so back out.
+ */
+ if (WARN_ON_ONCE(todo > 0))
+ return 0;
+
/* Ready to "commit" this state change to tgt */
skb_shinfo(tgt)->nr_frags = to;
@@ -4418,8 +4425,6 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++];
skb_shinfo(skb)->nr_frags = to;
- BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags);
-
onlymerged:
/* Most likely the tgt won't ever need its checksum anymore, skb on
* the other hand might need it if it needs to be resent
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error
2026-10-06 17:10 [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Josef Bacik
` (8 preceding siblings ...)
2026-10-06 17:10 ` [PATCH net-next 9/9] net: skbuff: remove the BUG_ON()s from skb_shift() Josef Bacik
@ 2026-10-07 14:48 ` Willem de Bruijn
2026-10-07 14:59 ` Fernando Fernandez Mancera
9 siblings, 1 reply; 14+ messages in thread
From: Willem de Bruijn @ 2026-10-07 14:48 UTC (permalink / raw)
To: Josef Bacik, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Kaiyuan Zhang, Mina Almasry,
Willem de Bruijn
Cc: netdev, linux-kernel, bpf, Josef Bacik
Josef Bacik wrote:
> I'm going through and reducing BUG_ON() usage in areas that have created
> the most problems for us. 89 commits in the tree quote "kernel BUG at
> net/core/skbuff.c", 31 of them since 2024, and some of those could be
> triggered from inside a user namespace.
>
> The first patch is a fix: skb_copy_and_csum_bits() leaves stale bytes
> in a buffer headed for the wire when it hits unreadable frags. The
> BUG_ON() conversion of the same function needs the same handling, so
> it's here rather than sent separately.
>
> The rest of the series converts 17 of the 19 BUG_ON()s in skbuff.c.
> Each one becomes
>
> if (WARN_ON_ONCE(cond))
> <error path>;
Good idea. I was thinking of doing exactly this sweep after addressing
one case recently in commit ee1972def665 ("net: downgrade BUG_ON
EIOCBQUEUED in sock_sendmsg_nosec")
Instead of WARN_ON_ONCE, which still triggers a panic on systems with
panic_on_warn, DEBUG_NET_WARN_ON_ONCE?
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error
2026-10-07 14:48 ` [PATCH net-next 0/9] net: skbuff: convert most BUG_ON()s to WARN_ON_ONCE() and an error Willem de Bruijn
@ 2026-10-07 14:59 ` Fernando Fernandez Mancera
0 siblings, 0 replies; 14+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-07 14:59 UTC (permalink / raw)
To: Willem de Bruijn, Josef Bacik, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Kaiyuan Zhang,
Mina Almasry, Willem de Bruijn
Cc: netdev, linux-kernel, bpf
On 10/7/26 4:48 PM, Willem de Bruijn wrote:
> Josef Bacik wrote:
>> I'm going through and reducing BUG_ON() usage in areas that have created
>> the most problems for us. 89 commits in the tree quote "kernel BUG at
>> net/core/skbuff.c", 31 of them since 2024, and some of those could be
>> triggered from inside a user namespace.
>>
>> The first patch is a fix: skb_copy_and_csum_bits() leaves stale bytes
>> in a buffer headed for the wire when it hits unreadable frags. The
>> BUG_ON() conversion of the same function needs the same handling, so
>> it's here rather than sent separately.
>>
>> The rest of the series converts 17 of the 19 BUG_ON()s in skbuff.c.
>> Each one becomes
>>
>> if (WARN_ON_ONCE(cond))
>> <error path>;
>
> Good idea. I was thinking of doing exactly this sweep after addressing
> one case recently in commit ee1972def665 ("net: downgrade BUG_ON
> EIOCBQUEUED in sock_sendmsg_nosec")
>
> Instead of WARN_ON_ONCE, which still triggers a panic on systems with
> panic_on_warn, DEBUG_NET_WARN_ON_ONCE?
I agree with using DEBUG_NET_WARN_ON_ONCE at least for paths that can be
triggered from userspace. I did something similar in Netfilter subsystem
not so long ago.
^ permalink raw reply [flat|nested] 14+ messages in thread