Skip to content

Commit 8cf81bf

Browse files
TaeheeYoogregkh
authored andcommitted
net: rmnet: fix bridge mode bugs
[ Upstream commit d939b6d ] In order to attach a bridge interface to the rmnet interface, "master" operation is used. (e.g. ip link set dummy1 master rmnet0) But, in the rmnet_add_bridge(), which is a callback of ->ndo_add_slave() doesn't register lower interface. So, ->ndo_del_slave() doesn't work. There are other problems too. 1. It couldn't detect circular upper/lower interface relationship. 2. It couldn't prevent stack overflow because of too deep depth of upper/lower interface 3. It doesn't check the number of lower interfaces. 4. Panics because of several reasons. The root problem of these issues is actually the same. So, in this patch, these all problems will be fixed. Test commands: modprobe rmnet ip link add dummy0 type dummy ip link add rmnet0 link dummy0 type rmnet mux_id 1 ip link add dummy1 master rmnet0 type dummy ip link add dummy2 master rmnet0 type dummy ip link del rmnet0 ip link del dummy2 ip link del dummy1 Splat looks like: [ 41.867595][ T1164] general protection fault, probably for non-canonical address 0xdffffc0000000101I [ 41.869993][ T1164] KASAN: null-ptr-deref in range [0x0000000000000808-0x000000000000080f] [ 41.872950][ T1164] CPU: 0 PID: 1164 Comm: ip Not tainted 5.6.0-rc1+ #447 [ 41.873915][ T1164] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 41.875161][ T1164] RIP: 0010:rmnet_unregister_bridge.isra.6+0x71/0xf0 [rmnet] [ 41.876178][ T1164] Code: 48 89 ef 48 89 c6 5b 5d e9 fc fe ff ff e8 f7 f3 ff ff 48 8d b8 08 08 00 00 48 ba 00 7 [ 41.878925][ T1164] RSP: 0018:ffff8880c4d0f188 EFLAGS: 00010202 [ 41.879774][ T1164] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000101 [ 41.887689][ T1164] RDX: dffffc0000000000 RSI: ffffffffb8cf64f0 RDI: 0000000000000808 [ 41.888727][ T1164] RBP: ffff8880c40e4000 R08: ffffed101b3c0e3c R09: 0000000000000001 [ 41.889749][ T1164] R10: 0000000000000001 R11: ffffed101b3c0e3b R12: 1ffff110189a1e3c [ 41.890783][ T1164] R13: ffff8880c4d0f200 R14: ffffffffb8d56160 R15: ffff8880ccc2c000 [ 41.891794][ T1164] FS: 00007f4300edc0c0(0000) GS:ffff8880d9c00000(0000) knlGS:0000000000000000 [ 41.892953][ T1164] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 41.893800][ T1164] CR2: 00007f43003bc8c0 CR3: 00000000ca53e001 CR4: 00000000000606f0 [ 41.894824][ T1164] Call Trace: [ 41.895274][ T1164] ? rcu_is_watching+0x2c/0x80 [ 41.895895][ T1164] rmnet_config_notify_cb+0x1f7/0x590 [rmnet] [ 41.896687][ T1164] ? rmnet_unregister_bridge.isra.6+0xf0/0xf0 [rmnet] [ 41.897611][ T1164] ? rmnet_unregister_bridge.isra.6+0xf0/0xf0 [rmnet] [ 41.898508][ T1164] ? __module_text_address+0x13/0x140 [ 41.899162][ T1164] notifier_call_chain+0x90/0x160 [ 41.899814][ T1164] rollback_registered_many+0x660/0xcf0 [ 41.900544][ T1164] ? netif_set_real_num_tx_queues+0x780/0x780 [ 41.901316][ T1164] ? __lock_acquire+0xdfe/0x3de0 [ 41.901958][ T1164] ? memset+0x1f/0x40 [ 41.902468][ T1164] ? __nla_validate_parse+0x98/0x1ab0 [ 41.903166][ T1164] unregister_netdevice_many.part.133+0x13/0x1b0 [ 41.903988][ T1164] rtnl_delete_link+0xbc/0x100 [ ... ] Fixes: 60d58f9 ("net: qualcomm: rmnet: Implement bridge mode") Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 7997816 commit 8cf81bf

File tree

4 files changed

+64
-77
lines changed

4 files changed

+64
-77
lines changed

drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,6 @@
2222
#include "rmnet_vnd.h"
2323
#include "rmnet_private.h"
2424

