Skip to content

Commit d15040a

Browse files
committed
Merge branch 'bridge-ioctl-fixes'
Nikolay Aleksandrov says: ==================== net: bridge: fix recent ioctl changes These are three fixes for the recent bridge removal of ndo_do_ioctl done by commit ad2f99a ("net: bridge: move bridge ioctls out of .ndo_do_ioctl"). Patch 01 fixes a deadlock of the new bridge ioctl hook lock and rtnl by taking a netdev reference and always taking the bridge ioctl lock first then rtnl from within the bridge hook. Patch 02 fixes old_deviceless() bridge calls device name argument, and patch 03 checks in dev_ifsioc()'s SIOCBRADD/DELIF cases if the netdevice is actually a bridge before interpreting its private ptr as net_bridge. Patch 01 was tested by running old bridge-utils commands with lockdep enabled. Patch 02 was tested again by using bridge-utils and using the respective ioctl calls on a "up" bridge device. Patch 03 was tested by using the addif ioctl on a non-bridge device (e.g. loopback). ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4167a96 + 9384eac commit d15040a

File tree

3 files changed

+34
-18
lines changed

3 files changed

+34
-18
lines changed

net/bridge/br_if.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ int br_add_bridge(struct net *net, const char *name)
456456
dev_net_set(dev, net);
457457
dev->rtnl_link_ops = &br_link_ops;
458458

459-
res = register_netdev(dev);
459+
res = register_netdevice(dev);
460460
if (res)
461461
free_netdev(dev);
462462
return res;
@@ -467,7 +467,6 @@ int br_del_bridge(struct net *net, const char *name)
467467
struct net_device *dev;
468468
int ret = 0;
469469

470-
rtnl_lock();
471470
dev = __dev_get_by_name(net, name);
472471
if (dev == NULL)
473472
ret = -ENXIO; /* Could not find device */
@@ -485,7 +484,6 @@ int br_del_bridge(struct net *net, const char *name)
485484
else
486485
br_dev_delete(dev, NULL);
487486

488-
rtnl_unlock();
489487
return ret;
490488
}
491489

net/bridge/br_ioctl.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ static int old_deviceless(struct net *net, void __user *uarg)
351351
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
352352
return -EPERM;
353353

354-
if (copy_from_user(buf, uarg, IFNAMSIZ))
354+
if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ))
355355
return -EFAULT;
356356

357357
buf[IFNAMSIZ-1] = 0;
@@ -369,33 +369,44 @@ static int old_deviceless(struct net *net, void __user *uarg)
369369
int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd,
370370
struct ifreq *ifr, void __user *uarg)
371371
{
372+
int ret = -EOPNOTSUPP;
373+
374+
rtnl_lock();
375+
372376
switch (cmd) {
373377
case SIOCGIFBR:
374378
case SIOCSIFBR:
375-
return old_deviceless(net, uarg);
376-
379+
ret = old_deviceless(net, uarg);
380+
break;
377381
case SIOCBRADDBR:
378382
case SIOCBRDELBR:
379383
{
380384
char buf[IFNAMSIZ];
381385

382-
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
383-
return -EPERM;
386+
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
387+
ret = -EPERM;
388+
break;
389+
}
384390

385-
if (copy_from_user(buf, uarg, IFNAMSIZ))
386-
return -EFAULT;
391+
if (copy_from_user(buf, uarg, IFNAMSIZ)) {
392+
ret = -EFAULT;
393+
break;
394+
}
387395

388396
buf[IFNAMSIZ-1] = 0;
389397
if (cmd == SIOCBRADDBR)
390-
return br_add_bridge(net, buf);
391-
392-
return br_del_bridge(net, buf);
398+
ret = br_add_bridge(net, buf);
399+
else
400+
ret = br_del_bridge(net, buf);
393401
}
394-
402+
break;
395403
case SIOCBRADDIF:
396404
case SIOCBRDELIF:
397-
return add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF);
398-
405+
ret = add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF);
406+
break;
399407
}
400-
return -EOPNOTSUPP;
408+
409+
rtnl_unlock();
410+
411+
return ret;
401412
}

net/core/dev_ioctl.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,14 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
379379
case SIOCBRDELIF:
380380
if (!netif_device_present(dev))
381381
return -ENODEV;
382-
return br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
382+
if (!netif_is_bridge_master(dev))
383+
return -EOPNOTSUPP;
384+
dev_hold(dev);
385+
rtnl_unlock();
386+
err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
387+
dev_put(dev);
388+
rtnl_lock();
389+
return err;
383390

384391
case SIOCSHWTSTAMP:
385392
err = net_hwtstamp_validate(ifr);

0 commit comments

Comments
 (0)