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>
This commit is contained in:
Arnd Bergmann
2021-07-22 16:29:02 +02:00
committed by David S. Miller
parent b0e99d0377
commit 876f0bf9d0
3 changed files with 44 additions and 72 deletions

View File

@@ -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;
pos = ifc->ifc_buf;
len = ifc->ifc_len;
if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf)))
return -EFAULT;
/*
* Loop over the interfaces, and write an info block for each.
*/
pos = compat_ptr(ifc32.ifcbuf);
len = ifc32.ifc_len;
size = sizeof(struct compat_ifreq);
} else {
struct ifconf ifc;
total = 0;
if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
return -EFAULT;
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)