Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bonding-fix-missing-xdp-compat-check-on-xmit_hash_policy-change'

Jiayuan Chen says:

====================
bonding: fix missing XDP compat check on xmit_hash_policy change

syzkaller reported a bug https://syzkaller.appspot.com/bug?extid=5a287bcdc08104bc3132

When a bond device is in 802.3ad or balance-xor mode, XDP is supported
only when xmit_hash_policy != vlan+srcmac. This constraint is enforced
in bond_option_mode_set() via bond_xdp_check(), which prevents switching
to an XDP-incompatible mode while a program is loaded. However, the
symmetric path -- changing xmit_hash_policy while XDP is loaded -- had
no such guard in bond_option_xmit_hash_policy_set().

This means the following sequence silently creates an inconsistent state:

1. Create a bond in 802.3ad mode with xmit_hash_policy=layer2+3.
2. Attach a native XDP program to the bond.
3. Change xmit_hash_policy to vlan+srcmac (no error, not checked).

Now bond->xdp_prog is set but bond_xdp_check() returns false for the
same device. When the bond is later torn down (e.g. netns deletion),
dev_xdp_uninstall() calls bond_xdp_set(dev, NULL) to remove the
program, which hits the bond_xdp_check() guard and returns -EOPNOTSUPP,
triggering a kernel WARNING:

bond1 (unregistering): Error: No native XDP support for the current bonding mode
------------[ cut here ]------------
dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL)
WARNING: net/core/dev.c:10361 at dev_xdp_uninstall net/core/dev.c:10361 [inline], CPU#0: kworker/u8:22/11031
Modules linked in:
CPU: 0 UID: 0 PID: 11031 Comm: kworker/u8:22 Not tainted syzkaller #0 PREEMPT(full)
Workqueue: netns cleanup_net
RIP: 0010:dev_xdp_uninstall net/core/dev.c:10361 [inline]
RIP: 0010:unregister_netdevice_many_notify+0x1efd/0x2370 net/core/dev.c:12393
RSP: 0018:ffffc90003b2f7c0 EFLAGS: 00010293
RAX: ffffffff8971e99c RBX: ffff888052f84c40 RCX: ffff88807896bc80
RDX: 0000000000000000 RSI: 00000000ffffffa1 RDI: 0000000000000000
RBP: ffffc90003b2f930 R08: ffffc90003b2f207 R09: 1ffff92000765e40
R10: dffffc0000000000 R11: fffff52000765e41 R12: 00000000ffffffa1
R13: ffff888052f84c38 R14: 1ffff1100a5f0988 R15: ffffc9000df67000
FS: 0000000000000000(0000) GS:ffff8881254ae000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f60871d5d58 CR3: 000000006c41c000 CR4: 00000000003526f0
Call Trace:
<TASK>
ops_exit_rtnl_list net/core/net_namespace.c:187 [inline]
ops_undo_list+0x3d3/0x940 net/core/net_namespace.c:248
cleanup_net+0x56b/0x800 net/core/net_namespace.c:704
process_one_work kernel/workqueue.c:3275 [inline]
process_scheduled_works+0xaec/0x17a0 kernel/workqueue.c:3358
worker_thread+0xa50/0xfc0 kernel/workqueue.c:3439
kthread+0x388/0x470 kernel/kthread.c:467
ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>

Beyond the WARNING itself, when dev_xdp_install() fails during
dev_xdp_uninstall(), bond_xdp_set() returns early without calling
bpf_prog_put() on the old program. dev_xdp_uninstall() then releases
only the reference held by dev->xdp_state[], while the reference held
by bond->xdp_prog is never dropped, leaking the struct bpf_prog.

The fix refactors the core logic of bond_xdp_check() into a new helper
__bond_xdp_check_mode(mode, xmit_policy) that takes both parameters
explicitly, avoiding the need to read them from the bond struct.
bond_xdp_check() becomes a thin wrapper around it.
bond_option_xmit_hash_policy_set() then uses __bond_xdp_check_mode()
directly, passing the candidate xmit_policy before it is committed,
mirroring exactly what bond_option_mode_set() already does for mode
changes.

Patch 1 adds the kernel fix.
Patch 2 adds a selftest that reproduces the WARNING by attaching native
XDP to a bond in 802.3ad mode, then attempting to change xmit_hash_policy
to vlan+srcmac -- verifying the change is rejected with the fix applied.
====================

