diff options
author | Pete Zaitcev <zaitcev@redhat.com> | 2005-10-17 21:15:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 19:47:46 -0400 |
commit | c36fc889b5a4fd66cfd9ba80d9e038745d349567 (patch) | |
tree | c49f295dfdf53a4c6f495be8414497f2cdf4a4d3 /drivers | |
parent | 72adaa962741e8e910300b66bb123b1a9c31a8a8 (diff) |
[PATCH] usb: Patch for USBDEVFS_IOCTL from 32-bit programs
Dell supplied me with the following test:
#include<stdio.h>
#include<errno.h>
#include<sys/ioctl.h>
#include<fcntl.h>
#include<linux/usbdevice_fs.h>
main(int argc,char*argv[])
{
struct usbdevfs_hub_portinfo hubPortInfo = {0};
struct usbdevfs_ioctl command = {0};
command.ifno = 0;
command.ioctl_code = USBDEVFS_HUB_PORTINFO;
command.data = (void*)&hubPortInfo;
int fd, ret;
if(argc != 2) {
fprintf(stderr,"Usage: %s /proc/bus/usb/<BusNo>/<HubID>\n",argv[0]);
fprintf(stderr,"Example: %s /proc/bus/usb/001/001\n",argv[0]);
exit(1);
}
errno = 0;
fd = open(argv[1],O_RDWR);
if(fd < 0) {
perror("open failed:");
exit(errno);
}
errno = 0;
ret = ioctl(fd,USBDEVFS_IOCTL,&command);
printf("IOCTL return status:%d\n",ret);
if(ret<0) {
perror("IOCTL failed:");
close(fd);
exit(3);
} else {
printf("IOCTL passed:Num of ports %d\n",hubPortInfo.nports);
close(fd);
exit(0);
}
return 0;
}
I have verified that it breaks if built in 32 bit mode on x86_64 and that
the patch below fixes it.
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/devio.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2bd742ba812d..ffb2e242b100 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -1301,23 +1301,20 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg) | |||
1301 | return 0; | 1301 | return 0; |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | static int proc_ioctl (struct dev_state *ps, void __user *arg) | 1304 | static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) |
1305 | { | 1305 | { |
1306 | struct usbdevfs_ioctl ctrl; | ||
1307 | int size; | 1306 | int size; |
1308 | void *buf = NULL; | 1307 | void *buf = NULL; |
1309 | int retval = 0; | 1308 | int retval = 0; |
1310 | struct usb_interface *intf = NULL; | 1309 | struct usb_interface *intf = NULL; |
1311 | struct usb_driver *driver = NULL; | 1310 | struct usb_driver *driver = NULL; |
1312 | 1311 | ||
1313 | /* get input parameters and alloc buffer */ | 1312 | /* alloc buffer */ |
1314 | if (copy_from_user(&ctrl, arg, sizeof (ctrl))) | 1313 | if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { |
1315 | return -EFAULT; | ||
1316 | if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { | ||
1317 | if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) | 1314 | if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) |
1318 | return -ENOMEM; | 1315 | return -ENOMEM; |
1319 | if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { | 1316 | if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { |
1320 | if (copy_from_user (buf, ctrl.data, size)) { | 1317 | if (copy_from_user (buf, ctl->data, size)) { |
1321 | kfree(buf); | 1318 | kfree(buf); |
1322 | return -EFAULT; | 1319 | return -EFAULT; |
1323 | } | 1320 | } |
@@ -1333,9 +1330,9 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) | |||
1333 | 1330 | ||
1334 | if (ps->dev->state != USB_STATE_CONFIGURED) | 1331 | if (ps->dev->state != USB_STATE_CONFIGURED) |
1335 | retval = -EHOSTUNREACH; | 1332 | retval = -EHOSTUNREACH; |
1336 | else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) | 1333 | else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) |
1337 | retval = -EINVAL; | 1334 | retval = -EINVAL; |
1338 | else switch (ctrl.ioctl_code) { | 1335 | else switch (ctl->ioctl_code) { |
1339 | 1336 | ||
1340 | /* disconnect kernel driver from interface */ | 1337 | /* disconnect kernel driver from interface */ |
1341 | case USBDEVFS_DISCONNECT: | 1338 | case USBDEVFS_DISCONNECT: |
@@ -1367,7 +1364,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) | |||
1367 | if (driver == NULL || driver->ioctl == NULL) { | 1364 | if (driver == NULL || driver->ioctl == NULL) { |
1368 | retval = -ENOTTY; | 1365 | retval = -ENOTTY; |
1369 | } else { | 1366 | } else { |
1370 | retval = driver->ioctl (intf, ctrl.ioctl_code, buf); | 1367 | retval = driver->ioctl (intf, ctl->ioctl_code, buf); |
1371 | if (retval == -ENOIOCTLCMD) | 1368 | if (retval == -ENOIOCTLCMD) |
1372 | retval = -ENOTTY; | 1369 | retval = -ENOTTY; |
1373 | } | 1370 | } |
@@ -1376,15 +1373,42 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) | |||
1376 | 1373 | ||
1377 | /* cleanup and return */ | 1374 | /* cleanup and return */ |
1378 | if (retval >= 0 | 1375 | if (retval >= 0 |
1379 | && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 | 1376 | && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 |
1380 | && size > 0 | 1377 | && size > 0 |
1381 | && copy_to_user (ctrl.data, buf, size) != 0) | 1378 | && copy_to_user (ctl->data, buf, size) != 0) |
1382 | retval = -EFAULT; | 1379 | retval = -EFAULT; |
1383 | 1380 | ||
1384 | kfree(buf); | 1381 | kfree(buf); |
1385 | return retval; | 1382 | return retval; |
1386 | } | 1383 | } |
1387 | 1384 | ||
1385 | static int proc_ioctl_default(struct dev_state *ps, void __user *arg) | ||
1386 | { | ||
1387 | struct usbdevfs_ioctl ctrl; | ||
1388 | |||
1389 | if (copy_from_user(&ctrl, arg, sizeof (ctrl))) | ||
1390 | return -EFAULT; | ||
1391 | return proc_ioctl(ps, &ctrl); | ||
1392 | } | ||
1393 | |||
1394 | #ifdef CONFIG_COMPAT | ||
1395 | static int proc_ioctl_compat(struct dev_state *ps, void __user *arg) | ||
1396 | { | ||
1397 | struct usbdevfs_ioctl32 __user *uioc; | ||
1398 | struct usbdevfs_ioctl ctrl; | ||
1399 | u32 udata; | ||
1400 | |||
1401 | uioc = compat_ptr(arg); | ||
1402 | if (get_user(ctrl.ifno, &uioc->ifno) || | ||
1403 | get_user(ctrl.ioctl_code, &uioc->ioctl_code) || | ||
1404 | __get_user(udata, &uioc->data)) | ||
1405 | return -EFAULT; | ||
1406 | ctrl.data = compat_ptr(udata); | ||
1407 | |||
1408 | return proc_ioctl(ps, &ctrl); | ||
1409 | } | ||
1410 | #endif | ||
1411 | |||
1388 | /* | 1412 | /* |
1389 | * NOTE: All requests here that have interface numbers as parameters | 1413 | * NOTE: All requests here that have interface numbers as parameters |
1390 | * are assuming that somehow the configuration has been prevented from | 1414 | * are assuming that somehow the configuration has been prevented from |
@@ -1485,6 +1509,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
1485 | ret = proc_reapurbnonblock_compat(ps, p); | 1509 | ret = proc_reapurbnonblock_compat(ps, p); |
1486 | break; | 1510 | break; |
1487 | 1511 | ||
1512 | case USBDEVFS_IOCTL32: | ||
1513 | snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); | ||
1514 | ret = proc_ioctl_compat(ps, p); | ||
1515 | break; | ||
1488 | #endif | 1516 | #endif |
1489 | 1517 | ||
1490 | case USBDEVFS_DISCARDURB: | 1518 | case USBDEVFS_DISCARDURB: |
@@ -1519,7 +1547,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
1519 | 1547 | ||
1520 | case USBDEVFS_IOCTL: | 1548 | case USBDEVFS_IOCTL: |
1521 | snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); | 1549 | snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); |
1522 | ret = proc_ioctl(ps, p); | 1550 | ret = proc_ioctl_default(ps, p); |
1523 | break; | 1551 | break; |
1524 | } | 1552 | } |
1525 | usb_unlock_device(dev); | 1553 | usb_unlock_device(dev); |