* [PATCH net v4 1/3] openvswitch: only skb_tx_error() a packet we are about to drop
2026-08-22 9:10 [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb Norbert Szetei
@ 2026-08-22 9:12 ` Norbert Szetei
2026-08-22 9:13 ` [PATCH net v4 2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy() Norbert Szetei
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Norbert Szetei @ 2026-08-22 9:12 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Aaron Conole, Eelco Chaudron, Ilya Maximets,
Steffen Klassert, Kuan-Ting Chen, Michael S. Tsirkin,
Willem de Bruijn, linux-kernel, dev, Jongmin Jang
queue_userspace_packet() borrows the packet skb -- it only copies it into
a private netlink message (user_skb) and does not own it; on return
do_execute_actions() keeps forwarding it through the flow's remaining
actions. Its error path nevertheless calls skb_tx_error(skb), which via
skb_zcopy_clear() does skb_shinfo(skb)->flags &= ~SKBFL_ALL_ZEROCOPY,
stripping SKBFL_SHARED_FRAG from that live skb (skb_tx_error()'s kerneldoc
says "skb must be freed afterwards").
For a MSG_ZEROCOPY skb carrying page-cache frags, SKBFL_SHARED_FRAG is
what makes esp_input() skb_cow_data() before in-place AEAD; once it is
stripped a later local ESP-in-UDP delivery decrypts in place over pages
the sender does not own -- an unprivileged page-cache write (the
"Fragnesia" primitive).
do_execute_actions() ignores output_userspace()'s return value, so any
action after a failed USERSPACE upcall inherits the stripped skb.
Move the skb_tx_error() to the flow-miss drop path - the "default"
branch of ovs_dp_process_packet()'s switch(error), before kfree_skb().
The call has been here since commit 36d5fe6a0007 ("core, nfqueue,
openvswitch: Orphan frags in skb_zerocopy and handle errors") but was
harmless until esp_input() began relying on SKBFL_SHARED_FRAG to gate
in-place decrypt; only then did stripping it on a still-forwarded skb
become a page-cache write primitive.
Fixes: 36d5fe6a0007 ("core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors")
Fixes: f4c50a4034e6 ("xfrm: esp: avoid in-place decrypt on shared skb frags")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
Tested-by: Jongmin Jang <payload.jang@gmail.com>
---
net/openvswitch/datapath.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index f2d5b5ab38de..2fc9ef6c321f 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -285,6 +285,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
consume_skb(skb);
break;
default:
+ skb_tx_error(skb);
kfree_skb(skb);
break;
}
@@ -604,8 +605,6 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
user_skb = NULL;
out:
- if (err)
- skb_tx_error(skb);
consume_skb(user_skb);
consume_skb(nskb);
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH net v4 2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy()
2026-08-22 9:10 [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb Norbert Szetei
2026-08-22 9:12 ` [PATCH net v4 1/3] openvswitch: only skb_tx_error() a packet we are about to drop Norbert Szetei
@ 2026-08-22 9:13 ` Norbert Szetei
2026-08-22 20:58 ` Willem de Bruijn
2026-08-22 9:15 ` [PATCH net v4 3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error() Norbert Szetei
2026-08-25 7:50 ` [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb patchwork-bot+netdevbpf
3 siblings, 1 reply; 7+ messages in thread
From: Norbert Szetei @ 2026-08-22 9:13 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Aaron Conole, Eelco Chaudron, Ilya Maximets,
Steffen Klassert, Kuan-Ting Chen, Michael S. Tsirkin,
Willem de Bruijn, linux-kernel, dev, Jongmin Jang
skb_zerocopy() copies frags from @from into @to. On an
skb_orphan_frags() failure it calls skb_tx_error(@from), a destructive
operation on the source skb the copy helper does not own. That completes
@from's zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, including the
SKBFL_SHARED_FRAG page-ownership marker.
Both callers already report the failure on their own drop path.
nfnetlink_queue does it at nla_put_failure, and Open vSwitch does it in
the flow-miss drop arm of ovs_dp_process_packet(), so nothing is lost by
dropping it here.
On Open vSwitch's OVS_ACTION_ATTR_USERSPACE path the skb is not freed on
this error: do_execute_actions() ignores output_userspace()'s return
value and, unless the upcall was the last action, keeps forwarding the
same skb through the flow's remaining actions. The uarg is completed
while that skb is still in flight, telling the producer its buffers are
free, and SKBFL_SHARED_FRAG is cleared on an skb the rest of the stack
still handles. That flag is what makes esp_input() call skb_cow_data()
instead of decrypting in place, so a later local ESP delivery can
decrypt over frags the skb does not own privately.
Leave error reporting to the callers.
Fixes: 36d5fe6a0007 ("core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors")
Cc: stable@vger.kernel.org
Suggested-by: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
---
net/core/skbuff.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d4382b68d56e..ab3d161247b9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3914,7 +3914,6 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
skb_len_add(to, len + plen);
if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
- skb_tx_error(from);
if (j > 0)
put_page(virt_to_head_page(from->head));
return -ENOMEM;
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH net v4 2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy()
2026-08-22 9:13 ` [PATCH net v4 2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy() Norbert Szetei
@ 2026-08-22 20:58 ` Willem de Bruijn
0 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2026-08-22 20:58 UTC (permalink / raw)
To: Norbert Szetei, netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Aaron Conole, Eelco Chaudron, Ilya Maximets,
Steffen Klassert, Kuan-Ting Chen, Michael S. Tsirkin,
Willem de Bruijn, linux-kernel, dev, Jongmin Jang
Norbert Szetei wrote:
> skb_zerocopy() copies frags from @from into @to. On an
> skb_orphan_frags() failure it calls skb_tx_error(@from), a destructive
> operation on the source skb the copy helper does not own. That completes
> @from's zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, including the
> SKBFL_SHARED_FRAG page-ownership marker.
>
> Both callers already report the failure on their own drop path.
> nfnetlink_queue does it at nla_put_failure, and Open vSwitch does it in
> the flow-miss drop arm of ovs_dp_process_packet(), so nothing is lost by
> dropping it here.
>
> On Open vSwitch's OVS_ACTION_ATTR_USERSPACE path the skb is not freed on
> this error: do_execute_actions() ignores output_userspace()'s return
> value and, unless the upcall was the last action, keeps forwarding the
> same skb through the flow's remaining actions. The uarg is completed
> while that skb is still in flight, telling the producer its buffers are
> free, and SKBFL_SHARED_FRAG is cleared on an skb the rest of the stack
> still handles. That flag is what makes esp_input() call skb_cow_data()
> instead of decrypting in place, so a later local ESP delivery can
> decrypt over frags the skb does not own privately.
>
> Leave error reporting to the callers.
>
> Fixes: 36d5fe6a0007 ("core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors")
> Cc: stable@vger.kernel.org
> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
> Signed-off-by: Norbert Szetei <norbert@doyensec.com>
> Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net v4 3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error()
2026-08-22 9:10 [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb Norbert Szetei
2026-08-22 9:12 ` [PATCH net v4 1/3] openvswitch: only skb_tx_error() a packet we are about to drop Norbert Szetei
2026-08-22 9:13 ` [PATCH net v4 2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy() Norbert Szetei
@ 2026-08-22 9:15 ` Norbert Szetei
2026-08-23 18:26 ` Willem de Bruijn
2026-08-25 7:50 ` [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb patchwork-bot+netdevbpf
3 siblings, 1 reply; 7+ messages in thread
From: Norbert Szetei @ 2026-08-22 9:15 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Aaron Conole, Eelco Chaudron, Ilya Maximets,
Steffen Klassert, Kuan-Ting Chen, Michael S. Tsirkin,
Willem de Bruijn, linux-kernel, dev, Jongmin Jang
skb_tx_error() completes the zerocopy uarg and clears
SKBFL_ALL_ZEROCOPY, and skb_zcopy_downgrade_managed() clears
SKBFL_MANAGED_FRAG_REFS. Both live in skb_shinfo(), which every clone
shares, while the caller only owns the reference it is about to drop.
Through a clone it tells the producer its pages are free and drops
SKBFL_SHARED_FRAG for an skb that is still in flight.
Open vSwitch reaches this with a non-last OVS_ACTION_ATTR_RECIRC:
clone_execute() sends a skb_clone() into ovs_dp_process_packet() while
do_execute_actions() keeps forwarding the original, and skb_clone()
does not privatise the frags here -- skb_orphan_frags() returns early
on SKBFL_DONT_ORPHAN. A flow miss on the clone then strips the marker
from the packet still being forwarded, and a later local ESP delivery
decrypts in place over frags it does not own privately.
Skip it for a cloned skb. Nothing is lost: skb_release_data() clears
the zerocopy state once the last reference to the shared data goes.
Fixes: 25121173f7b1 ("skb: api to report errors for zero copy skbs")
Cc: stable@vger.kernel.org
Suggested-by: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
Tested-by: Jongmin Jang <payload.jang@gmail.com>
---
net/core/skbuff.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ab3d161247b9..b9541329f1a7 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1417,10 +1417,13 @@ EXPORT_SYMBOL(skb_dump);
*
* Report xmit error if a device callback is tracking this skb.
* skb must be freed afterwards.
+ *
+ * Does nothing for a cloned skb: the zerocopy state lives in
+ * skb_shinfo(), which the clones share.
*/
void skb_tx_error(struct sk_buff *skb)
{
- if (skb) {
+ if (skb && !skb_cloned(skb)) {
skb_zcopy_downgrade_managed(skb);
skb_zcopy_clear(skb, true);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH net v4 3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error()
2026-08-22 9:15 ` [PATCH net v4 3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error() Norbert Szetei
@ 2026-08-23 18:26 ` Willem de Bruijn
0 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2026-08-23 18:26 UTC (permalink / raw)
To: Norbert Szetei, netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Aaron Conole, Eelco Chaudron, Ilya Maximets,
Steffen Klassert, Kuan-Ting Chen, Michael S. Tsirkin,
Willem de Bruijn, linux-kernel, dev, Jongmin Jang
Norbert Szetei wrote:
> skb_tx_error() completes the zerocopy uarg and clears
> SKBFL_ALL_ZEROCOPY, and skb_zcopy_downgrade_managed() clears
> SKBFL_MANAGED_FRAG_REFS. Both live in skb_shinfo(), which every clone
> shares, while the caller only owns the reference it is about to drop.
> Through a clone it tells the producer its pages are free and drops
> SKBFL_SHARED_FRAG for an skb that is still in flight.
>
> Open vSwitch reaches this with a non-last OVS_ACTION_ATTR_RECIRC:
> clone_execute() sends a skb_clone() into ovs_dp_process_packet() while
> do_execute_actions() keeps forwarding the original, and skb_clone()
> does not privatise the frags here -- skb_orphan_frags() returns early
> on SKBFL_DONT_ORPHAN. A flow miss on the clone then strips the marker
> from the packet still being forwarded, and a later local ESP delivery
> decrypts in place over frags it does not own privately.
>
> Skip it for a cloned skb. Nothing is lost: skb_release_data() clears
> the zerocopy state once the last reference to the shared data goes.
>
> Fixes: 25121173f7b1 ("skb: api to report errors for zero copy skbs")
> Cc: stable@vger.kernel.org
> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
> Signed-off-by: Norbert Szetei <norbert@doyensec.com>
> Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
> Tested-by: Jongmin Jang <payload.jang@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Took me some time to wrap my head around this one, because
There are two independent types of zerocopy in this context:
1. skb_zerocopy(), used by nfqueue and ovs to create a derived skb
2. skb_zcopy(), skbs with "zerocopy" page frags
And there second has two variants:
2A. original, such as vhost-net, that do not support refcounting and
thus must be downgraded on skb_clone() and such
2B. SKBFL_DONT_ORPHAN, that support clones through refcounting
The bug here is modifying shared shinfo fields of cloned skbs, so
affects type 2B skbs only.
skb_tx_error was introduced for type 2A skbs, predates refcounting.
For type 2B, the signal is indeed generated at skb_release_data.
So LGTM.
> ---
> net/core/skbuff.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index ab3d161247b9..b9541329f1a7 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -1417,10 +1417,13 @@ EXPORT_SYMBOL(skb_dump);
> *
> * Report xmit error if a device callback is tracking this skb.
> * skb must be freed afterwards.
> + *
> + * Does nothing for a cloned skb: the zerocopy state lives in
> + * skb_shinfo(), which the clones share.
> */
> void skb_tx_error(struct sk_buff *skb)
> {
> - if (skb) {
> + if (skb && !skb_cloned(skb)) {
> skb_zcopy_downgrade_managed(skb);
> skb_zcopy_clear(skb, true);
> }
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb
2026-08-22 9:10 [PATCH net v4 0/3] net: don't strip zerocopy frag markers from a forwarded skb Norbert Szetei
` (2 preceding siblings ...)
2026-08-22 9:15 ` [PATCH net v4 3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error() Norbert Szetei
@ 2026-08-25 7:50 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-08-25 7:50 UTC (permalink / raw)
To: Norbert Szetei
Cc: netdev, davem, edumazet, kuba, pabeni, horms, aconole, echaudro,
i.maximets, steffen.klassert, h3xrabbit, mst, willemb,
linux-kernel, dev, payload.jang
Hello:
This series was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Sat, 22 Aug 2026 11:10:09 +0200 you wrote:
> queue_userspace_packet() calls skb_tx_error() on the packet skb in its
> error path, but it only borrows that skb: on the OVS_ACTION_ATTR_USERSPACE
> action path do_execute_actions() ignores output_userspace()'s return value
> and keeps forwarding the same skb through the flow's remaining actions.
> skb_tx_error() completes the zerocopy uarg and clears SKBFL_ALL_ZEROCOPY,
> and with it SKBFL_SHARED_FRAG.
>
> [...]
Here is the summary with links:
- [net,v4,1/3] openvswitch: only skb_tx_error() a packet we are about to drop
https://git.kernel.org/netdev/net/c/0dbc2398fca3
- [net,v4,2/3] net: skbuff: don't skb_tx_error() the source skb in skb_zerocopy()
https://git.kernel.org/netdev/net/c/8ece90615012
- [net,v4,3/3] net: skbuff: don't touch shared zerocopy state in skb_tx_error()
https://git.kernel.org/netdev/net/c/f66bdb1cc0fc
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 7+ messages in thread