|
@@ -961,10 +961,22 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
|
|
* If this ioctl is unknown try to hand it down
|
|
* If this ioctl is unknown try to hand it down
|
|
* to the NIC driver.
|
|
* to the NIC driver.
|
|
*/
|
|
*/
|
|
- if (err == -ENOIOCTLCMD)
|
|
|
|
- err = dev_ioctl(net, cmd, argp);
|
|
|
|
|
|
+ if (err != -ENOIOCTLCMD)
|
|
|
|
+ return err;
|
|
|
|
|
|
- return err;
|
|
|
|
|
|
+ if (cmd == SIOCGIFCONF) {
|
|
|
|
+ struct ifconf ifc;
|
|
|
|
+ if (copy_from_user(&ifc, argp, sizeof(struct ifconf)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ rtnl_lock();
|
|
|
|
+ err = dev_ifconf(net, &ifc, sizeof(struct ifreq));
|
|
|
|
+ rtnl_unlock();
|
|
|
|
+ if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf)))
|
|
|
|
+ err = -EFAULT;
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return dev_ioctl(net, cmd, argp);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2673,70 +2685,25 @@ static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
|
|
|
|
|
|
+static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
|
|
{
|
|
{
|
|
struct compat_ifconf ifc32;
|
|
struct compat_ifconf ifc32;
|
|
struct ifconf ifc;
|
|
struct ifconf ifc;
|
|
- struct ifconf __user *uifc;
|
|
|
|
- struct compat_ifreq __user *ifr32;
|
|
|
|
- struct ifreq __user *ifr;
|
|
|
|
- unsigned int i, j;
|
|
|
|
int err;
|
|
int err;
|
|
|
|
|
|
if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
|
|
if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
- memset(&ifc, 0, sizeof(ifc));
|
|
|
|
- if (ifc32.ifcbuf == 0) {
|
|
|
|
- ifc32.ifc_len = 0;
|
|
|
|
- ifc.ifc_len = 0;
|
|
|
|
- ifc.ifc_req = NULL;
|
|
|
|
- uifc = compat_alloc_user_space(sizeof(struct ifconf));
|
|
|
|
- } else {
|
|
|
|
- size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) *
|
|
|
|
- sizeof(struct ifreq);
|
|
|
|
- uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
|
|
|
|
- ifc.ifc_len = len;
|
|
|
|
- ifr = ifc.ifc_req = (void __user *)(uifc + 1);
|
|
|
|
- ifr32 = compat_ptr(ifc32.ifcbuf);
|
|
|
|
- for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) {
|
|
|
|
- if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
|
|
|
|
- return -EFAULT;
|
|
|
|
- ifr++;
|
|
|
|
- ifr32++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (copy_to_user(uifc, &ifc, sizeof(struct ifconf)))
|
|
|
|
- return -EFAULT;
|
|
|
|
|
|
+ ifc.ifc_len = ifc32.ifc_len;
|
|
|
|
+ ifc.ifc_req = compat_ptr(ifc32.ifcbuf);
|
|
|
|
|
|
- err = dev_ioctl(net, SIOCGIFCONF, uifc);
|
|
|
|
|
|
+ rtnl_lock();
|
|
|
|
+ err = dev_ifconf(net, &ifc, sizeof(struct compat_ifreq));
|
|
|
|
+ rtnl_unlock();
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
|
|
|
|
- if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
|
|
|
|
- return -EFAULT;
|
|
|
|
-
|
|
|
|
- ifr = ifc.ifc_req;
|
|
|
|
- ifr32 = compat_ptr(ifc32.ifcbuf);
|
|
|
|
- for (i = 0, j = 0;
|
|
|
|
- i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
|
|
|
|
- i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) {
|
|
|
|
- if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq)))
|
|
|
|
- return -EFAULT;
|
|
|
|
- ifr32++;
|
|
|
|
- ifr++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (ifc32.ifcbuf == 0) {
|
|
|
|
- /* Translate from 64-bit structure multiple to
|
|
|
|
- * a 32-bit one.
|
|
|
|
- */
|
|
|
|
- i = ifc.ifc_len;
|
|
|
|
- i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq));
|
|
|
|
- ifc32.ifc_len = i;
|
|
|
|
- } else {
|
|
|
|
- ifc32.ifc_len = i;
|
|
|
|
- }
|
|
|
|
|
|
+ ifc32.ifc_len = ifc.ifc_len;
|
|
if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf)))
|
|
if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
@@ -3133,7 +3100,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
|
|
case SIOCGIFNAME:
|
|
case SIOCGIFNAME:
|
|
return dev_ifname32(net, argp);
|
|
return dev_ifname32(net, argp);
|
|
case SIOCGIFCONF:
|
|
case SIOCGIFCONF:
|
|
- return dev_ifconf(net, argp);
|
|
|
|
|
|
+ return compat_dev_ifconf(net, argp);
|
|
case SIOCETHTOOL:
|
|
case SIOCETHTOOL:
|
|
return ethtool_ioctl(net, argp);
|
|
return ethtool_ioctl(net, argp);
|
|
case SIOCWANDEV:
|
|
case SIOCWANDEV:
|