Commit 909b8503 authored by Henning Meier-Geinitz's avatar Henning Meier-Geinitz Committed by Greg Kroah-Hartman

[PATCH] scanner.c: fix race in ioctl_scanner()

This patch adds locking to ioctl_scanner() which was completely
lacking until now. The patch is originally from Oliver Neukum
<oliver@neukum.name>.

The patch was forward-ported from 2.4.
parent 8d99c8a3
...@@ -328,6 +328,8 @@ ...@@ -328,6 +328,8 @@
* - Accept devices with more than one interface. Only use interfaces that * - Accept devices with more than one interface. Only use interfaces that
* look like belonging to scanners. * look like belonging to scanners.
* - Fix compilation error when debugging is enabled. * - Fix compilation error when debugging is enabled.
* - Add locking to ioctl_scanner(). Thanks to Oliver Neukum
* <oliver@neukum.name>.
* *
* TODO * TODO
* - Remove the 2/3 endpoint limitation * - Remove the 2/3 endpoint limitation
...@@ -713,23 +715,25 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -713,23 +715,25 @@ ioctl_scanner(struct inode *inode, struct file *file,
{ {
struct usb_device *dev; struct usb_device *dev;
struct scn_usb_data *scn = file->private_data; struct scn_usb_data *scn = file->private_data;
int retval = -ENOTTY;
int scn_minor; int scn_minor;
scn_minor = USB_SCN_MINOR(inode); scn_minor = USB_SCN_MINOR(inode);
down(&(scn->sem));
dev = scn->scn_dev; dev = scn->scn_dev;
switch (cmd) switch (cmd)
{ {
case SCANNER_IOCTL_VENDOR : case SCANNER_IOCTL_VENDOR :
return (put_user(dev->descriptor.idVendor, (unsigned int *) arg)); retval = (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
break;
case SCANNER_IOCTL_PRODUCT : case SCANNER_IOCTL_PRODUCT :
return (put_user(dev->descriptor.idProduct, (unsigned int *) arg)); retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
break;
#ifdef PV8630 #ifdef PV8630
case PV8630_IOCTL_INREQUEST : case PV8630_IOCTL_INREQUEST :
{ {
int result;
struct { struct {
__u8 data; __u8 data;
__u8 request; __u8 request;
...@@ -737,10 +741,12 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -737,10 +741,12 @@ ioctl_scanner(struct inode *inode, struct file *file,
__u16 index; __u16 index;
} args; } args;
if (copy_from_user(&args, (void *)arg, sizeof(args))) if (copy_from_user(&args, (void *)arg, sizeof(args))) {
return -EFAULT; retval = -EFAULT;
break;
}
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
args.request, USB_TYPE_VENDOR| args.request, USB_TYPE_VENDOR|
USB_RECIP_DEVICE|USB_DIR_IN, USB_RECIP_DEVICE|USB_DIR_IN,
args.value, args.index, &args.data, args.value, args.index, &args.data,
...@@ -749,36 +755,36 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -749,36 +755,36 @@ ioctl_scanner(struct inode *inode, struct file *file,
dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request); dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
if (copy_to_user((void *)arg, &args, sizeof(args))) if (copy_to_user((void *)arg, &args, sizeof(args)))
return -EFAULT; retval = -EFAULT;
dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result); dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, retval);
return result; break;
} }
case PV8630_IOCTL_OUTREQUEST : case PV8630_IOCTL_OUTREQUEST :
{ {
int result;
struct { struct {
__u8 request; __u8 request;
__u16 value; __u16 value;
__u16 index; __u16 index;
} args; } args;
if (copy_from_user(&args, (void *)arg, sizeof(args))) if (copy_from_user(&args, (void *)arg, sizeof(args))) {
return -EFAULT; retval = -EFAULT;
break;
}
dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request); dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
args.request, USB_TYPE_VENDOR| args.request, USB_TYPE_VENDOR|
USB_RECIP_DEVICE|USB_DIR_OUT, USB_RECIP_DEVICE|USB_DIR_OUT,
args.value, args.index, NULL, args.value, args.index, NULL,
0, HZ*5); 0, HZ*5);
dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result); dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, retval);
return result; break;
} }
#endif /* PV8630 */ #endif /* PV8630 */
case SCANNER_IOCTL_CTRLMSG: case SCANNER_IOCTL_CTRLMSG:
...@@ -789,19 +795,26 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -789,19 +795,26 @@ ioctl_scanner(struct inode *inode, struct file *file,
} cmsg; } cmsg;
int pipe, nb, ret; int pipe, nb, ret;
unsigned char buf[64]; unsigned char buf[64];
retval = 0;
if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
return -EFAULT; if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) {
retval = -EFAULT;
break;
}
nb = cmsg.req.wLength; nb = cmsg.req.wLength;
if (nb > sizeof(buf)) if (nb > sizeof(buf)) {
return -EINVAL; retval = -EINVAL;
break;
}
if ((cmsg.req.bRequestType & 0x80) == 0) { if ((cmsg.req.bRequestType & 0x80) == 0) {
pipe = usb_sndctrlpipe(dev, 0); pipe = usb_sndctrlpipe(dev, 0);
if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) {
return -EFAULT; retval = -EFAULT;
break;
}
} else { } else {
pipe = usb_rcvctrlpipe(dev, 0); pipe = usb_rcvctrlpipe(dev, 0);
} }
...@@ -814,18 +827,20 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -814,18 +827,20 @@ ioctl_scanner(struct inode *inode, struct file *file,
if (ret < 0) { if (ret < 0) {
err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret); err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
return -EIO; retval = -EIO;
break;
} }
if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb)) if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
return -EFAULT; retval = -EFAULT;
return 0; break;
} }
default: default:
return -ENOTTY; break;
} }
return 0; up(&(scn->sem));
return retval;
} }
static struct static struct
......
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