Thread (13 messages) 13 messages, 5 authors, 2026-03-06

Re: [PATCH net v4 1/2] bonding: fix null-ptr-deref in bond_rr_gen_slave_id()

From: "Jiayuan Chen" <jiayuan.chen@linux.dev>
Date: 2026-03-04 08:47:37
Also in: bpf, linux-kselftest, linux-rt-devel, lkml

March 4, 2026 at 16:20, "Daniel Borkmann" <daniel@iogearbox.net mailto:daniel@iogearbox.net?to=%22Daniel%20Borkmann%22%20%3Cdaniel%40iogearbox.net%3E > wrote:

quoted hunk ↗ jump to hunk
On 3/4/26 8:42 AM, Jiayuan Chen wrote:
quoted
From: Jiayuan Chen <redacted>
 bond_rr_gen_slave_id() dereferences bond->rr_tx_counter without a NULL
 check. rr_tx_counter is a per-CPU counter only allocated in bond_open()
 when the bond mode is round-robin. If the bond device was never brought
 up, rr_tx_counter remains NULL, causing a null-ptr-deref.
 The XDP redirect path can reach this code even when the bond is not up:
 bpf_master_redirect_enabled_key is a global static key, so when any bond
 device has native XDP attached, the XDP_TX -> xdp_master_redirect()
 interception is enabled for all bond slaves system-wide. This allows the
 path xdp_master_redirect() -> bond_xdp_get_xmit_slave() ->
 bond_xdp_xmit_roundrobin_slave_get() -> bond_rr_gen_slave_id() to be
 reached on a bond that was never opened.
 Fix this by allocating rr_tx_counter unconditionally in bond_init()
 (ndo_init), which is called by register_netdevice() and covers both
 device creation paths (bond_create() and bond_newlink()). This also
 handles the case where bond mode is changed to round-robin after device
 creation. The conditional allocation in bond_open() is removed. Since
 bond_destructor() already unconditionally calls
 free_percpu(bond->rr_tx_counter), the lifecycle is clean: allocate at
 ndo_init, free at destructor.
 Note: rr_tx_counter is only used by round-robin mode, so this
 deliberately allocates a per-cpu u32 that goes unused for other modes.
 Conditional allocation (e.g., in bond_option_mode_set) was considered
 but rejected: the XDP path can race with mode changes on a downed bond,
 and adding memory barriers to the XDP hot path is not justified for
 saving 4 bytes per CPU.
Arguably it's a corner case, but could we not just do sth like this to
actually check if the device is up and if not drop?
diff --git a/net/core/filter.c b/net/core/filter.c
index ba019ded773d..c447fd989a27 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->flags & IFF_UP)))
+ return XDP_ABORTED;
+
 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
Hi Daniel,

It was discussed at [1].

The primary concern at the time was that assuming
bond->rr_tx_counter had been allocated based on the
interface being up was too implicit.

[1] https://lore.kernel.org/netdev/20260224112545.37888-1-jiayuan.chen@linux.dev/T/#t (local)

Feel free to share any other thoughts or ideas

Thanks,
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help