ChangeSet 1.893.2.25, 2003/01/06 11:02:15-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 . diff -Nru a/drivers/usb/scanner.c b/drivers/usb/scanner.c --- a/drivers/usb/scanner.c Mon Jan 6 11:29:32 2003 +++ b/drivers/usb/scanner.c Mon Jan 6 11:29:32 2003 @@ -327,6 +327,8 @@ * - Accept devices with more than one interface. Only use interfaces that * look like belonging to scanners. * - Use altsetting[0], not altsetting[ifnum]. + * - Add locking to ioctl_scanner(). Thanks to Oliver Neukum + * . * * TODO * - Remove the 2/3 endpoint limitation @@ -417,7 +419,7 @@ dev = scn->scn_dev; - down(&(scn->sem)); /* Now protect the scn_usb_data structure */ + down(&(scn->sem)); /* Now protect the scn_usb_data structure */ up(&scn_mutex); /* Now handled by the above */ @@ -651,7 +653,7 @@ goto data_recvd; } } - + if (result == -EPIPE) { /* No hope */ if(usb_clear_halt(dev, scn->bulk_in_ep)) { err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret); @@ -699,30 +701,26 @@ ioctl_scanner(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + struct scn_usb_data *scn; struct usb_device *dev; + int retval = -ENOTTY; - kdev_t scn_minor; - - scn_minor = USB_SCN_MINOR(inode); - - if (!p_scn_table[scn_minor]) { - err("ioctl_scanner(%d): invalid scn_minor", scn_minor); - return -ENODEV; - } + scn = file->private_data; + down(&(scn->sem)); - dev = p_scn_table[scn_minor]->scn_dev; + 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; @@ -730,48 +728,42 @@ __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, 1, HZ*5); - 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); - - 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; - - dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request); + if (copy_from_user(&args, (void *)arg, sizeof(args))) { + retval = -EFAULT; + break; + } - 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); - - return result; + break; } #endif /* PV8630 */ case SCANNER_IOCTL_CTRLMSG: @@ -782,19 +774,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); } @@ -806,19 +805,21 @@ buf, nb, HZ); if (ret < 0) { - err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret); - return -EIO; + err("ioctl_scanner: control_msg returned %d\n", ret); + 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