Skip to content

Commit 876f0bf

Browse files
arndbdavem330
authored andcommitted
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>
1 parent b0e99d0 commit 876f0bf

File tree

3 files changed

+44
-72
lines changed

3 files changed

+44
-72
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4008,7 +4008,7 @@ void netdev_rx_handler_unregister(struct net_device *dev);
40084008
bool dev_valid_name(const char *name);
40094009
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
40104010
bool *need_copyout);
4011-
int dev_ifconf(struct net *net, struct ifconf *, int);
4011+
int dev_ifconf(struct net *net, struct ifconf __user *ifc);
40124012
int dev_ethtool(struct net *net, struct ifreq *);
40134013
unsigned int dev_get_flags(const struct net_device *);
40144014
int __dev_change_flags(struct net_device *dev, unsigned int flags,

net/core/dev_ioctl.c

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,48 +31,51 @@ static int dev_ifname(struct net *net, struct ifreq *ifr)
3131
* size eventually, and there is nothing I can do about it.
3232
* Thus we will need a 'compatibility mode'.
3333
*/
34-
35-
int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
34+
int dev_ifconf(struct net *net, struct ifconf __user *uifc)
3635
{
3736
struct net_device *dev;
38-
char __user *pos;
39-
int len;
40-
int total;
41-
int i;
37+
void __user *pos;
38+
size_t size;
39+
int len, total = 0, done;
4240

43-
/*
44-
* Fetch the caller's info block.
45-
*/
41+
/* both the ifconf and the ifreq structures are slightly different */
42+
if (in_compat_syscall()) {
43+
struct compat_ifconf ifc32;
44+
45+
if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf)))
46+
return -EFAULT;
4647

47-
pos = ifc->ifc_buf;
48-
len = ifc->ifc_len;
48+
pos = compat_ptr(ifc32.ifcbuf);
49+
len = ifc32.ifc_len;
50+
size = sizeof(struct compat_ifreq);
51+
} else {
52+
struct ifconf ifc;
4953

50-
/*
51-
* Loop over the interfaces, and write an info block for each.
52-
*/
54+
if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
55+
return -EFAULT;
5356

54-
total = 0;
57+
pos = ifc.ifc_buf;
58+
len = ifc.ifc_len;
59+
size = sizeof(struct ifreq);
60+
}
61+
62+
/* Loop over the interfaces, and write an info block for each. */
63+
rtnl_lock();
5564
for_each_netdev(net, dev) {
56-
int done;
5765
if (!pos)
5866
done = inet_gifconf(dev, NULL, 0, size);
5967
else
6068
done = inet_gifconf(dev, pos + total,
6169
len - total, size);
62-
if (done < 0)
70+
if (done < 0) {
71+
rtnl_unlock();
6372
return -EFAULT;
73+
}
6474
total += done;
6575
}
76+
rtnl_unlock();
6677

67-
/*
68-
* All done. Write the updated control block back to the caller.
69-
*/
70-
ifc->ifc_len = total;
71-
72-
/*
73-
* Both BSD and Solaris return 0 here, so we do too.
74-
*/
75-
return 0;
78+
return put_user(total, &uifc->ifc_len);
7679
}
7780

7881
static int dev_getifmap(struct net_device *dev, struct ifreq *ifr)

net/socket.c

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,8 @@ EXPORT_SYMBOL(vlan_ioctl_set);
10881088
static long sock_do_ioctl(struct net *net, struct socket *sock,
10891089
unsigned int cmd, unsigned long arg)
10901090
{
1091+
struct ifreq ifr;
1092+
bool need_copyout;
10911093
int err;
10921094
void __user *argp = (void __user *)arg;
10931095

@@ -1100,25 +1102,13 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
11001102
if (err != -ENOIOCTLCMD)
11011103
return err;
11021104

1103-
if (cmd == SIOCGIFCONF) {
1104-
struct ifconf ifc;
1105-
if (copy_from_user(&ifc, argp, sizeof(struct ifconf)))
1106-
return -EFAULT;
1107-
rtnl_lock();
1108-
err = dev_ifconf(net, &ifc, sizeof(struct ifreq));
1109-
rtnl_unlock();
1110-
if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf)))
1111-
err = -EFAULT;
1112-
} else {
1113-
struct ifreq ifr;
1114-
bool need_copyout;
1115-
if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
1105+
if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
1106+
return -EFAULT;
1107+
err = dev_ioctl(net, cmd, &ifr, &need_copyout);
1108+
if (!err && need_copyout)
1109+
if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
11161110
return -EFAULT;
1117-
err = dev_ioctl(net, cmd, &ifr, &need_copyout);
1118-
if (!err && need_copyout)
1119-
if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
1120-
return -EFAULT;
1121-
}
1111+
11221112
return err;
11231113
}
11241114

@@ -1217,6 +1207,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
12171207
cmd == SIOCGSTAMP_NEW,
12181208
false);
12191209
break;
1210+
1211+
case SIOCGIFCONF:
1212+
err = dev_ifconf(net, argp);
1213+
break;
1214+
12201215
default:
12211216
err = sock_do_ioctl(net, sock, cmd, arg);
12221217
break;
@@ -3127,31 +3122,6 @@ void socket_seq_show(struct seq_file *seq)
31273122
#endif /* CONFIG_PROC_FS */
31283123

31293124
#ifdef CONFIG_COMPAT
3130-
static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
3131-
{
3132-
struct compat_ifconf ifc32;
3133-
struct ifconf ifc;
3134-
int err;
3135-
3136-
if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
3137-
return -EFAULT;
3138-
3139-
ifc.ifc_len = ifc32.ifc_len;
3140-
ifc.ifc_req = compat_ptr(ifc32.ifcbuf);
3141-
3142-
rtnl_lock();
3143-
err = dev_ifconf(net, &ifc, sizeof(struct compat_ifreq));
3144-
rtnl_unlock();
3145-
if (err)
3146-
return err;
3147-
3148-
ifc32.ifc_len = ifc.ifc_len;
3149-
if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf)))
3150-
return -EFAULT;
3151-
3152-
return 0;
3153-
}
3154-
31553125
static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
31563126
{
31573127
compat_uptr_t uptr32;
@@ -3270,8 +3240,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
32703240
case SIOCSIFBR:
32713241
case SIOCGIFBR:
32723242
return old_bridge_ioctl(argp);
3273-
case SIOCGIFCONF:
3274-
return compat_dev_ifconf(net, argp);
32753243
case SIOCWANDEV:
32763244
return compat_siocwandev(net, argp);
32773245
case SIOCGSTAMP_OLD:
@@ -3299,6 +3267,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
32993267
case SIOCGSKNS:
33003268
case SIOCGSTAMP_NEW:
33013269
case SIOCGSTAMPNS_NEW:
3270+
case SIOCGIFCONF:
33023271
return sock_ioctl(file, cmd, arg);
33033272

33043273
case SIOCGIFFLAGS:

0 commit comments

Comments
 (0)