On 4/11/26 12:28 AM, Daniel Borkmann wrote:
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);

Hi daniel

Thanks for the review and for verifying the crash reproduces without the fix.

I've applied your suggestion.



Reply via email to