Commit 59e67606 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse (compat_ioctl): SIOCGIFCONF

	Switched to compat_alloc_user_space(), killed kmalloc and set_fs(),
annotated, somewhat cleaned up.
parent 031e2236
...@@ -490,75 +490,71 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -490,75 +490,71 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct ifconf32 ifc32; struct ifconf32 ifc32;
struct ifconf ifc; struct ifconf ifc;
struct ifreq32 *ifr32; struct ifconf __user *uifc;
struct ifreq *ifr; struct ifreq32 __user *ifr32;
mm_segment_t old_fs; struct ifreq __user *ifr;
unsigned int i, j; unsigned int i, j;
int err; int err;
if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32))) if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32)))
return -EFAULT; return -EFAULT;
if(ifc32.ifcbuf == 0) { if (ifc32.ifcbuf == 0) {
ifc32.ifc_len = 0; ifc32.ifc_len = 0;
ifc.ifc_len = 0; ifc.ifc_len = 0;
ifc.ifc_buf = NULL; ifc.ifc_req = NULL;
uifc = compat_alloc_user_space(sizeof(struct ifconf));
} else { } else {
ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
sizeof (struct ifreq); sizeof (struct ifreq);
/* should the size be limited? -arnd */ uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); ifc.ifc_len = len;
if (!ifc.ifc_buf) ifr = ifc.ifc_req = (void __user *)(uifc + 1);
return -ENOMEM; ifr32 = compat_ptr(ifc32.ifcbuf);
for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32)))
return -EFAULT;
ifr++;
ifr32++;
}
} }
if (copy_to_user(uifc, &ifc, sizeof(struct ifconf)))
return -EFAULT;
err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc);
if (err)
return err;
if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
return -EFAULT;
ifr = ifc.ifc_req; ifr = ifc.ifc_req;
ifr32 = compat_ptr(ifc32.ifcbuf); ifr32 = compat_ptr(ifc32.ifcbuf);
for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
if (copy_from_user(ifr, ifr32, sizeof (struct ifreq32))) { i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
kfree (ifc.ifc_buf); if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32)))
return -EFAULT; return -EFAULT;
} ifr32++;
ifr++; ifr++;
ifr32++;
} }
old_fs = get_fs(); set_fs (KERNEL_DS);
err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); if (ifc32.ifcbuf == 0) {
set_fs (old_fs); /* Translate from 64-bit structure multiple to
if (!err) { * a 32-bit one.
ifr = ifc.ifc_req; */
ifr32 = compat_ptr(ifc32.ifcbuf); i = ifc.ifc_len;
for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { ifc32.ifc_len = i;
int k = copy_to_user(ifr32, ifr, sizeof (struct ifreq32)); } else {
ifr32++; if (i <= ifc32.ifc_len)
ifr++; ifc32.ifc_len = i;
if (k) { else
err = -EFAULT; ifc32.ifc_len = i - sizeof (struct ifreq32);
break;
}
}
if (!err) {
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 ifreq32));
ifc32.ifc_len = i;
} else {
if (i <= ifc32.ifc_len)
ifc32.ifc_len = i;
else
ifc32.ifc_len = i - sizeof (struct ifreq32);
}
if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32)))
err = -EFAULT;
}
} }
if(ifc.ifc_buf != NULL) if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32)))
kfree (ifc.ifc_buf); return -EFAULT;
return err;
return 0;
} }
static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment