* [PATCH v1 net] ipvlan: Fix use-after-free in ipvlan_get_iflink().
@ 2025-01-01 9:10 Kuniyuki Iwashima
2025-01-03 1:44 ` Jakub Kicinski
0 siblings, 1 reply; 3+ messages in thread
From: Kuniyuki Iwashima @ 2025-01-01 9:10 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman
Cc: Mahesh Bandewar, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
syzkaller
syzbot presented a use-after-free report [0] regarding ipvlan and
linkwatch.
ipvlan does not hold a refcnt of the lower device.
When the linkwatch work is triggered for the ipvlan dev, the lower
dev might have already been freed.
Let's hold the lower dev's refcnt in dev->netdev_ops->ndo_init()
and release it in dev->priv_destructor() as done for vlan and macvlan.
[0]:
BUG: KASAN: slab-use-after-free in ipvlan_get_iflink+0x84/0x88 drivers/net/ipvlan/ipvlan_main.c:353
Read of size 4 at addr ffff0000d768c0e0 by task kworker/u8:35/6944
CPU: 0 UID: 0 PID: 6944 Comm: kworker/u8:35 Not tainted 6.13.0-rc2-g9bc5c9515b48 #12 4c3cb9e8b4565456f6a355f312ff91f4f29b3c47
Hardware name: linux,dummy-virt (DT)
Workqueue: events_unbound linkwatch_event
Call trace:
show_stack+0x38/0x50 arch/arm64/kernel/stacktrace.c:484 (C)
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0xbc/0x108 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0x16c/0x6f0 mm/kasan/report.c:489
kasan_report+0xc0/0x120 mm/kasan/report.c:602
__asan_report_load4_noabort+0x20/0x30 mm/kasan/report_generic.c:380
ipvlan_get_iflink+0x84/0x88 drivers/net/ipvlan/ipvlan_main.c:353
dev_get_iflink+0x7c/0xd8 net/core/dev.c:674
default_operstate net/core/link_watch.c:45 [inline]
rfc2863_policy+0x144/0x360 net/core/link_watch.c:72
linkwatch_do_dev+0x60/0x228 net/core/link_watch.c:175
__linkwatch_run_queue+0x2f4/0x5b8 net/core/link_watch.c:239
linkwatch_event+0x64/0xa8 net/core/link_watch.c:282
process_one_work+0x700/0x1398 kernel/workqueue.c:3229
process_scheduled_works kernel/workqueue.c:3310 [inline]
worker_thread+0x8c4/0xe10 kernel/workqueue.c:3391
kthread+0x2b0/0x360 kernel/kthread.c:389
ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:862
Allocated by task 9303:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x30/0x68 mm/kasan/common.c:68
kasan_save_alloc_info+0x44/0x58 mm/kasan/generic.c:568
poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
__kasan_kmalloc+0x84/0xa0 mm/kasan/common.c:394
kasan_kmalloc include/linux/kasan.h:260 [inline]
__do_kmalloc_node mm/slub.c:4283 [inline]
__kmalloc_node_noprof+0x2a0/0x560 mm/slub.c:4289
__kvmalloc_node_noprof+0x9c/0x230 mm/util.c:650
alloc_netdev_mqs+0xb4/0x1118 net/core/dev.c:11209
rtnl_create_link+0x2b8/0xb60 net/core/rtnetlink.c:3595
rtnl_newlink_create+0x19c/0x868 net/core/rtnetlink.c:3771
__rtnl_newlink net/core/rtnetlink.c:3896 [inline]
rtnl_newlink+0x122c/0x15c0 net/core/rtnetlink.c:4011
rtnetlink_rcv_msg+0x61c/0x918 net/core/rtnetlink.c:6901
netlink_rcv_skb+0x1dc/0x398 net/netlink/af_netlink.c:2542
rtnetlink_rcv+0x34/0x50 net/core/rtnetlink.c:6928
netlink_unicast_kernel net/netlink/af_netlink.c:1321 [inline]
netlink_unicast+0x618/0x838 net/netlink/af_netlink.c:1347
netlink_sendmsg+0x5fc/0x8b0 net/netlink/af_netlink.c:1891
sock_sendmsg_nosec net/socket.c:711 [inline]
__sock_sendmsg net/socket.c:726 [inline]
__sys_sendto+0x2ec/0x438 net/socket.c:2197
__do_sys_sendto net/socket.c:2204 [inline]
__se_sys_sendto net/socket.c:2200 [inline]
__arm64_sys_sendto+0xe4/0x110 net/socket.c:2200
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x90/0x278 arch/arm64/kernel/syscall.c:49
el0_svc_common+0x13c/0x250 arch/arm64/kernel/syscall.c:132
do_el0_svc+0x54/0x70 arch/arm64/kernel/syscall.c:151
el0_svc+0x4c/0xa8 arch/arm64/kernel/entry-common.c:744
el0t_64_sync_handler+0x78/0x108 arch/arm64/kernel/entry-common.c:762
el0t_64_sync+0x198/0x1a0 arch/arm64/kernel/entry.S:600
Freed by task 10200:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x30/0x68 mm/kasan/common.c:68
kasan_save_free_info+0x58/0x70 mm/kasan/generic.c:582
poison_slab_object mm/kasan/common.c:247 [inline]
__kasan_slab_free+0x48/0x68 mm/kasan/common.c:264
kasan_slab_free include/linux/kasan.h:233 [inline]
slab_free_hook mm/slub.c:2338 [inline]
slab_free mm/slub.c:4598 [inline]
kfree+0x140/0x420 mm/slub.c:4746
kvfree+0x4c/0x68 mm/util.c:693
netdev_release+0x94/0xc8 net/core/net-sysfs.c:2034
device_release+0x98/0x1c0
kobject_cleanup lib/kobject.c:689 [inline]
kobject_release lib/kobject.c:720 [inline]
kref_put include/linux/kref.h:65 [inline]
kobject_put+0x2b0/0x438 lib/kobject.c:737
netdev_run_todo+0xdd8/0xf48 net/core/dev.c:10924
rtnl_unlock net/core/rtnetlink.c:152 [inline]
rtnl_net_unlock net/core/rtnetlink.c:209 [inline]
rtnl_dellink+0x484/0x680 net/core/rtnetlink.c:3526
rtnetlink_rcv_msg+0x61c/0x918 net/core/rtnetlink.c:6901
netlink_rcv_skb+0x1dc/0x398 net/netlink/af_netlink.c:2542
rtnetlink_rcv+0x34/0x50 net/core/rtnetlink.c:6928
netlink_unicast_kernel net/netlink/af_netlink.c:1321 [inline]
netlink_unicast+0x618/0x838 net/netlink/af_netlink.c:1347
netlink_sendmsg+0x5fc/0x8b0 net/netlink/af_netlink.c:1891
sock_sendmsg_nosec net/socket.c:711 [inline]
__sock_sendmsg net/socket.c:726 [inline]
____sys_sendmsg+0x410/0x708 net/socket.c:2583
___sys_sendmsg+0x178/0x1d8 net/socket.c:2637
__sys_sendmsg net/socket.c:2669 [inline]
__do_sys_sendmsg net/socket.c:2674 [inline]
__se_sys_sendmsg net/socket.c:2672 [inline]
__arm64_sys_sendmsg+0x12c/0x1c8 net/socket.c:2672
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x90/0x278 arch/arm64/kernel/syscall.c:49
el0_svc_common+0x13c/0x250 arch/arm64/kernel/syscall.c:132
do_el0_svc+0x54/0x70 arch/arm64/kernel/syscall.c:151
el0_svc+0x4c/0xa8 arch/arm64/kernel/entry-common.c:744
el0t_64_sync_handler+0x78/0x108 arch/arm64/kernel/entry-common.c:762
el0t_64_sync+0x198/0x1a0 arch/arm64/kernel/entry.S:600
The buggy address belongs to the object at ffff0000d768c000
which belongs to the cache kmalloc-cg-4k of size 4096
The buggy address is located 224 bytes inside of
freed 4096-byte region [ffff0000d768c000, ffff0000d768d000)
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x117688
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
memcg:ffff0000c77ef981
flags: 0xbfffe0000000040(head|node=0|zone=2|lastcpupid=0x1ffff)
page_type: f5(slab)
raw: 0bfffe0000000040 ffff0000c000f500 dead000000000100 dead000000000122
raw: 0000000000000000 0000000000040004 00000001f5000000 ffff0000c77ef981
head: 0bfffe0000000040 ffff0000c000f500 dead000000000100 dead000000000122
head: 0000000000000000 0000000000040004 00000001f5000000 ffff0000c77ef981
head: 0bfffe0000000003 fffffdffc35da201 ffffffffffffffff 0000000000000000
head: 0000000000000008 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff0000d768bf80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff0000d768c000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff0000d768c080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff0000d768c100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff0000d768c180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.")
Reported-by: syzkaller <syzkaller@googlegroups.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
drivers/net/ipvlan/ipvlan.h | 1 +
drivers/net/ipvlan/ipvlan_main.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index 025e0c19ec25..3d22e0c7805d 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -70,6 +70,7 @@ struct ipvl_dev {
netdev_features_t sfeatures;
u32 msg_enable;
spinlock_t addrs_lock;
+ netdevice_tracker dev_tracker;
};
struct ipvl_addr {
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index ee2c3cf4df36..3566b21f49d5 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -160,6 +160,9 @@ static int ipvlan_init(struct net_device *dev)
}
port = ipvlan_port_get_rtnl(phy_dev);
port->count += 1;
+
+ netdev_hold(phy_dev, &ipvlan->dev_tracker, GFP_KERNEL);
+
return 0;
}
@@ -669,6 +672,13 @@ void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
}
EXPORT_SYMBOL_GPL(ipvlan_link_delete);
+static void ipvlan_link_destruct(struct net_device *dev)
+{
+ struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+ netdev_put(ipvlan->phy_dev, &ipvlan->dev_tracker);
+}
+
void ipvlan_link_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -678,6 +688,7 @@ void ipvlan_link_setup(struct net_device *dev)
dev->priv_flags |= IFF_UNICAST_FLT | IFF_NO_QUEUE;
dev->netdev_ops = &ipvlan_netdev_ops;
dev->needs_free_netdev = true;
+ dev->priv_destructor = ipvlan_link_destruct;
dev->header_ops = &ipvlan_header_ops;
dev->ethtool_ops = &ipvlan_ethtool_ops;
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v1 net] ipvlan: Fix use-after-free in ipvlan_get_iflink().
2025-01-01 9:10 [PATCH v1 net] ipvlan: Fix use-after-free in ipvlan_get_iflink() Kuniyuki Iwashima
@ 2025-01-03 1:44 ` Jakub Kicinski
2025-01-03 13:37 ` Kuniyuki Iwashima
0 siblings, 1 reply; 3+ messages in thread
From: Jakub Kicinski @ 2025-01-03 1:44 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Andrew Lunn,
Simon Horman, Mahesh Bandewar, Kuniyuki Iwashima, netdev,
syzkaller
On Wed, 1 Jan 2025 18:10:08 +0900 Kuniyuki Iwashima wrote:
> syzbot presented a use-after-free report [0] regarding ipvlan and
> linkwatch.
>
> ipvlan does not hold a refcnt of the lower device.
>
> When the linkwatch work is triggered for the ipvlan dev, the lower
> dev might have already been freed.
>
> Let's hold the lower dev's refcnt in dev->netdev_ops->ndo_init()
> and release it in dev->priv_destructor() as done for vlan and macvlan.
Hmmm, random ndo calls after unregister_netdevice() has returned
are very error prone, if we can address this in the core - I think
that's better.
Perhaps we could take Eric's commit 750e51603395 ("net: avoid potential
UAF in default_operstate()") even further?
If the device is unregistering we can just assume DOWN. And we can use
RCU protection to make sure the unregistration doesn't race with us?
Just to give the idea (not even compile tested):
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index 1b4d39e38084..985273bc7c0d 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -42,14 +42,20 @@ static unsigned int default_operstate(const struct net_device *dev)
* first check whether lower is indeed the source of its down state.
*/
if (!netif_carrier_ok(dev)) {
- int iflink = dev_get_iflink(dev);
struct net_device *peer;
+ int iflink;
/* If called from netdev_run_todo()/linkwatch_sync_dev(),
* dev_net(dev) can be already freed, and RTNL is not held.
*/
- if (dev->reg_state == NETREG_UNREGISTERED ||
- iflink == dev->ifindex)
+ rcu_read_lock();
+ if (dev->reg_state <= NETREG_REGISTERED)
+ iflink = dev_get_iflink(dev);
+ else
+ iflink = dev->ifindex;
+ rcu_read_unlock();
+
+ if (iflink == dev->ifindex)
return IF_OPER_DOWN;
ASSERT_RTNL();
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v1 net] ipvlan: Fix use-after-free in ipvlan_get_iflink().
2025-01-03 1:44 ` Jakub Kicinski
@ 2025-01-03 13:37 ` Kuniyuki Iwashima
0 siblings, 0 replies; 3+ messages in thread
From: Kuniyuki Iwashima @ 2025-01-03 13:37 UTC (permalink / raw)
To: kuba
Cc: andrew+netdev, davem, edumazet, horms, kuni1840, kuniyu, maheshb,
netdev, pabeni, syzkaller
From: Jakub Kicinski <kuba@kernel.org>
Date: Thu, 2 Jan 2025 17:44:00 -0800
> On Wed, 1 Jan 2025 18:10:08 +0900 Kuniyuki Iwashima wrote:
> > syzbot presented a use-after-free report [0] regarding ipvlan and
> > linkwatch.
> >
> > ipvlan does not hold a refcnt of the lower device.
> >
> > When the linkwatch work is triggered for the ipvlan dev, the lower
> > dev might have already been freed.
> >
> > Let's hold the lower dev's refcnt in dev->netdev_ops->ndo_init()
> > and release it in dev->priv_destructor() as done for vlan and macvlan.
>
> Hmmm, random ndo calls after unregister_netdevice() has returned
> are very error prone, if we can address this in the core - I think
> that's better.
>
> Perhaps we could take Eric's commit 750e51603395 ("net: avoid potential
> UAF in default_operstate()") even further?
>
> If the device is unregistering we can just assume DOWN. And we can use
> RCU protection to make sure the unregistration doesn't race with us?
Sounds good to me.
Will post v2, thanks!
> Just to give the idea (not even compile tested):
>
> diff --git a/net/core/link_watch.c b/net/core/link_watch.c
> index 1b4d39e38084..985273bc7c0d 100644
> --- a/net/core/link_watch.c
> +++ b/net/core/link_watch.c
> @@ -42,14 +42,20 @@ static unsigned int default_operstate(const struct net_device *dev)
> * first check whether lower is indeed the source of its down state.
> */
> if (!netif_carrier_ok(dev)) {
> - int iflink = dev_get_iflink(dev);
> struct net_device *peer;
> + int iflink;
>
> /* If called from netdev_run_todo()/linkwatch_sync_dev(),
> * dev_net(dev) can be already freed, and RTNL is not held.
> */
> - if (dev->reg_state == NETREG_UNREGISTERED ||
> - iflink == dev->ifindex)
> + rcu_read_lock();
> + if (dev->reg_state <= NETREG_REGISTERED)
> + iflink = dev_get_iflink(dev);
> + else
> + iflink = dev->ifindex;
> + rcu_read_unlock();
> +
> + if (iflink == dev->ifindex)
> return IF_OPER_DOWN;
>
> ASSERT_RTNL();
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-01-03 13:38 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-01 9:10 [PATCH v1 net] ipvlan: Fix use-after-free in ipvlan_get_iflink() Kuniyuki Iwashima
2025-01-03 1:44 ` Jakub Kicinski
2025-01-03 13:37 ` Kuniyuki Iwashima
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).