aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2005-10-17 21:15:54 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:46 -0400
commitc36fc889b5a4fd66cfd9ba80d9e038745d349567 (patch)
treec49f295dfdf53a4c6f495be8414497f2cdf4a4d3 /drivers
parent72adaa962741e8e910300b66bb123b1a9c31a8a8 (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.c56
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
1304static int proc_ioctl (struct dev_state *ps, void __user *arg) 1304static 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
1385static 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
1395static 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);