Skip to content

Commit 434e804

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 0ea728c commit 434e804

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
@@ -13,25 +13,6 @@
1313
#include "rmnet_vnd.h"
1414
#include "rmnet_private.h"
1515

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

3718
static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
@@ -51,9 +32,10 @@ rmnet_get_port_rtnl(const struct net_device *real_dev)
5132
return rtnl_dereference(real_dev->rx_handler_data);
5233
}
5334

54-
static int rmnet_unregister_real_device(struct net_device *real_dev,
55-
struct rmnet_port *port)
35+
static int rmnet_unregister_real_device(struct net_device *real_dev)
5636
{
37+
struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
38+
5739
if (port->nr_rmnet_devs)
5840
return -EINVAL;
5941

@@ -93,28 +75,33 @@ static int rmnet_register_real_device(struct net_device *real_dev)
9375
return 0;
9476
}
9577

96-
static void rmnet_unregister_bridge(struct net_device *dev,
97-
struct rmnet_port *port)
78+
static void rmnet_unregister_bridge(struct rmnet_port *port)
9879
{
99-
struct rmnet_port *bridge_port;
100-
struct net_device *bridge_dev;
80+
struct net_device *bridge_dev, *real_dev, *rmnet_dev;
81+
struct rmnet_port *real_port;
10182

10283
if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
10384
return;
10485

105-
/* bridge slave handling */
86+
rmnet_dev = port->rmnet_dev;
10687
if (!port->nr_rmnet_devs) {
107-
bridge_dev = port->bridge_ep;
88+
/* bridge device */
89+
real_dev = port->bridge_ep;
90+
bridge_dev = port->dev;
10891

109-
bridge_port = rmnet_get_port_rtnl(bridge_dev);
110-
bridge_port->bridge_ep = NULL;
111-
bridge_port->rmnet_mode = RMNET_EPMODE_VND;
92+
real_port = rmnet_get_port_rtnl(real_dev);
93+
real_port->bridge_ep = NULL;
94+
real_port->rmnet_mode = RMNET_EPMODE_VND;
11295
} else {
96+
/* real device */
11397
bridge_dev = port->bridge_ep;
11498

115-
bridge_port = rmnet_get_port_rtnl(bridge_dev);
116-
rmnet_unregister_real_device(bridge_dev, bridge_port);
99+
port->bridge_ep = NULL;
100+
port->rmnet_mode = RMNET_EPMODE_VND;
117101
}
102+
103+
netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
104+
rmnet_unregister_real_device(bridge_dev);
118105
}
119106

120107
static int rmnet_newlink(struct net *src_net, struct net_device *dev,
@@ -161,6 +148,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
161148
goto err2;
162149

163150
port->rmnet_mode = mode;
151+
port->rmnet_dev = dev;
164152

165153
hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
166154

@@ -178,8 +166,9 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
178166

179167
err2:
180168
unregister_netdevice(dev);
169+
rmnet_vnd_dellink(mux_id, port, ep);
181170
err1:
182-
rmnet_unregister_real_device(real_dev, port);
171+
rmnet_unregister_real_device(real_dev);
183172
err0:
184173
kfree(ep);
185174
return err;
@@ -188,30 +177,32 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
188177
static void rmnet_dellink(struct net_device *dev, struct list_head *head)
189178
{
190179
struct rmnet_priv *priv = netdev_priv(dev);
191-
struct net_device *real_dev;
180+
struct net_device *real_dev, *bridge_dev;
181+
struct rmnet_port *real_port, *bridge_port;
192182
struct rmnet_endpoint *ep;
193-
struct rmnet_port *port;
194-
u8 mux_id;
183+
u8 mux_id = priv->mux_id;
195184

196185
real_dev = priv->real_dev;
197186

198-
if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
187+
if (!rmnet_is_real_dev_registered(real_dev))
199188
return;
200189

201-
port = rmnet_get_port_rtnl(real_dev);
202-
203-
mux_id = rmnet_vnd_get_mux(dev);
190+
real_port = rmnet_get_port_rtnl(real_dev);
191+
bridge_dev = real_port->bridge_ep;
192+
if (bridge_dev) {
193+
bridge_port = rmnet_get_port_rtnl(bridge_dev);
194+
rmnet_unregister_bridge(bridge_port);
195+
}
204196

205-
ep = rmnet_get_endpoint(port, mux_id);
197+
ep = rmnet_get_endpoint(real_port, mux_id);
206198
if (ep) {
207199
hlist_del_init_rcu(&ep->hlnode);
208-
rmnet_unregister_bridge(dev, port);
209-
rmnet_vnd_dellink(mux_id, port, ep);
200+
rmnet_vnd_dellink(mux_id, real_port, ep);
210201
kfree(ep);
211202
}
212-
netdev_upper_dev_unlink(real_dev, dev);
213-
rmnet_unregister_real_device(real_dev, port);
214203

204+
netdev_upper_dev_unlink(real_dev, dev);
205+
rmnet_unregister_real_device(real_dev);
215206
unregister_netdevice_queue(dev, head);
216207
}
217208

@@ -223,23 +214,23 @@ static void rmnet_force_unassociate_device(struct net_device *real_dev)
223214
unsigned long bkt_ep;
224215
LIST_HEAD(list);
225216

226-
ASSERT_RTNL();
227-
228217
port = rmnet_get_port_rtnl(real_dev);
229218

230-
rmnet_unregister_bridge(real_dev, port);
231-
232-
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
233-
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
234-
unregister_netdevice_queue(ep->egress_dev, &list);
235-
rmnet_vnd_dellink(ep->mux_id, port, ep);
236-
hlist_del_init_rcu(&ep->hlnode);
237-
kfree(ep);
219+
if (port->nr_rmnet_devs) {
220+
/* real device */
221+
rmnet_unregister_bridge(port);
222+
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
223+
unregister_netdevice_queue(ep->egress_dev, &list);
224+
netdev_upper_dev_unlink(real_dev, ep->egress_dev);
225+
rmnet_vnd_dellink(ep->mux_id, port, ep);
226+
hlist_del_init_rcu(&ep->hlnode);
227+
kfree(ep);
228+
}
229+
rmnet_unregister_real_device(real_dev);
230+
unregister_netdevice_many(&list);
231+
} else {
232+
rmnet_unregister_bridge(port);
238233
}
239-
240-
unregister_netdevice_many(&list);
241-
242-
rmnet_unregister_real_device(real_dev, port);
243234
}
244235

