From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: netdev@vger.kernel.org
Cc: Jiayuan Chen <jiayuan.chen@linux.dev>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next] macvlan: fix use-after-free of macvlan_port in macvlan_fill_info()
Date: Mon, 1 Jun 2026 14:13:03 +0800 [thread overview]
Message-ID: <20260601061304.344248-1-jiayuan.chen@linux.dev> (raw)
This issue was reported by our internal syzkaller [1].
rtnl_link_ops->macvlan_fill_info() reads and dereferences
'port = vlan->port'.
However, when we delete the underlying physical device of a
macvlan (e.g., eth0), we traverse all child macvlan devices and call
ndo_uninit -> macvlan_uninit.
Each child goes through ndo_uninit -> macvlan_uninit, which
synchronously kfree()s the shared port once the last child is gone, but
does not clear vlan->port. The child netdevice itself is NOT freed here:
its free_netdev() is deferred to netdev_run_todo(), and a concurrent
rtnl_getlink() additionally holds a reference via netdev_hold(). So the
netdevice stays alive with a now-dangling vlan->port, which
macvlan_fill_info() later dereferences -> use-after-free.
Here, we set vlan->port = NULL after kfree(port), and then add a NULL check
in macvlan_fill_info(). Both kfree(port) and vlan->port = NULL are atomic
under the protection of the rtnl lock, so this is safe.
In macvlan_fill_info(), if port does not exist, we should simply ignore it
and not goto nla_put_failure; otherwise, it would trigger WARN_ON_ONCE(1)
in rtnl_getlink().
vlan->port has no concurrent reader either (all under rtnl_lock, the
lockless xmit path is quiesced before macvlan_uninit()), so no
READ_ONCE()/WRITE_ONCE() is needed.
Before the blamed commit, rtnl_getlink() ran __dev_get_by_index() and
rtnl_fill_ifinfo() entirely under rtnl_lock, so it could not race with
macvlan_uninit().
[1]:
'''
BUG: KASAN: slab-use-after-free in macvlan_fill_info drivers/net/macvlan.c:1740
Call Trace:
<TASK>
macvlan_fill_info+0x681/0x750 drivers/net/macvlan.c:1740
rtnl_link_info_fill net/core/rtnetlink.c:905 [inline]
rtnl_link_fill net/core/rtnetlink.c:926 [inline]
rtnl_fill_ifinfo.isra.0+0x2ba7/0x4d70 net/core/rtnetlink.c:2185
rtnl_getlink+0x9b7/0xfc0 net/core/rtnetlink.c:4280
rtnetlink_rcv_msg+0x80f/0xd60 net/core/rtnetlink.c:7062
netlink_rcv_skb+0x15f/0x430 net/netlink/af_netlink.c:2556
rtnetlink_rcv+0x21/0x40 net/core/rtnetlink.c:7089
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x6ef/0xb50 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x8d8/0xd70 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec net/socket.c:787 [inline]
Allocated by task 5163:
macvlan_port_create drivers/net/macvlan.c:1260 [inline]
macvlan_common_newlink+0x45a/0x1ab0 drivers/net/macvlan.c:1498
macvlan_newlink+0x2a/0x40 drivers/net/macvlan.c:1596
rtnl_newlink_create net/core/rtnetlink.c:3905 [inline]
__rtnl_newlink net/core/rtnetlink.c:4036 [inline]
rtnl_newlink+0xd38/0x2360 net/core/rtnetlink.c:4151
rtnetlink_rcv_msg+0x80f/0xd60 net/core/rtnetlink.c:7062
netlink_rcv_skb+0x15f/0x430 net/netlink/af_netlink.c:2556
rtnetlink_rcv+0x21/0x40 net/core/rtnetlink.c:7089
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x6ef/0xb50 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x8d8/0xd70 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec net/socket.c:787 [inline]
Freed by task 5166:
macvlan_port_destroy+0x3c5/0x630 drivers/net/macvlan.c:1319
macvlan_uninit+0xf5/0x140 drivers/net/macvlan.c:977
unregister_netdevice_many_notify+0x108f/0x2140 net/core/dev.c:12454
unregister_netdevice_many+0x1e/0x30 net/core/dev.c:12496
macvlan_device_event+0x477/0x880 drivers/net/macvlan.c:1856
notifier_call_chain+0xb7/0x330 kernel/notifier.c:85
raw_notifier_call_chain+0x32/0x50 kernel/notifier.c:453
call_netdevice_notifiers_info+0xa7/0x100 net/core/dev.c:2249
call_netdevice_notifiers_extack net/core/dev.c:2287 [inline]
call_netdevice_notifiers net/core/dev.c:2301 [inline]
unregister_netdevice_many_notify+0xde2/0x2140 net/core/dev.c:12435
rtnl_delete_link net/core/rtnetlink.c:3593 [inline]
rtnl_dellink+0x3db/0xaf0 net/core/rtnetlink.c:3635
rtnetlink_rcv_msg+0x80f/0xd60 net/core/rtnetlink.c:7062
netlink_rcv_skb+0x15f/0x430 net/netlink/af_netlink.c:2556
rtnetlink_rcv+0x21/0x40 net/core/rtnetlink.c:7089
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x6ef/0xb50 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x8d8/0xd70 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec net/socket.c:787 [inline]
'''
Fixes: e896e5c0734b ("rtnetlink: do not acquire RTNL in rtnl_getlink() with RTEXT_FILTER_NAME_ONLY")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
drivers/net/macvlan.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index c40fa331836b..4ff3a4de972e 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -975,6 +975,8 @@ static void macvlan_uninit(struct net_device *dev)
port->count -= 1;
if (!port->count)
macvlan_port_destroy(port->dev);
+
+ vlan->port = NULL;
}
static void macvlan_dev_get_stats64(struct net_device *dev,
@@ -1736,12 +1738,14 @@ static int macvlan_fill_info(struct sk_buff *skb,
}
if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req))
goto nla_put_failure;
- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED,
- READ_ONCE(port->bc_queue_len_used)))
- goto nla_put_failure;
- if (port->bc_cutoff != 1 &&
- nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff))
- goto nla_put_failure;
+ if (port) {
+ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED,
+ READ_ONCE(port->bc_queue_len_used)))
+ goto nla_put_failure;
+ if (port->bc_cutoff != 1 &&
+ nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff))
+ goto nla_put_failure;
+ }
return 0;
nla_put_failure:
--
2.43.0
reply other threads:[~2026-06-01 6:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260601061304.344248-1-jiayuan.chen@linux.dev \
--to=jiayuan.chen@linux.dev \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox