* [PATCH net] net: Avoid checksumming unreadable skb tail on trim
@ 2026-05-22 12:06 Björn Töpel
2026-05-22 15:39 ` Breno Leitao
0 siblings, 1 reply; 2+ messages in thread
From: Björn Töpel @ 2026-05-22 12:06 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Mina Almasry, Willem de Bruijn, Kaiyuan Zhang,
netdev
Cc: Björn Töpel, linux-kernel
pskb_trim_rcsum_slow() keeps CHECKSUM_COMPLETE valid by subtracting
the checksum of the bytes removed from the skb tail. That assumes the
removed bytes can be read.
io_uring zcrx skbs may contain unreadable net_iov frags. With fbnic
header/data split, small TCP/IPv4 packets can carry Ethernet padding
in such a frag. ip_rcv_core() trims the skb to iph->tot_len before TCP
sees it, and the CHECKSUM_COMPLETE adjustment then calls
skb_checksum() on the padding.
This is exposed by IPv4 because small TCP/IPv4 frames can be shorter
than the Ethernet minimum payload. TCP/IPv6 frames are large enough in
the normal zcrx path, so they do not hit the same padding trim.
Keep the existing checksum adjustment for readable skbs. If the
remaining packet is fully linear, drop CHECKSUM_COMPLETE and let the
stack validate the packet after trimming. If unreadable payload would
remain, fail the trim; the checksum cannot be adjusted without reading
the trimmed tail.
Also clear skb->unreadable when trimming removes all frags.
Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
Signed-off-by: Björn Töpel <bjorn@kernel.org>
---
net/core/skbuff.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 44ac121cfccb..d247acd447e4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2787,6 +2787,8 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
skb->data_len = 0;
skb_set_tail_pointer(skb, len);
}
+ if (!skb_shinfo(skb)->nr_frags && !skb_has_frag_list(skb))
+ skb->unreadable = 0;
if (!skb->sk || skb->destructor == sock_edemux)
skb_condense(skb);
@@ -2794,16 +2796,37 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
}
EXPORT_SYMBOL(___pskb_trim);
+static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len)
+{
+ int delta = skb->len - len;
+
+ if (skb_frags_readable(skb)) {
+ skb->csum = csum_block_sub(skb->csum,
+ skb_checksum(skb, len, delta, 0),
+ len);
+ return 0;
+ }
+
+ if (len > skb_headlen(skb))
+ return -EFAULT;
+
+ /* The trimmed bytes are unreadable, but the remaining packet can be
+ * checksummed by software after trimming.
+ */
+ skb->ip_summed = CHECKSUM_NONE;
+ return 0;
+}
+
/* Note : use pskb_trim_rcsum() instead of calling this directly
*/
int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len)
{
if (skb->ip_summed == CHECKSUM_COMPLETE) {
- int delta = skb->len - len;
+ int err;
- skb->csum = csum_block_sub(skb->csum,
- skb_checksum(skb, len, delta, 0),
- len);
+ err = pskb_trim_rcsum_complete(skb, len);
+ if (err)
+ return err;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
int hdlen = (len > skb_headlen(skb)) ? skb_headlen(skb) : len;
int offset = skb_checksum_start_offset(skb) + skb->csum_offset;
base-commit: 68993ced0f618e36cf33388f1e50223e5e6e78cc
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH net] net: Avoid checksumming unreadable skb tail on trim
2026-05-22 12:06 [PATCH net] net: Avoid checksumming unreadable skb tail on trim Björn Töpel
@ 2026-05-22 15:39 ` Breno Leitao
0 siblings, 0 replies; 2+ messages in thread
From: Breno Leitao @ 2026-05-22 15:39 UTC (permalink / raw)
To: Björn Töpel
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Mina Almasry, Willem de Bruijn, Kaiyuan Zhang,
netdev, linux-kernel
On Fri, May 22, 2026 at 02:06:40PM +0200, Björn Töpel wrote:
> pskb_trim_rcsum_slow() keeps CHECKSUM_COMPLETE valid by subtracting
> the checksum of the bytes removed from the skb tail. That assumes the
> removed bytes can be read.
>
> io_uring zcrx skbs may contain unreadable net_iov frags. With fbnic
> header/data split, small TCP/IPv4 packets can carry Ethernet padding
> in such a frag. ip_rcv_core() trims the skb to iph->tot_len before TCP
> sees it, and the CHECKSUM_COMPLETE adjustment then calls
> skb_checksum() on the padding.
>
> This is exposed by IPv4 because small TCP/IPv4 frames can be shorter
> than the Ethernet minimum payload. TCP/IPv6 frames are large enough in
> the normal zcrx path, so they do not hit the same padding trim.
>
> Keep the existing checksum adjustment for readable skbs. If the
> remaining packet is fully linear, drop CHECKSUM_COMPLETE and let the
> stack validate the packet after trimming. If unreadable payload would
> remain, fail the trim; the checksum cannot be adjusted without reading
> the trimmed tail.
>
> Also clear skb->unreadable when trimming removes all frags.
>
> Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
> Signed-off-by: Björn Töpel <bjorn@kernel.org>
Reviewed-by: Breno Leitao <leitao@debian.org>
> +static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len)
> +{
> + int delta = skb->len - len;
I suppose this is not unsigned/size_t because csum_block_sub() requires
an 'int', is this right?
> /* Note : use pskb_trim_rcsum() instead of calling this directly
> */
I think you can make this a one-line comment, or just a proper kdoc.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-22 15:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-22 12:06 [PATCH net] net: Avoid checksumming unreadable skb tail on trim Björn Töpel
2026-05-22 15:39 ` Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox