From d2527ad3a9e1f3031095d65376a94a8e640b2b74 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 30 Jun 2025 15:42:11 -0400 Subject: [PATCH] net: preserve MSG_ZEROCOPY with forwarding MSG_ZEROCOPY data must be copied before data is queued to local sockets, to avoid indefinite timeout until memory release. This test is performed by skb_orphan_frags_rx, which is called when looping an egress skb to packet sockets, error queue or ingress path. To preserve zerocopy for skbs that are looped to ingress but are then forwarded to an egress device rather than delivered locally, defer this last check until an skb enters the local IP receive path. This is analogous to existing behavior of skb_clear_delivery_time. Signed-off-by: Willem de Bruijn Link: https://patch.msgid.link/20250630194312.1571410-2-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 2 -- net/ipv4/ip_input.c | 6 ++++++ net/ipv6/ip6_input.c | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 7ee808eb068e4..96d33dead604f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5937,8 +5937,6 @@ check_vlan_id: } if (pt_prev) { - if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) - goto drop; *ppt_prev = pt_prev; } else { drop: diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 30a5e9460d006..f8696e67def4d 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -226,6 +226,12 @@ resubmit: static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) { + __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); + kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM); + return 0; + } + skb_clear_delivery_time(skb); __skb_pull(skb, skb_network_header_len(skb)); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 0b3b81fd4a58a..168ec07e31cc3 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -478,6 +478,13 @@ discard: static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) { + __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_INDISCARDS); + kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM); + return 0; + } + skb_clear_delivery_time(skb); ip6_protocol_deliver_rcu(net, skb, 0, false); -- 2.47.2