On 4/10/26 1:37 PM, Jiayuan Chen wrote:
Add a selftest that reproduces the null-ptr-deref in
bond_rr_gen_slave_id() when XDP redirect targets a bond device in
round-robin mode that was never brought up. The test verifies the fix
by ensuring no crash occurs.
Test setup:
- bond0: active-backup mode, UP, with native XDP (enables
bpf_master_redirect_enabled_key globally)
- bond1: round-robin mode, never UP
- veth1: slave of bond1, with generic XDP (XDP_TX)
- BPF_PROG_TEST_RUN with live frames triggers the redirect path
Signed-off-by: Jiayuan Chen <[email protected]>
I checked locally that this XDP test passes fine and triggers a NULL
pointer deref without the fix.
[...]
+ /* Attach generic XDP (XDP_TX) to veth1.
+ * When packets arrive at veth1 via netif_receive_skb,
do_xdp_generic()
+ * runs this program. XDP_TX + bond slave triggers
xdp_master_redirect().
+ */
+ xdp_tx_fd = bpf_program__fd(skeletons->xdp_tx->progs.xdp_tx);
+ if (!ASSERT_GE(xdp_tx_fd, 0, "xdp_tx prog_fd"))
+ goto out;
nit: no need for the ASSERT_GE given the skeleton loaded, see also the
various
other tests gathering bpf_program__fd().
+ err = bpf_xdp_attach(veth1_ifindex, xdp_tx_fd,
+ XDP_FLAGS_SKB_MODE, NULL);
+ if (!ASSERT_OK(err, "attach generic XDP to veth1"))
+ goto out;
+
+ /* Run BPF_PROG_TEST_RUN with XDP_PASS live frames on veth1.
+ * XDP_PASS frames become SKBs with skb->dev = veth1, entering
+ * netif_receive_skb -> do_xdp_generic -> xdp_master_redirect.
+ * Without the fix, bond_rr_gen_slave_id() dereferences NULL
+ * rr_tx_counter and crashes.
+ */
+ xdp_pass_fd =
bpf_program__fd(skeletons->xdp_dummy->progs.xdp_dummy_prog);
+ if (!ASSERT_GE(xdp_pass_fd, 0, "xdp_pass prog_fd"))
+ goto out;
ditto, can be simplified a bit into:
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
index 0d4ec1e5b401..c42488e445c2 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
@@ -506,7 +506,7 @@ static void test_xdp_bonding_nested(struct
skeletons *skeletons)
static void test_xdp_bonding_redirect_no_up(struct skeletons *skeletons)
{
struct nstoken *nstoken = NULL;
- int xdp_pass_fd, xdp_tx_fd;
+ int xdp_pass_fd;
int veth1_ifindex;
int err;
char pkt[ETH_HLEN + 1];
@@ -555,11 +555,8 @@ static void
test_xdp_bonding_redirect_no_up(struct skeletons *skeletons)
* When packets arrive at veth1 via netif_receive_skb,
do_xdp_generic()
* runs this program. XDP_TX + bond slave triggers
xdp_master_redirect().
*/
- xdp_tx_fd = bpf_program__fd(skeletons->xdp_tx->progs.xdp_tx);
- if (!ASSERT_GE(xdp_tx_fd, 0, "xdp_tx prog_fd"))
- goto out;
-
- err = bpf_xdp_attach(veth1_ifindex, xdp_tx_fd,
+ err = bpf_xdp_attach(veth1_ifindex,
+ bpf_program__fd(skeletons->xdp_tx->progs.xdp_tx),
XDP_FLAGS_SKB_MODE, NULL);
if (!ASSERT_OK(err, "attach generic XDP to veth1"))
goto out;
@@ -571,8 +568,6 @@ static void test_xdp_bonding_redirect_no_up(struct
skeletons *skeletons)
* rr_tx_counter and crashes.
*/
xdp_pass_fd =
bpf_program__fd(skeletons->xdp_dummy->progs.xdp_dummy_prog);
- if (!ASSERT_GE(xdp_pass_fd, 0, "xdp_pass prog_fd"))
- goto out;
memset(pkt, 0, sizeof(pkt));
ctx_in.data_end = sizeof(pkt);