aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/usb/core/devio.c56
-rw-r--r--fs/compat_ioctl.c1
-rw-r--r--include/linux/usbdevice_fs.h7
3 files changed, 50 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);
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e28a74203f3b..a327e03753ac 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -3050,6 +3050,7 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
3050HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control) 3050HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
3051HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk) 3051HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
3052HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) 3052HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
3053COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
3053/* i2c */ 3054/* i2c */
3054HANDLE_IOCTL(I2C_FUNCS, w_long) 3055HANDLE_IOCTL(I2C_FUNCS, w_long)
3055HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) 3056HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 9facf733800c..8859f0b41543 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -140,6 +140,12 @@ struct usbdevfs_urb32 {
140 compat_caddr_t usercontext; /* unused */ 140 compat_caddr_t usercontext; /* unused */
141 struct usbdevfs_iso_packet_desc iso_frame_desc[0]; 141 struct usbdevfs_iso_packet_desc iso_frame_desc[0];
142}; 142};
143
144struct usbdevfs_ioctl32 {
145 s32 ifno;
146 s32 ioctl_code;
147 compat_caddr_t data;
148};
143#endif 149#endif
144 150
145#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) 151#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
@@ -160,6 +166,7 @@ struct usbdevfs_urb32 {
160#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) 166#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
161#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo) 167#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo)
162#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl) 168#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl)
169#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32)
163#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) 170#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo)
164#define USBDEVFS_RESET _IO('U', 20) 171#define USBDEVFS_RESET _IO('U', 20)
165#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) 172#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)