From: Jiayuan Chen <[email protected]>

xdp_master_redirect() dereferences the master device pointer and calls
ndo_xdp_get_xmit_slave() without checking whether the master is valid
or running. When a bond device in round-robin mode has never been brought
up, bond->rr_tx_counter is not allocated (only allocated in bond_open()).
The XDP redirect path can still reach bond_rr_gen_slave_id() via
xdp_master_redirect() → bond_xdp_get_xmit_slave() →
bond_xdp_xmit_roundrobin_slave_get(), causing a null-ptr-deref on
rr_tx_counter.

bpf_master_redirect_enabled_key is a global static key. When any bond
device has native XDP attached, this key is enabled system-wide, causing
the XDP_TX → xdp_master_redirect interception to fire for all bond
slaves, even slaves of other bond devices that have never been opened.

To trigger, the following conditions must be met:
1. A bond (bond0) with native XDP attached, enabling the global key
2. Another bond (bond1) in round-robin mode, never brought up
3. A slave (veth1) of bond1 with generic XDP returning XDP_TX
4. Packets hitting the generic XDP path on veth1

Add a check in xdp_master_redirect() to verify the master device is
valid and running before proceeding with the redirect. This is
semantically correct because redirecting to a non-running master is
meaningless, and safe from a concurrency perspective because
xdp_master_redirect() runs under RCU protection and the master's
resources are not freed until after an RCU grace period.

Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave 
device")
Reported-by: [email protected]
Closes: 
https://lore.kernel.org/all/[email protected]/T/
Signed-off-by: Jiayuan Chen <[email protected]>
---
 net/core/filter.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/core/filter.c b/net/core/filter.c
index ba019ded773d..9a45dabd0044 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4387,6 +4387,9 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)
        struct net_device *master, *slave;
 
        master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev);
+       if (unlikely(!master || !netif_running(master)))
+               return XDP_TX;
+
        slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp);
        if (slave && slave != xdp->rxq->dev) {
                /* The target device is different from the receiving device, so
-- 
2.43.0


Reply via email to