]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfrm: fix stale skb->prev after async crypto steals a GSO segment
authorPetr Wozniak <petr.wozniak@gmail.com>
Sun, 21 Jun 2026 10:03:27 +0000 (12:03 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Fri, 26 Jun 2026 06:13:55 +0000 (08:13 +0200)
skb_gso_segment() leaves the segment list head with ->prev pointing at
the last segment, an invariant validate_xmit_skb_list() relies on when
it sets its tail pointer (tail = skb->prev).

When validate_xmit_xfrm() walks a GSO list and some segments are stolen
by async crypto (->xmit() returns -EINPROGRESS), those segments are
unlinked from the list but the head ->prev is never updated.  If the
last segment is the one stolen, the returned head still has ->prev
pointing at it, even though it is now owned by the crypto engine and may
be freed.  validate_xmit_skb_list() later does tail->next = skb, writing
through that stale pointer -- a use-after-free.

Repoint skb->prev at the last retained segment before returning.

Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.")
Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_device.c

index 19c77f09acc95611ccb7befe90e373b59ca08343..aec1e1184a71349d640ad51e9d1b15101755cc84 100644 (file)
@@ -224,6 +224,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
                pskb = skb2;
        }
 
+       /* skb_gso_segment() set skb->prev to the last segment, but async
+        * crypto may have stolen it above without updating ->prev.  Repoint
+        * it at the last retained segment so validate_xmit_skb_list() does
+        * not chain onto a segment now owned by the crypto engine.
+        */
+       if (skb)
+               skb->prev = pskb;
+
        return skb ? skb : ERR_PTR(-EINPROGRESS);
 }
 EXPORT_SYMBOL_GPL(validate_xmit_xfrm);