ChangeSet 1.879.9.18, 2003/01/07 15:09:22-08:00, henning@meier-geinitz.de [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 . The patch was forward-ported from 2.4. diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c --- a/drivers/usb/image/scanner.c Wed Jan 8 11:58:08 2003 +++ b/drivers/usb/image/scanner.c Wed Jan 8 11:58:08 2003 @@ -328,6 +328,8 @@ * - Accept devices with more than one interface. Only use interfaces that * look like belonging to scanners. * - Fix compilation error when debugging is enabled. + * - Add locking to ioctl_scanner(). Thanks to Oliver Neukum + * . * * TODO * - Remove the 2/3 endpoint limitation @@ -713,23 +715,25 @@ { struct usb_device *dev; struct scn_usb_data *scn = file->private_data; + int retval = -ENOTTY; int scn_minor; scn_minor = USB_SCN_MINOR(inode); + down(&(scn->sem)); dev = scn->scn_dev; switch (cmd) { 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 : - return (put_user(dev->descriptor.idProduct, (unsigned int *) arg)); + retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg)); + break; #ifdef PV8630 case PV8630_IOCTL_INREQUEST : { - int result; - struct { __u8 data; __u8 request; @@ -737,10 +741,12 @@ __u16 index; } args; - if (copy_from_user(&args, (void *)arg, sizeof(args))) - return -EFAULT; + if (copy_from_user(&args, (void *)arg, sizeof(args))) { + 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| USB_RECIP_DEVICE|USB_DIR_IN, args.value, args.index, &args.data, @@ -749,36 +755,36 @@ 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))) - 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 : { - int result; - struct { __u8 request; __u16 value; __u16 index; } args; - if (copy_from_user(&args, (void *)arg, sizeof(args))) - return -EFAULT; + if (copy_from_user(&args, (void *)arg, sizeof(args))) { + 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); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), args.request, USB_TYPE_VENDOR| USB_RECIP_DEVICE|USB_DIR_OUT, args.value, args.index, NULL, 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 */ case SCANNER_IOCTL_CTRLMSG: @@ -789,19 +795,26 @@ } cmsg; int pipe, nb, ret; unsigned char buf[64]; - - if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) - return -EFAULT; + retval = 0; + + if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) { + retval = -EFAULT; + break; + } nb = cmsg.req.wLength; - if (nb > sizeof(buf)) - return -EINVAL; + if (nb > sizeof(buf)) { + retval = -EINVAL; + break; + } if ((cmsg.req.bRequestType & 0x80) == 0) { pipe = usb_sndctrlpipe(dev, 0); - if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) - return -EFAULT; + if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) { + retval = -EFAULT; + break; + } } else { pipe = usb_rcvctrlpipe(dev, 0); } @@ -814,18 +827,20 @@ if (ret < 0) { 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)) - return -EFAULT; + retval = -EFAULT; - return 0; + break; } default: - return -ENOTTY; + break; } - return 0; + up(&(scn->sem)); + return retval; } static struct