25-
/* Locking scheme -
26-
* The shared resource which needs to be protected is realdev->rx_handler_data.
27-
* For the writer path, this is using rtnl_lock(). The writer paths are
28-
* rmnet_newlink(), rmnet_dellink() and rmnet_force_unassociate_device(). These
29-
* paths are already called with rtnl_lock() acquired in. There is also an
30-
* ASSERT_RTNL() to ensure that we are calling with rtnl acquired. For
31-
* dereference here, we will need to use rtnl_dereference(). Dev list writing
32-
* needs to happen with rtnl_lock() acquired for netdev_master_upper_dev_link().
33-
* For the reader path, the real_dev->rx_handler_data is called in the TX / RX
34-
* path. We only need rcu_read_lock() for these scenarios. In these cases,
35-
* the rcu_read_lock() is held in __dev_queue_xmit() and
36-
* netif_receive_skb_internal(), so readers need to use rcu_dereference_rtnl()
37-
* to get the relevant information. For dev list reading, we again acquire
38-
* rcu_read_lock() in rmnet_dellink() for netdev_master_upper_dev_get_rcu().
39-
* We also use unregister_netdevice_many() to free all rmnet devices in
40-
* rmnet_force_unassociate_device() so we dont lose the rtnl_lock() and free in
41-
* same context.
42-
*/
43-
4425
/* Local Definitions and Declarations */
4526

4627
static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
@@ -60,9 +41,10 @@ rmnet_get_port_rtnl(const struct net_device *real_dev)
6041
return rtnl_dereference(real_dev->rx_handler_data);
6142
}
6243

63-
static int rmnet_unregister_real_device(struct net_device *real_dev,
64-
struct rmnet_port *port)
44+
static int rmnet_unregister_real_device(struct net_device *real_dev)
6545
{
46+
struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
47+
6648
if (port->nr_rmnet_devs)
6749
return -EINVAL;
6850

@@ -102,28 +84,33 @@ static int rmnet_register_real_device(struct net_device *real_dev)
10284
return 0;
10385
}
10486

105-
static void rmnet_unregister_bridge(struct net_device *dev,
106-
struct rmnet_port *port)
87+
static void rmnet_unregister_bridge(struct rmnet_port *port)
10788
{
108-
struct rmnet_port *bridge_port;
109-
struct net_device *bridge_dev;
89+
struct net_device *bridge_dev, *real_dev, *rmnet_dev;
90+
struct rmnet_port *real_port;
11091

11192
if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
11293
return;
11394

114-
/* bridge slave handling */
95+
rmnet_dev = port->rmnet_dev;
11596
if (!port->nr_rmnet_devs) {
116-
bridge_dev = port->bridge_ep;
97+
/* bridge device */
98+
real_dev = port->bridge_ep;
99+
bridge_dev = port->dev;
117100

118-
bridge_port = rmnet_get_port_rtnl(bridge_dev);
119-
bridge_port->bridge_ep = NULL;
120-
bridge_port->rmnet_mode = RMNET_EPMODE_VND;
101+
real_port = rmnet_get_port_rtnl(real_dev);
102+
real_port->bridge_ep = NULL;
103+
real_port->rmnet_mode = RMNET_EPMODE_VND;
121104
} else {
105+
/* real device */
122106
bridge_dev = port->bridge_ep;
123107

124-
bridge_port = rmnet_get_port_rtnl(bridge_dev);
125-
rmnet_unregister_real_device(bridge_dev, bridge_port);
108+
port->bridge_ep = NULL;
109+
port->rmnet_mode = RMNET_EPMODE_VND;
126110
}
111+
112+
netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
113+
rmnet_unregister_real_device(bridge_dev);
127114
}
128115