245236
static int rmnet_config_notify_cb(struct notifier_block *nb,
@@ -418,16 +409,27 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
418409
if (port->nr_rmnet_devs > 1)
419410
return -EINVAL;
420411

412+
if (port->rmnet_mode != RMNET_EPMODE_VND)
413+
return -EINVAL;
414+
421415
if (rmnet_is_real_dev_registered(slave_dev))
422416
return -EBUSY;
423417

424418
err = rmnet_register_real_device(slave_dev);
425419
if (err)
426420
return -EBUSY;
427421

422+
err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
423+
extack);
424+
if (err) {
425+
rmnet_unregister_real_device(slave_dev);
426+
return err;
427+
}
428+
428429
slave_port = rmnet_get_port_rtnl(slave_dev);
429430
slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
430431
slave_port->bridge_ep = real_dev;
432+
slave_port->rmnet_dev = rmnet_dev;
431433

432434
port->rmnet_mode = RMNET_EPMODE_BRIDGE;
433435
port->bridge_ep = slave_dev;
@@ -439,16 +441,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
439441
int rmnet_del_bridge(struct net_device *rmnet_dev,
440442
struct net_device *slave_dev)
441443
{
442-
struct rmnet_priv *priv = netdev_priv(rmnet_dev);
443-
struct net_device *real_dev = priv->real_dev;
444-
struct rmnet_port *port, *slave_port;
445-
446-
port = rmnet_get_port_rtnl(real_dev);
447-
port->rmnet_mode = RMNET_EPMODE_VND;
448-
port->bridge_ep = NULL;
444+
struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
449445

450-
slave_port = rmnet_get_port_rtnl(slave_dev);
451-
rmnet_unregister_real_device(slave_dev, slave_port);
446+
rmnet_unregister_bridge(port);
452447

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

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct rmnet_port {
2828
u8 rmnet_mode;
2929
struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
3030
struct net_device *bridge_ep;
31+
struct net_device *rmnet_dev;
3132
};
3233

3334
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
@@ -266,14 +266,6 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
266266
return 0;
267267
}
268268

269-
u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
270-
{
271-
struct rmnet_priv *priv;
272-
273-
priv = netdev_priv(rmnet_dev);
274-
return priv->mux_id;
275-
}
276-
277269
int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
278270
{
279271
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
@@ -16,6 +16,5 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
1616
struct rmnet_endpoint *ep);
1717
void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
1818
void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
19-
u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
2019
void rmnet_vnd_setup(struct net_device *dev);
2120
#endif /* _RMNET_VND_H_ */

0 commit comments

Comments
 (0)