Re: [PATCH net] macvlan: require lower-netns admin for shared port settings

From: Xiang Mei

Date: Wed Jul 29 2026 - 14:37:06 EST


On Sun, Jul 26, 2026 at 5:54 AM Doruk Tan Ozturk <doruk@xxxxxxx> wrote:
>
> A macvlan device can be moved to a network namespace whose user
> namespace does not administer the lower device. The rtnetlink
> changelink path checks CAP_NET_ADMIN only in the macvlan device network
> namespace. However, IFLA_MACVLAN_BC_QUEUE_LEN and
> IFLA_MACVLAN_BC_CUTOFF update macvlan_port fields shared by every
> macvlan on the lower device.
>
> A caller can also create a nested macvlan on the moved device.
> macvlan_common_newlink() resolves that device to the real lower device
> without rechecking access to its network namespace.
>
> Xiang Mei reported that a caller can set the shared broadcast queue
> length to U32_MAX from an unprivileged user namespace and grow the host
> backlog until OOM under an incoming broadcast flood. A fixed numeric
> limit was proposed, but legitimate deployments use queue lengths of
> 100000 or more.
>
> Require CAP_NET_ADMIN in the lower device network namespace for shared
> port changes and nested macvlan creation. Per-device settings remain
> available to an administrator of the macvlan device network namespace.
> This matches the permission model used by ipvlan.
>
> Found by 0sec automated security-research tooling (https://0sec.ai).
>
> Reported-by: Xiang Mei (Microsoft) <xmei5@xxxxxxx>
> Closes: https://lore.kernel.org/r/20260706212556.3199234-1-xmei5@xxxxxxx

Hi Doruk, it's a real issue, but it's a different bug from mine. Can
you drop the reported-by/closes related to me?

The two cases differ in who the caller is. Yours is a caller who does not
administer the lower device. Mine administers everything involved: it
unshares a user+net namespace, creates a veth there, and puts the macvlan
on that veth.

I proved that it's a different bug by triggering the same crash on the
kernel with your patch:

```log
[ 15.527061] Out of memory: Killed process 156 (exploit) total-vm:1044kB, an0
[ 15.570960] Out of memory: Killed process 155 (exploit) total-vm:1044kB, an0
[ 15.581119] Out of memory: Killed process 154 (exploit) total-vm:1044kB, an0
[ 15.586159] Out of memory: Killed process 153 (exploit) total-vm:1044kB, an0
[ 15.590773] Out of memory: Killed process 152 (exploit) total-vm:1044kB, an0
[ 15.596233] Out of memory: Killed process 151 (exploit) total-vm:1044kB, an0
[ 15.604532] Out of memory: Killed process 142 (exploit) total-vm:1044kB, an0
[ 15.610991] Out of memory: Killed process 141 (su) total-vm:4508kB, anon-rs0
[ 15.688053] Out of memory: Killed process 130 (init.sh) total-vm:3992kB, an0
[ 15.723989] Kernel panic - not syncing: System is deadlocked on memory
[ 15.725438] CPU: 0 UID: 0 PID: 1 Comm: init Not tainted 7.2.0-rc4+ #3 PREEM
[ 15.727084] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_cap4
[ 15.729530] Call Trace:
[ 15.730097] <TASK>
[ 15.730588] vpanic+0x6b7/0x7a0
[ 15.731311] ? __pfx_vpanic+0x10/0x10
[ 15.732133] panic+0xca/0xd0
[ 15.732793] ? __pfx_panic+0x10/0x10
[ 15.733602] ? panic_on_this_cpu+0x1a/0x40
[ 15.734510] out_of_memory+0x121b/0x13a0
[ 15.735385] ? __pfx_out_of_memory+0x10/0x10
[ 15.736343] __alloc_frozen_pages_noprof+0x28df/0x3350
[ 15.737463] ? srso_alias_return_thunk+0x5/0xfbef5
[ 15.738512] ? blk_mq_flush_plug_list+0x1a5/0x6b0
[ 15.739553] ? submit_bio_noacct+0x270/0x1630
[ 15.740520] ? __pfx___alloc_frozen_pages_noprof+0x10/0x10
...
```

> Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate")
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: 0sec:multi-model
> Signed-off-by: Doruk Tan Ozturk <doruk@xxxxxxx>
> ---
> drivers/net/macvlan.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
> index 9a4bc99dbf53b..22f03b206c718 100644
> --- a/drivers/net/macvlan.c
> +++ b/drivers/net/macvlan.c
> @@ -1483,8 +1483,11 @@ int macvlan_common_newlink(struct net_device *dev,
> /* When creating macvlans or macvtaps on top of other macvlans - use
> * the real device as the lowerdev.
> */
> - if (netif_is_macvlan(lowerdev))
> + if (netif_is_macvlan(lowerdev)) {
> lowerdev = macvlan_dev_real_dev(lowerdev);
> + if (!rtnl_dev_link_net_capable(dev, dev_net(lowerdev)))
> + return -EPERM;
> + }
>
> if (!tb[IFLA_MTU])
> dev->mtu = lowerdev->mtu;
> @@ -1623,6 +1626,12 @@ static int macvlan_changelink(struct net_device *dev,
> enum macvlan_macaddr_mode macmode;
> int ret;
>
> + if (data &&
> + (data[IFLA_MACVLAN_BC_QUEUE_LEN] ||
> + data[IFLA_MACVLAN_BC_CUTOFF]) &&
> + !rtnl_dev_link_net_capable(dev, dev_net(vlan->lowerdev)))
> + return -EPERM;
> +
> /* Validate mode, but don't set yet: setting flags may fail. */
> if (data && data[IFLA_MACVLAN_MODE]) {
> set_mode = true;
> --
> 2.43.0
>