]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
eth: fbnic: don't cache shinfo across skb realloc
authorJakub Kicinski <kuba@kernel.org>
Thu, 25 Jun 2026 16:05:08 +0000 (09:05 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 30 Jun 2026 00:29:15 +0000 (17:29 -0700)
fbnic_tx_lso() calls skb_cow_head() which may reallocate the skb
including the shared info. We can't use the pointer calculated
before the call.

    BUG: KASAN: slab-use-after-free in fbnic_tx_lso.isra.0+0x668/0x8e0
    Read of size 4 at addr ff110000262edd98 by task swapper/5/0
    Call Trace:
     fbnic_tx_lso.isra.0+0x668/0x8e0
     fbnic_xmit_frame+0x622/0xba0
     dev_hard_start_xmit+0xf4/0x620

    Allocated by task 8653:
     __alloc_skb+0x11e/0x5f0
     alloc_skb_with_frags+0xcc/0x6c0
     sock_alloc_send_pskb+0x327/0x3f0
     __ip_append_data+0x188b/0x47a0
     ip_make_skb+0x24a/0x300
     udp_sendmsg+0x14d2/0x21e0

    Freed by task 0:
     kfree+0x123/0x5a0
     pskb_expand_head+0x36c/0xfa0
     fbnic_tx_lso.isra.0+0x500/0x8e0
     fbnic_xmit_frame+0x622/0xba0
     dev_hard_start_xmit+0xf4/0x620
     sch_direct_xmit+0x25b/0x1100

    The buggy address belongs to the object at ff110000262edc40
     which belongs to the cache skbuff_small_head of size 640
    The buggy address is located 344 bytes inside of
     freed 640-byte region [ff110000262edc40ff110000262ede

Link: https://netdev.bots.linux.dev/logs/vmksft/fbnic-qemu-dbg/results/705762/15-uso-py/stderr
Fixes: b0b0f52042ac ("eth: fbnic: support TCP segmentation offload")
Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Link: https://patch.msgid.link/20260625160508.3327986-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c

index 9cd85a0d0c3a7f8aac25109258654adee3e83e7e..401f8b8ae1cae443b2352a9f3a30544e5baf0665 100644 (file)
@@ -194,16 +194,18 @@ static bool fbnic_tx_tstamp(struct sk_buff *skb)
 
 static bool
 fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
-            struct skb_shared_info *shinfo, __le64 *meta,
-            unsigned int *l2len, unsigned int *i3len)
+            __le64 *meta, unsigned int *l2len, unsigned int *i3len)
 {
        unsigned int l3_type, l4_type, l4len, hdrlen;
+       struct skb_shared_info *shinfo;
        unsigned char *l4hdr;
        __be16 payload_len;
 
        if (unlikely(skb_cow_head(skb, 0)))
                return true;
 
+       shinfo = skb_shinfo(skb);
+
        if (shinfo->gso_type & SKB_GSO_PARTIAL) {
                l3_type = FBNIC_TWD_L3_TYPE_OTHER;
        } else if (!skb->encapsulation) {
@@ -258,7 +260,6 @@ fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
 static bool
 fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
 {
-       struct skb_shared_info *shinfo = skb_shinfo(skb);
        unsigned int l2len, i3len;
 
        if (fbnic_tx_tstamp(skb))
@@ -273,8 +274,8 @@ fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
        *meta |= cpu_to_le64(FIELD_PREP(FBNIC_TWD_CSUM_OFFSET_MASK,
                                        skb->csum_offset / 2));
 
-       if (shinfo->gso_size) {
-               if (fbnic_tx_lso(ring, skb, shinfo, meta, &l2len, &i3len))
+       if (skb_is_gso(skb)) {
+               if (fbnic_tx_lso(ring, skb, meta, &l2len, &i3len))
                        return true;
        } else {
                *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_CSO);