129116
static int rmnet_newlink(struct net *src_net, struct net_device *dev,
@@ -170,6 +157,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
170157
goto err2;
171158

172159
port->rmnet_mode = mode;
160+
port->rmnet_dev = dev;
173161

174162
hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
175163

@@ -187,8 +175,9 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
187175

188176
err2:
189177
unregister_netdevice(dev);
178+
rmnet_vnd_dellink(mux_id, port, ep);
190179
err1:
191-
rmnet_unregister_real_device(real_dev, port);
180+
rmnet_unregister_real_device(real_dev);
192181
err0:
193182
kfree(ep);
194183
return err;
@@ -197,30 +186,32 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
197186
static void rmnet_dellink(struct net_device *dev, struct list_head *head)
198187
{
199188
struct rmnet_priv *priv = netdev_priv(dev);
200-
struct net_device *real_dev;
189+
struct net_device *real_dev, *bridge_dev;
190+
struct rmnet_port *real_port, *bridge_port;
201191
struct rmnet_endpoint *ep;
202-
struct rmnet_port *port;
203-
u8 mux_id;
192+
u8 mux_id = priv->mux_id;
204193

205194
real_dev = priv->real_dev;
206195

207-
if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
196+
if (!rmnet_is_real_dev_registered(real_dev))
208197
return;
209198

210-
port = rmnet_get_port_rtnl(real_dev);
211-
212-
mux_id = rmnet_vnd_get_mux(dev);
199+
real_port = rmnet_get_port_rtnl(real_dev);
200+
bridge_dev = real_port->bridge_ep;
201+
if (bridge_dev) {
202+
bridge_port = rmnet_get_port_rtnl(bridge_dev);
203+
rmnet_unregister_bridge(bridge_port);
204+
}
213205

214-
ep = rmnet_get_endpoint(port, mux_id);
206+
ep = rmnet_get_endpoint(real_port, mux_id);
215207
if (ep) {
216208
hlist_del_init_rcu(&ep->hlnode);
217-
rmnet_unregister_bridge(dev, port);
218-
rmnet_vnd_dellink(mux_id, port, ep);
209+
rmnet_vnd_dellink(mux_id, real_port, ep);
219210
kfree(ep);
220211
}
221-
netdev_upper_dev_unlink(real_dev, dev);
222-
rmnet_unregister_real_device(real_dev, port);
223212

213+
netdev_upper_dev_unlink(real_dev, dev);
214+
rmnet_unregister_real_device(real_dev);
224215
unregister_netdevice_queue(dev, head);
225216
}
226217

@@ -232,23 +223,23 @@ static void rmnet_force_unassociate_device(struct net_device *real_dev)
232223
unsigned long bkt_ep;
233224
LIST_HEAD(list);
234225

235-
ASSERT_RTNL();
236-
237226
port = rmnet_get_port_rtnl(real_dev);
238227

239-
rmnet_unregister_bridge(real_dev, port);
240-
241-
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
242-
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
243-
unregister_netdevice_queue(ep->egress_dev, &list);
244-
rmnet_vnd_dellink(ep->mux_id, port, ep);
245-
hlist_del_init_rcu(&ep->hlnode);
246-
kfree(ep);
228+
if (port->nr_rmnet_devs) {
229+
/* real device */
230+
rmnet_unregister_bridge(port);
231+
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
232+
unregister_netdevice_queue(ep->egress_dev, &list);
233+
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
234+
rmnet_vnd_dellink(ep->mux_id, port, ep);
235+
hlist_del_init_rcu(&ep->hlnode);
236+
kfree(ep);
237+
}
238+
rmnet_unregister_real_device(real_dev);
239+
unregister_netdevice_many(&list);
240+
} else {
241+
rmnet_unregister_bridge(port);
247242
}
248-
249-
unregister_netdevice_many(&list);
250-
251-
rmnet_unregister_real_device(real_dev, port);
252243
}
253244

254245
static int rmnet_config_notify_cb(struct notifier_block *nb,
@@ -427,16 +418,27 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
427418
if (port->nr_rmnet_devs > 1)
428419
return -EINVAL;
429420

421+
if (port->rmnet_mode != RMNET_EPMODE_VND)
422+
return -EINVAL;
423+
430424
if (rmnet_is_real_dev_registered(slave_dev))
431425
return -EBUSY;
432426

433427
err = rmnet_register_real_device(slave_dev);
434428
if (err)
435429
return -EBUSY;
436430

431+
err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
432+
extack);
433+
if (err) {
434+
rmnet_unregister_real_device(slave_dev);
435+
return err;
436+
}
437+
437438
slave_port = rmnet_get_port_rtnl(slave_dev);
438439
slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
439440
slave_port->bridge_ep = real_dev;
441+
slave_port->rmnet_dev = rmnet_dev;
440442

441443
port->rmnet_mode = RMNET_EPMODE_BRIDGE;
442444
port->bridge_ep = slave_dev;
@@ -448,16 +450,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
448450
int rmnet_del_bridge(struct net_device *rmnet_dev,
449451
struct net_device *slave_dev)
450452
{
451-
struct rmnet_priv *priv = netdev_priv(rmnet_dev);
452-
struct net_device *real_dev = priv->real_dev;
453-
struct rmnet_port *port, *slave_port;
454-
455-
port = rmnet_get_port_rtnl(real_dev);
456-
port->rmnet_mode = RMNET_EPMODE_VND;
457-
port->bridge_ep = NULL;
453+
struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
458454

459-
slave_port = rmnet_get_port_rtnl(slave_dev);
460-
rmnet_unregister_real_device(slave_dev, slave_port);
455+
rmnet_unregister_bridge(port);
461456

462457
netdev_dbg(slave_dev, "removed from rmnet as slave\n");
463458
return 0;

drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct rmnet_port {
3737
u8 rmnet_mode;
3838
struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
3939
struct net_device *bridge_ep;
40+
struct net_device *rmnet_dev;
4041
};
4142

4243
extern struct rtnl_link_ops rmnet_link_ops;

drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,14 +276,6 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
276276
return 0;
277277
}
278278

279-
u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
280-
{
281-
struct rmnet_priv *priv;
282-
283-
priv = netdev_priv(rmnet_dev);
284-
return priv->mux_id;
285-
}
286-
287279
int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
288280
{
289281
netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);

drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,5 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
2525
struct rmnet_endpoint *ep);
2626
void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
2727
void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
28-
u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
2928
void rmnet_vnd_setup(struct net_device *dev);
3029
#endif /* _RMNET_VND_H_ */

0 commit comments

Comments
 (0)