diff options
author | Arnd Bergmann <arnd@arndb.de> | 2021-07-22 16:29:02 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-07-23 15:20:25 +0200 |
commit | 876f0bf9d0d5189dca9341c8e8e8686b09db8398 (patch) | |
tree | 399c3cf96ae9b0dd4506cb1f3ca03a5458ce8a9a /net/core/dev_ioctl.c | |
parent | net: socket: remove register_gifconf (diff) | |
download | linux-876f0bf9d0d5189dca9341c8e8e8686b09db8398.tar.xz linux-876f0bf9d0d5189dca9341c8e8e8686b09db8398.zip |
net: socket: simplify dev_ifconf handling
The dev_ifconf() calling conventions make compat handling
more complicated than necessary, simplify this by moving
the in_compat_syscall() check into the function.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev_ioctl.c')
-rw-r--r-- | net/core/dev_ioctl.c | 55 |
1 files changed, 29 insertions, 26 deletions
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index c22c3dc15ce9..950e2fe5d56a 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -31,48 +31,51 @@ static int dev_ifname(struct net *net, struct ifreq *ifr) * size eventually, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */ - -int dev_ifconf(struct net *net, struct ifconf *ifc, int size) +int dev_ifconf(struct net *net, struct ifconf __user *uifc) { struct net_device *dev; - char __user *pos; - int len; - int total; - int i; + void __user *pos; + size_t size; + int len, total = 0, done; - /* - * Fetch the caller's info block. - */ + /* both the ifconf and the ifreq structures are slightly different */ + if (in_compat_syscall()) { + struct compat_ifconf ifc32; + + if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf))) + return -EFAULT; - pos = ifc->ifc_buf; - len = ifc->ifc_len; + pos = compat_ptr(ifc32.ifcbuf); + len = ifc32.ifc_len; + size = sizeof(struct compat_ifreq); + } else { + struct ifconf ifc; - /* - * Loop over the interfaces, and write an info block for each. - */ + if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) + return -EFAULT; - total = 0; + pos = ifc.ifc_buf; + len = ifc.ifc_len; + size = sizeof(struct ifreq); + } + + /* Loop over the interfaces, and write an info block for each. */ + rtnl_lock(); for_each_netdev(net, dev) { - int done; if (!pos) done = inet_gifconf(dev, NULL, 0, size); else done = inet_gifconf(dev, pos + total, len - total, size); - if (done < 0) + if (done < 0) { + rtnl_unlock(); return -EFAULT; + } total += done; } + rtnl_unlock(); - /* - * All done. Write the updated control block back to the caller. - */ - ifc->ifc_len = total; - - /* - * Both BSD and Solaris return 0 here, so we do too. - */ - return 0; + return put_user(total, &uifc->ifc_len); } static int dev_getifmap(struct net_device *dev, struct ifreq *ifr) |