mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
net: rmnet: use upper/lower device infrastructure
netdev_upper_dev_link() is useful to manage lower/upper interfaces.
And this function internally validates looping, maximum depth.
All or most virtual interfaces that could have a real interface
(e.g. macsec, macvlan, ipvlan etc.) use lower/upper infrastructure.
Test commands:
modprobe rmnet
ip link add dummy0 type dummy
ip link add rmnet1 link dummy0 type rmnet mux_id 1
for i in {2..100}
do
let A=$i-1
ip link add rmnet$i link rmnet$A type rmnet mux_id $i
done
ip link del dummy0
The purpose of the test commands is to make stack overflow.
Splat looks like:
[ 52.411438][ T1395] BUG: KASAN: slab-out-of-bounds in find_busiest_group+0x27e/0x2c00
[ 52.413218][ T1395] Write of size 64 at addr ffff8880c774bde0 by task ip/1395
[ 52.414841][ T1395]
[ 52.430720][ T1395] CPU: 1 PID: 1395 Comm: ip Not tainted 5.6.0-rc1+ #447
[ 52.496511][ T1395] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 52.513597][ T1395] Call Trace:
[ 52.546516][ T1395]
[ 52.558773][ T1395] Allocated by task 3171537984:
[ 52.588290][ T1395] BUG: unable to handle page fault for address: ffffffffb999e260
[ 52.589311][ T1395] #PF: supervisor read access in kernel mode
[ 52.590529][ T1395] #PF: error_code(0x0000) - not-present page
[ 52.591374][ T1395] PGD d6818067 P4D d6818067 PUD d6819063 PMD 0
[ 52.592288][ T1395] Thread overran stack, or stack corrupted
[ 52.604980][ T1395] Oops: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN PTI
[ 52.605856][ T1395] CPU: 1 PID: 1395 Comm: ip Not tainted 5.6.0-rc1+ #447
[ 52.611764][ T1395] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 52.621520][ T1395] RIP: 0010:stack_depot_fetch+0x10/0x30
[ 52.622296][ T1395] Code: ff e9 f9 fe ff ff 48 89 df e8 9c 1d 91 ff e9 ca fe ff ff cc cc cc cc cc cc cc 89 f8 0
[ 52.627887][ T1395] RSP: 0018:ffff8880c774bb60 EFLAGS: 00010006
[ 52.628735][ T1395] RAX: 00000000001f8880 RBX: ffff8880c774d140 RCX: 0000000000000000
[ 52.631773][ T1395] RDX: 000000000000001d RSI: ffff8880c774bb68 RDI: 0000000000003ff0
[ 52.649584][ T1395] RBP: ffffea00031dd200 R08: ffffed101b43e403 R09: ffffed101b43e403
[ 52.674857][ T1395] R10: 0000000000000001 R11: ffffed101b43e402 R12: ffff8880d900e5c0
[ 52.678257][ T1395] R13: ffff8880c774c000 R14: 0000000000000000 R15: dffffc0000000000
[ 52.694541][ T1395] FS: 00007fe867f6e0c0(0000) GS:ffff8880da000000(0000) knlGS:0000000000000000
[ 52.764039][ T1395] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 52.815008][ T1395] CR2: ffffffffb999e260 CR3: 00000000c26aa005 CR4: 00000000000606e0
[ 52.862312][ T1395] Call Trace:
[ 52.887133][ T1395] Modules linked in: dummy rmnet veth openvswitch nsh nf_conncount nf_nat nf_conntrack nf_dex
[ 52.936749][ T1395] CR2: ffffffffb999e260
[ 52.965695][ T1395] ---[ end trace 7e32ca99482dbb31 ]---
[ 52.966556][ T1395] RIP: 0010:stack_depot_fetch+0x10/0x30
[ 52.971083][ T1395] Code: ff e9 f9 fe ff ff 48 89 df e8 9c 1d 91 ff e9 ca fe ff ff cc cc cc cc cc cc cc 89 f8 0
[ 53.003650][ T1395] RSP: 0018:ffff8880c774bb60 EFLAGS: 00010006
[ 53.043183][ T1395] RAX: 00000000001f8880 RBX: ffff8880c774d140 RCX: 0000000000000000
[ 53.076480][ T1395] RDX: 000000000000001d RSI: ffff8880c774bb68 RDI: 0000000000003ff0
[ 53.093858][ T1395] RBP: ffffea00031dd200 R08: ffffed101b43e403 R09: ffffed101b43e403
[ 53.112795][ T1395] R10: 0000000000000001 R11: ffffed101b43e402 R12: ffff8880d900e5c0
[ 53.139837][ T1395] R13: ffff8880c774c000 R14: 0000000000000000 R15: dffffc0000000000
[ 53.141500][ T1395] FS: 00007fe867f6e0c0(0000) GS:ffff8880da000000(0000) knlGS:0000000000000000
[ 53.143343][ T1395] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 53.152007][ T1395] CR2: ffffffffb999e260 CR3: 00000000c26aa005 CR4: 00000000000606e0
[ 53.156459][ T1395] Kernel panic - not syncing: Fatal exception
[ 54.213570][ T1395] Shutting down cpus with NMI
[ 54.354112][ T1395] Kernel Offset: 0x33000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0x)
[ 54.355687][ T1395] Rebooting in 5 seconds..
Fixes: b37f78f234
("net: qualcomm: rmnet: Fix crash on real dev unregistration")
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1dc49e9d16
commit
037f9cdf72
@ -61,9 +61,6 @@ static int rmnet_unregister_real_device(struct net_device *real_dev,
|
|||||||
|
|
||||||
kfree(port);
|
kfree(port);
|
||||||
|
|
||||||
/* release reference on real_dev */
|
|
||||||
dev_put(real_dev);
|
|
||||||
|
|
||||||
netdev_dbg(real_dev, "Removed from rmnet\n");
|
netdev_dbg(real_dev, "Removed from rmnet\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -89,9 +86,6 @@ static int rmnet_register_real_device(struct net_device *real_dev)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hold on to real dev for MAP data */
|
|
||||||
dev_hold(real_dev);
|
|
||||||
|
|
||||||
for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
|
for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
|
||||||
INIT_HLIST_HEAD(&port->muxed_ep[entry]);
|
INIT_HLIST_HEAD(&port->muxed_ep[entry]);
|
||||||
|
|
||||||
@ -162,6 +156,10 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
|
|||||||
if (err)
|
if (err)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
|
err = netdev_upper_dev_link(real_dev, dev, extack);
|
||||||
|
if (err < 0)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
port->rmnet_mode = mode;
|
port->rmnet_mode = mode;
|
||||||
|
|
||||||
hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
|
hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
|
||||||
@ -178,6 +176,8 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
unregister_netdevice(dev);
|
||||||
err1:
|
err1:
|
||||||
rmnet_unregister_real_device(real_dev, port);
|
rmnet_unregister_real_device(real_dev, port);
|
||||||
err0:
|
err0:
|
||||||
@ -209,33 +209,30 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
|
|||||||
rmnet_vnd_dellink(mux_id, port, ep);
|
rmnet_vnd_dellink(mux_id, port, ep);
|
||||||
kfree(ep);
|
kfree(ep);
|
||||||
}
|
}
|
||||||
|
netdev_upper_dev_unlink(real_dev, dev);
|
||||||
rmnet_unregister_real_device(real_dev, port);
|
rmnet_unregister_real_device(real_dev, port);
|
||||||
|
|
||||||
unregister_netdevice_queue(dev, head);
|
unregister_netdevice_queue(dev, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rmnet_force_unassociate_device(struct net_device *dev)
|
static void rmnet_force_unassociate_device(struct net_device *real_dev)
|
||||||
{
|
{
|
||||||
struct net_device *real_dev = dev;
|
|
||||||
struct hlist_node *tmp_ep;
|
struct hlist_node *tmp_ep;
|
||||||
struct rmnet_endpoint *ep;
|
struct rmnet_endpoint *ep;
|
||||||
struct rmnet_port *port;
|
struct rmnet_port *port;
|
||||||
unsigned long bkt_ep;
|
unsigned long bkt_ep;
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
|
|
||||||
if (!rmnet_is_real_dev_registered(real_dev))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
port = rmnet_get_port_rtnl(dev);
|
port = rmnet_get_port_rtnl(real_dev);
|
||||||
|
|
||||||
rmnet_unregister_bridge(dev, port);
|
rmnet_unregister_bridge(real_dev, port);
|
||||||
|
|
||||||
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
|
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
|
||||||
|
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
|
||||||
unregister_netdevice_queue(ep->egress_dev, &list);
|
unregister_netdevice_queue(ep->egress_dev, &list);
|
||||||
rmnet_vnd_dellink(ep->mux_id, port, ep);
|
rmnet_vnd_dellink(ep->mux_id, port, ep);
|
||||||
|
|
||||||
hlist_del_init_rcu(&ep->hlnode);
|
hlist_del_init_rcu(&ep->hlnode);
|
||||||
kfree(ep);
|
kfree(ep);
|
||||||
}
|
}
|
||||||
@ -248,15 +245,15 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
|
|||||||
static int rmnet_config_notify_cb(struct notifier_block *nb,
|
static int rmnet_config_notify_cb(struct notifier_block *nb,
|
||||||
unsigned long event, void *data)
|
unsigned long event, void *data)
|
||||||
{
|
{
|
||||||
struct net_device *dev = netdev_notifier_info_to_dev(data);
|
struct net_device *real_dev = netdev_notifier_info_to_dev(data);
|
||||||
|
|
||||||
if (!dev)
|
if (!rmnet_is_real_dev_registered(real_dev))
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_UNREGISTER:
|
case NETDEV_UNREGISTER:
|
||||||
netdev_dbg(dev, "Kernel unregister\n");
|
netdev_dbg(real_dev, "Kernel unregister\n");
|
||||||
rmnet_force_unassociate_device(dev);
|
rmnet_force_unassociate_device(real_dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -477,8 +474,8 @@ static int __init rmnet_init(void)
|
|||||||
|
|
||||||
static void __exit rmnet_exit(void)
|
static void __exit rmnet_exit(void)
|
||||||
{
|
{
|
||||||
unregister_netdevice_notifier(&rmnet_dev_notifier);
|
|
||||||
rtnl_link_unregister(&rmnet_link_ops);
|
rtnl_link_unregister(&rmnet_link_ops);
|
||||||
|
unregister_netdevice_notifier(&rmnet_dev_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(rmnet_init)
|
module_init(rmnet_init)
|
||||||
|
Loading…
Reference in New Issue
Block a user