]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
neigh: let neigh_xmit take skb ownership
authorFlorian Westphal <fw@strlen.de>
Fri, 24 Apr 2026 14:58:38 +0000 (16:58 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 28 Apr 2026 02:02:11 +0000 (19:02 -0700)
neigh_xmit always releases the skb, except when no neighbour table is
found. But even the first added user of neigh_xmit (mpls) relied on
neigh_xmit to release the skb (or queue it for tx).

sashiko reported:
 If neigh_xmit() is called with an uninitialized neighbor table (for
 example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT
 and bypasses its internal out_kfree_skb error path.  Because the return
 value of neigh_xmit() is ignored here, does this leak the SKB?

Assume full ownership and remove the last code path that doesn't
xmit or free skb.

Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/neighbour.c

index 9e12524b67fadb4e9b74578ac7d6e8663af248ac..5d92160165071f73e486d5193220188038cb1923 100644 (file)
@@ -3210,8 +3210,10 @@ int neigh_xmit(int index, struct net_device *dev,
 
                rcu_read_lock();
                tbl = rcu_dereference(neigh_tables[index]);
-               if (!tbl)
-                       goto out_unlock;
+               if (!tbl) {
+                       rcu_read_unlock();
+                       goto out_kfree_skb;
+               }
                if (index == NEIGH_ARP_TABLE) {
                        u32 key = *((u32 *)addr);
 
@@ -3227,7 +3229,6 @@ int neigh_xmit(int index, struct net_device *dev,
                        goto out_kfree_skb;
                }
                err = READ_ONCE(neigh->output)(neigh, skb);
-out_unlock:
                rcu_read_unlock();
        }
        else if (index == NEIGH_LINK_TABLE) {
@@ -3237,11 +3238,10 @@ out_unlock:
                        goto out_kfree_skb;
                err = dev_queue_xmit(skb);
        }
-out:
        return err;
 out_kfree_skb:
        kfree_skb(skb);
-       goto out;
+       return err;
 }
 EXPORT_SYMBOL(neigh_xmit);