Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH net-next 0/3] net: bridge: fix recent ioctl changes
@ 2021-08-05 8:29 Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 1/3] net: bridge: fix ioctl locking Nikolay Aleksandrov
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Nikolay Aleksandrov @ 2021-08-05 8:29 UTC (permalink / raw)
To: netdev; +Cc: roopa, arnd, bridge, Nikolay Aleksandrov
From: Nikolay Aleksandrov <nikolay@nvidia.com>
Hi,
These are three fixes for the recent bridge removal of ndo_do_ioctl
done by commit ad2f99aedf8f ("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).
Thanks,
Nik
Nikolay Aleksandrov (3):
net: bridge: fix ioctl locking
net: bridge: fix ioctl old_deviceless bridge argument
net: core: don't call SIOCBRADD/DELIF for non-bridge devices
net/bridge/br_if.c | 4 +---
net/bridge/br_ioctl.c | 39 +++++++++++++++++++++++++--------------
net/core/dev_ioctl.c | 9 ++++++++-
3 files changed, 34 insertions(+), 18 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 1/3] net: bridge: fix ioctl locking
2021-08-05 8:29 [PATCH net-next 0/3] net: bridge: fix recent ioctl changes Nikolay Aleksandrov
@ 2021-08-05 8:29 ` Nikolay Aleksandrov
2021-08-05 9:29 ` Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 2/3] net: bridge: fix ioctl old_deviceless bridge argument Nikolay Aleksandrov
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Nikolay Aleksandrov @ 2021-08-05 8:29 UTC (permalink / raw)
To: netdev
Cc: roopa, arnd, bridge, Nikolay Aleksandrov, syzbot+34fe5894623c4ab1b379
From: Nikolay Aleksandrov <nikolay@nvidia.com>
Before commit ad2f99aedf8f ("net: bridge: move bridge ioctls out of
.ndo_do_ioctl") the bridge ioctl calls were divided in two parts:
one was deviceless called by sock_ioctl and didn't expect rtnl to be held,
the other was with a device called by dev_ifsioc() and expected rtnl to be
held. After the commit above they were united in a single ioctl stub, but
it didn't take care of the locking expectations.
For sock_ioctl now we acquire (1) br_ioctl_mutex, (2) rtnl
and for dev_ifsioc we acquire (1) rtnl, (2) br_ioctl_mutex
The fix is to get a refcnt on the netdev for dev_ifsioc calls and drop rtnl
then to reacquire it in the bridge ioctl stub after br_ioctl_mutex has
been acquired. That will avoid playing locking games and make the rules
straight-forward: we always take br_ioctl_mutex first, and then rtnl.
Reported-by: syzbot+34fe5894623c4ab1b379@syzkaller.appspotmail.com
Fixes: ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
net/bridge/br_if.c | 4 +---
net/bridge/br_ioctl.c | 37 ++++++++++++++++++++++++-------------
net/core/dev_ioctl.c | 7 ++++++-
3 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 86f6d7e93ea8..67c60240b713 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -456,7 +456,7 @@ int br_add_bridge(struct net *net, const char *name)
dev_net_set(dev, net);
dev->rtnl_link_ops = &br_link_ops;
- res = register_netdev(dev);
+ res = register_netdevice(dev);
if (res)
free_netdev(dev);
return res;
@@ -467,7 +467,6 @@ int br_del_bridge(struct net *net, const char *name)
struct net_device *dev;
int ret = 0;
- rtnl_lock();
dev = __dev_get_by_name(net, name);
if (dev == NULL)
ret = -ENXIO; /* Could not find device */
@@ -485,7 +484,6 @@ int br_del_bridge(struct net *net, const char *name)
else
br_dev_delete(dev, NULL);
- rtnl_unlock();
return ret;
}
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 46a24c20e405..2f848de3e755 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -369,33 +369,44 @@ static int old_deviceless(struct net *net, void __user *uarg)
int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd,
struct ifreq *ifr, void __user *uarg)
{
+ int ret = -EOPNOTSUPP;
+
+ rtnl_lock();
+
switch (cmd) {
case SIOCGIFBR:
case SIOCSIFBR:
- return old_deviceless(net, uarg);
-
+ ret = old_deviceless(net, uarg);
+ break;
case SIOCBRADDBR:
case SIOCBRDELBR:
{
char buf[IFNAMSIZ];
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- return -EPERM;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
- if (copy_from_user(buf, uarg, IFNAMSIZ))
- return -EFAULT;
+ if (copy_from_user(buf, uarg, IFNAMSIZ)) {
+ ret = -EFAULT;
+ break;
+ }
buf[IFNAMSIZ-1] = 0;
if (cmd == SIOCBRADDBR)
- return br_add_bridge(net, buf);
-
- return br_del_bridge(net, buf);
+ ret = br_add_bridge(net, buf);
+ else
+ ret = br_del_bridge(net, buf);
}
-
+ break;
case SIOCBRADDIF:
case SIOCBRDELIF:
- return add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF);
-
+ ret = add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF);
+ break;
}
- return -EOPNOTSUPP;
+
+ rtnl_unlock();
+
+ return ret;
}
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index 4035bce06bf8..ff16326f5903 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -379,7 +379,12 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
case SIOCBRDELIF:
if (!netif_device_present(dev))
return -ENODEV;
- return br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
+ dev_hold(dev);
+ rtnl_unlock();
+ err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
+ dev_put(dev);
+ rtnl_lock();
+ return err;
case SIOCSHWTSTAMP:
err = net_hwtstamp_validate(ifr);
--
2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 2/3] net: bridge: fix ioctl old_deviceless bridge argument
2021-08-05 8:29 [PATCH net-next 0/3] net: bridge: fix recent ioctl changes Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 1/3] net: bridge: fix ioctl locking Nikolay Aleksandrov
@ 2021-08-05 8:29 ` Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 3/3] net: core: don't call SIOCBRADD/DELIF for non-bridge devices Nikolay Aleksandrov
2021-08-05 10:40 ` [PATCH net-next 0/3] net: bridge: fix recent ioctl changes patchwork-bot+netdevbpf
3 siblings, 0 replies; 6+ messages in thread
From: Nikolay Aleksandrov @ 2021-08-05 8:29 UTC (permalink / raw)
To: netdev; +Cc: roopa, arnd, bridge, Nikolay Aleksandrov
From: Nikolay Aleksandrov <nikolay@nvidia.com>
Commit ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
changed the source of the argument copy in bridge's old_deviceless() from
args[1] (user ptr to device name) to uarg (ptr to ioctl arguments) causing
wrong device name to be used.
Example (broken, bridge exists but is up):
$ brctl delbr bridge
bridge bridge doesn't exist; can't delete it
Example (working):
$ brctl delbr bridge
bridge bridge is still up; can't delete it
Fixes: ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
net/bridge/br_ioctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 2f848de3e755..793b0db9d9a3 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -351,7 +351,7 @@ static int old_deviceless(struct net *net, void __user *uarg)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
- if (copy_from_user(buf, uarg, IFNAMSIZ))
+ if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ))
return -EFAULT;
buf[IFNAMSIZ-1] = 0;
--
2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 3/3] net: core: don't call SIOCBRADD/DELIF for non-bridge devices
2021-08-05 8:29 [PATCH net-next 0/3] net: bridge: fix recent ioctl changes Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 1/3] net: bridge: fix ioctl locking Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 2/3] net: bridge: fix ioctl old_deviceless bridge argument Nikolay Aleksandrov
@ 2021-08-05 8:29 ` Nikolay Aleksandrov
2021-08-05 10:40 ` [PATCH net-next 0/3] net: bridge: fix recent ioctl changes patchwork-bot+netdevbpf
3 siblings, 0 replies; 6+ messages in thread
From: Nikolay Aleksandrov @ 2021-08-05 8:29 UTC (permalink / raw)
To: netdev
Cc: roopa, arnd, bridge, Nikolay Aleksandrov, syzbot+79f4a8692e267bdb7227
From: Nikolay Aleksandrov <nikolay@nvidia.com>
Commit ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
changed SIOCBRADD/DELIF to use bridge's ioctl hook (br_ioctl_hook)
without checking if the target netdevice is actually a bridge which can
cause crashes and generally interpreting other devices' private pointers
as net_bridge pointers.
Crash example (lo - loopback):
$ brctl addif lo ens16
BUG: kernel NULL pointer dereference, address: 000000000000059898
#PF: supervisor read access in kernel modede
#PF: error_code(0x0000) - not-present pagege
PGD 0 P4D 0 ^Ac
Oops: 0000 [#1] SMP NOPTI
CPU: 2 PID: 1376 Comm: brctl Kdump: loaded Tainted: G W 5.14.0-rc3+ #405
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-4.fc34 04/01/2014
RIP: 0010:add_del_if+0x1f/0x7c [bridge]
Code: 80 bf 1b a0 41 5c e9 c0 3c 03 e1 0f 1f 44 00 00 41 55 41 54 41 89 f4 be 0c 00 00 00 55 48 89 fd 53 48 8b 87 88 00 00 00 89 d3 <4c> 8b a8 98 05 00 00 49 8b bd d0 00 00 00 e8 17 d7 f3 e0 84 c0 74
RSP: 0018:ffff888109d97cb0 EFLAGS: 00010202^Ac
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 000000000000000c RDI: ffff888101239bc0
RBP: ffff888101239bc0 R08: 0000000000000001 R09: 0000000000000000
R10: ffff888109d97cd8 R11: 00000000000000a3 R12: 0000000000000012
R13: 0000000000000000 R14: ffff888101239bc0 R15: ffff888109d97e10
FS: 00007fc1e365b540(0000) GS:ffff88822be80000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000598 CR3: 0000000106506000 CR4: 00000000000006e0
Call Trace:
br_ioctl_stub+0x7c/0x441 [bridge]
br_ioctl_call+0x6d/0x8a
dev_ifsioc+0x325/0x4e8
dev_ioctl+0x46b/0x4e1
sock_do_ioctl+0x7b/0xad
sock_ioctl+0x2de/0x2f2
vfs_ioctl+0x1e/0x2b
__do_sys_ioctl+0x63/0x86
do_syscall_64+0xcb/0xf2
entry_SYSCALL_64_after_hwframe+0x44/0xae
RIP: 0033:0x7fc1e3589427
Code: 00 00 90 48 8b 05 69 aa 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 39 aa 0c 00 f7 d8 64 89 01 48
RSP: 002b:00007ffc8d501d38 EFLAGS: 00000202 ORIG_RAX: 000000000000001010
RAX: ffffffffffffffda RBX: 0000000000000012 RCX: 00007fc1e3589427
RDX: 00007ffc8d501d60 RSI: 00000000000089a3 RDI: 0000000000000003
RBP: 00007ffc8d501d60 R08: 0000000000000000 R09: fefefeff77686d74
R10: fffffffffffff8f9 R11: 0000000000000202 R12: 00007ffc8d502e06
R13: 00007ffc8d502e06 R14: 0000000000000000 R15: 0000000000000000
Modules linked in: bridge stp llc bonding ipv6 virtio_net [last unloaded: llc]^Ac
CR2: 0000000000000598
Reported-by: syzbot+79f4a8692e267bdb7227@syzkaller.appspotmail.com
Fixes: ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
net/core/dev_ioctl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index ff16326f5903..0e87237fd871 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -379,6 +379,8 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
case SIOCBRDELIF:
if (!netif_device_present(dev))
return -ENODEV;
+ if (!netif_is_bridge_master(dev))
+ return -EOPNOTSUPP;
dev_hold(dev);
rtnl_unlock();
err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
--
2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 1/3] net: bridge: fix ioctl locking
2021-08-05 8:29 ` [PATCH net-next 1/3] net: bridge: fix ioctl locking Nikolay Aleksandrov
@ 2021-08-05 9:29 ` Nikolay Aleksandrov
0 siblings, 0 replies; 6+ messages in thread
From: Nikolay Aleksandrov @ 2021-08-05 9:29 UTC (permalink / raw)
To: Nikolay Aleksandrov, netdev
Cc: roopa, arnd, bridge, syzbot+34fe5894623c4ab1b379, Hillf Danton
On 05/08/2021 11:29, Nikolay Aleksandrov wrote:
> From: Nikolay Aleksandrov <nikolay@nvidia.com>
>
> Before commit ad2f99aedf8f ("net: bridge: move bridge ioctls out of
> .ndo_do_ioctl") the bridge ioctl calls were divided in two parts:
> one was deviceless called by sock_ioctl and didn't expect rtnl to be held,
> the other was with a device called by dev_ifsioc() and expected rtnl to be
> held. After the commit above they were united in a single ioctl stub, but
> it didn't take care of the locking expectations.
> For sock_ioctl now we acquire (1) br_ioctl_mutex, (2) rtnl
> and for dev_ifsioc we acquire (1) rtnl, (2) br_ioctl_mutex
>
> The fix is to get a refcnt on the netdev for dev_ifsioc calls and drop rtnl
> then to reacquire it in the bridge ioctl stub after br_ioctl_mutex has
> been acquired. That will avoid playing locking games and make the rules
> straight-forward: we always take br_ioctl_mutex first, and then rtnl.
>
> Reported-by: syzbot+34fe5894623c4ab1b379@syzkaller.appspotmail.com
> Fixes: ad2f99aedf8f ("net: bridge: move bridge ioctls out of .ndo_do_ioctl")
> Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
> ---
> net/bridge/br_if.c | 4 +---
> net/bridge/br_ioctl.c | 37 ++++++++++++++++++++++++-------------
> net/core/dev_ioctl.c | 7 ++++++-
> 3 files changed, 31 insertions(+), 17 deletions(-)
>
[snip]
I fixed the bridge side of things, but the unlock/lock suggestion was made first by Hillf.
I forgot to add:
Suggested-by: Hillf Danton <hdanton@sina.com>
+CC Hillf
Hillf, since the rtnl unlock/lock suggestion was yours feel free to add
your signed-off-by
Thanks,
Nik
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 0/3] net: bridge: fix recent ioctl changes
2021-08-05 8:29 [PATCH net-next 0/3] net: bridge: fix recent ioctl changes Nikolay Aleksandrov
` (2 preceding siblings ...)
2021-08-05 8:29 ` [PATCH net-next 3/3] net: core: don't call SIOCBRADD/DELIF for non-bridge devices Nikolay Aleksandrov
@ 2021-08-05 10:40 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-08-05 10:40 UTC (permalink / raw)
To: Nikolay Aleksandrov; +Cc: netdev, roopa, arnd, bridge, nikolay
Hello:
This series was applied to netdev/net-next.git (refs/heads/master):
On Thu, 5 Aug 2021 11:29:00 +0300 you wrote:
> From: Nikolay Aleksandrov <nikolay@nvidia.com>
>
> Hi,
> These are three fixes for the recent bridge removal of ndo_do_ioctl
> done by commit ad2f99aedf8f ("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.
>
> [...]
Here is the summary with links:
- [net-next,1/3] net: bridge: fix ioctl locking
https://git.kernel.org/netdev/net-next/c/893b19587534
- [net-next,2/3] net: bridge: fix ioctl old_deviceless bridge argument
https://git.kernel.org/netdev/net-next/c/cbd7ad29a507
- [net-next,3/3] net: core: don't call SIOCBRADD/DELIF for non-bridge devices
https://git.kernel.org/netdev/net-next/c/9384eacd80f3
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2021-08-05 10:40 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-05 8:29 [PATCH net-next 0/3] net: bridge: fix recent ioctl changes Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 1/3] net: bridge: fix ioctl locking Nikolay Aleksandrov
2021-08-05 9:29 ` Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 2/3] net: bridge: fix ioctl old_deviceless bridge argument Nikolay Aleksandrov
2021-08-05 8:29 ` [PATCH net-next 3/3] net: core: don't call SIOCBRADD/DELIF for non-bridge devices Nikolay Aleksandrov
2021-08-05 10:40 ` [PATCH net-next 0/3] net: bridge: fix recent ioctl changes patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).