Link: https://patch.msgid.link/20260226080306.98766-1-jiayuan.chen@linux.dev
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+68 -2
+7 -2
drivers/net/bonding/bond_main.c
··· 324 324 } 325 325 } 326 326 327 - bool bond_xdp_check(struct bonding *bond, int mode) 327 + bool __bond_xdp_check(int mode, int xmit_policy) 328 328 { 329 329 switch (mode) { 330 330 case BOND_MODE_ROUNDROBIN: ··· 335 335 /* vlan+srcmac is not supported with XDP as in most cases the 802.1q 336 336 * payload is not in the packet due to hardware offload. 337 337 */ 338 - if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC) 338 + if (xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC) 339 339 return true; 340 340 fallthrough; 341 341 default: 342 342 return false; 343 343 } 344 + } 345 + 346 + bool bond_xdp_check(struct bonding *bond, int mode) 347 + { 348 + return __bond_xdp_check(mode, bond->params.xmit_policy); 344 349 } 345 350 346 351 /*---------------------------------- VLAN -----------------------------------*/
+2
drivers/net/bonding/bond_options.c
··· 1575 1575 static int bond_option_xmit_hash_policy_set(struct bonding *bond, 1576 1576 const struct bond_opt_value *newval) 1577 1577 { 1578 + if (bond->xdp_prog && !__bond_xdp_check(BOND_MODE(bond), newval->value)) 1579 + return -EOPNOTSUPP; 1578 1580 netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n", 1579 1581 newval->string, newval->value); 1580 1582 bond->params.xmit_policy = newval->value;
+1
include/net/bonding.h
··· 699 699 void bond_debug_unregister(struct bonding *bond); 700 700 void bond_debug_reregister(struct bonding *bond); 701 701 const char *bond_mode_name(int mode); 702 + bool __bond_xdp_check(int mode, int xmit_policy); 702 703 bool bond_xdp_check(struct bonding *bond, int mode); 703 704 void bond_setup(struct net_device *bond_dev); 704 705 unsigned int bond_get_num_tx_queues(void);
+58
tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
··· 610 610 system("ip link del bond"); 611 611 } 612 612 613 + /* 614 + * Test that changing xmit_hash_policy to vlan+srcmac is rejected when a 615 + * native XDP program is loaded on a bond in 802.3ad or balance-xor mode. 616 + * These modes support XDP only when xmit_hash_policy != vlan+srcmac; freely 617 + * changing the policy creates an inconsistency that triggers a WARNING in 618 + * dev_xdp_uninstall() during device teardown. 619 + */ 620 + static void test_xdp_bonding_xmit_policy_compat(struct skeletons *skeletons) 621 + { 622 + struct nstoken *nstoken = NULL; 623 + int bond_ifindex = -1; 624 + int xdp_fd, err; 625 + 626 + SYS(out, "ip netns add ns_xmit_policy"); 627 + nstoken = open_netns("ns_xmit_policy"); 628 + if (!ASSERT_OK_PTR(nstoken, "open ns_xmit_policy")) 629 + goto out; 630 + 631 + /* 802.3ad with layer2+3 policy: native XDP is supported */ 632 + SYS(out, "ip link add bond0 type bond mode 802.3ad xmit_hash_policy layer2+3"); 633 + SYS(out, "ip link add veth0 type veth peer name veth0p"); 634 + SYS(out, "ip link set veth0 master bond0"); 635 + SYS(out, "ip link set bond0 up"); 636 + 637 + bond_ifindex = if_nametoindex("bond0"); 638 + if (!ASSERT_GT(bond_ifindex, 0, "bond0 ifindex")) 639 + goto out; 640 + 641 + xdp_fd = bpf_program__fd(skeletons->xdp_dummy->progs.xdp_dummy_prog); 642 + if (!ASSERT_GE(xdp_fd, 0, "xdp_dummy fd")) 643 + goto out; 644 + 645 + err = bpf_xdp_attach(bond_ifindex, xdp_fd, XDP_FLAGS_DRV_MODE, NULL); 646 + if (!ASSERT_OK(err, "attach XDP to bond0")) 647 + goto out; 648 + 649 + /* With XDP loaded, switching to vlan+srcmac must be rejected */ 650 + err = system("ip link set bond0 type bond xmit_hash_policy vlan+srcmac 2>/dev/null"); 651 + ASSERT_NEQ(err, 0, "vlan+srcmac change with XDP loaded should fail"); 652 + 653 + /* Detach XDP first, then the same change must succeed */ 654 + ASSERT_OK(bpf_xdp_detach(bond_ifindex, XDP_FLAGS_DRV_MODE, NULL), 655 + "detach XDP from bond0"); 656 + 657 + bond_ifindex = -1; 658 + err = system("ip link set bond0 type bond xmit_hash_policy vlan+srcmac 2>/dev/null"); 659 + ASSERT_OK(err, "vlan+srcmac change without XDP should succeed"); 660 + 661 + out: 662 + if (bond_ifindex > 0) 663 + bpf_xdp_detach(bond_ifindex, XDP_FLAGS_DRV_MODE, NULL); 664 + close_netns(nstoken); 665 + SYS_NOFAIL("ip netns del ns_xmit_policy"); 666 + } 667 + 613 668 static int libbpf_debug_print(enum libbpf_print_level level, 614 669 const char *format, va_list args) 615 670 { ··· 731 676 test_case->mode, 732 677 test_case->xmit_policy); 733 678 } 679 + 680 + if (test__start_subtest("xdp_bonding_xmit_policy_compat")) 681 + test_xdp_bonding_xmit_policy_compat(&skeletons); 734 682 735 683 if (test__start_subtest("xdp_bonding_redirect_multi")) 736 684 test_xdp_bonding_redirect_multi(&skeletons);