| From ec3263f69091978da2a9fdac3931f079a2c340b9 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 2 Nov 2021 10:12:18 +0800 |
| Subject: net: vlan: fix a UAF in vlan_dev_real_dev() |
| |
| From: Ziyang Xuan <william.xuanziyang@huawei.com> |
| |
| [ Upstream commit 563bcbae3ba233c275c244bfce2efe12938f5363 ] |
| |
| The real_dev of a vlan net_device may be freed after |
| unregister_vlan_dev(). Access the real_dev continually by |
| vlan_dev_real_dev() will trigger the UAF problem for the |
| real_dev like following: |
| |
| ================================================================== |
| BUG: KASAN: use-after-free in vlan_dev_real_dev+0xf9/0x120 |
| Call Trace: |
| kasan_report.cold+0x83/0xdf |
| vlan_dev_real_dev+0xf9/0x120 |
| is_eth_port_of_netdev_filter.part.0+0xb1/0x2c0 |
| is_eth_port_of_netdev_filter+0x28/0x40 |
| ib_enum_roce_netdev+0x1a3/0x300 |
| ib_enum_all_roce_netdevs+0xc7/0x140 |
| netdevice_event_work_handler+0x9d/0x210 |
| ... |
| |
| Freed by task 9288: |
| kasan_save_stack+0x1b/0x40 |
| kasan_set_track+0x1c/0x30 |
| kasan_set_free_info+0x20/0x30 |
| __kasan_slab_free+0xfc/0x130 |
| slab_free_freelist_hook+0xdd/0x240 |
| kfree+0xe4/0x690 |
| kvfree+0x42/0x50 |
| device_release+0x9f/0x240 |
| kobject_put+0x1c8/0x530 |
| put_device+0x1b/0x30 |
| free_netdev+0x370/0x540 |
| ppp_destroy_interface+0x313/0x3d0 |
| ... |
| |
| Move the put_device(real_dev) to vlan_dev_free(). Ensure |
| real_dev not be freed before vlan_dev unregistered. |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Reported-by: syzbot+e4df4e1389e28972e955@syzkaller.appspotmail.com |
| Signed-off-by: Ziyang Xuan <william.xuanziyang@huawei.com> |
| Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/8021q/vlan.c | 3 --- |
| net/8021q/vlan_dev.c | 3 +++ |
| 2 files changed, 3 insertions(+), 3 deletions(-) |
| |
| diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c |
| index 3f47abf9ef4a6..cd7c0429cddf8 100644 |
| --- a/net/8021q/vlan.c |
| +++ b/net/8021q/vlan.c |
| @@ -116,9 +116,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
| } |
| |
| vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
| - |
| - /* Get rid of the vlan's reference to real_dev */ |
| - dev_put(real_dev); |
| } |
| |
| int vlan_check_real_dev(struct net_device *real_dev, |
| diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c |
| index 2a78da4072de9..415a29d42cdf0 100644 |
| --- a/net/8021q/vlan_dev.c |
| +++ b/net/8021q/vlan_dev.c |
| @@ -790,6 +790,9 @@ static void vlan_dev_free(struct net_device *dev) |
| |
| free_percpu(vlan->vlan_pcpu_stats); |
| vlan->vlan_pcpu_stats = NULL; |
| + |
| + /* Get rid of the vlan's reference to real_dev */ |
| + dev_put(vlan->real_dev); |
| } |
| |
| void vlan_setup(struct net_device *dev) |
| -- |
| 2.33.0 |
| |