USB: pid_ns: ensure pid is not freed during kill_pid_info_as_uid
[linux-2.6.git] / drivers / usb / core / devio.c
index 825e0ab..0ca54e2 100644 (file)
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>     /* for usbcore internals */
 #include <linux/cdev.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
@@ -50,9 +50,7 @@
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
 
-#include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
-#include "hub.h"
 
 #define USB_MAXBUS                     64
 #define USB_DEVICE_MAX                 USB_MAXBUS * 128
@@ -122,7 +120,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
-       lock_kernel();
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
 
        switch (orig) {
        case 0:
@@ -138,7 +136,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
                ret = -EINVAL;
        }
 
-       unlock_kernel();
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
        return ret;
 }
 
@@ -310,7 +308,8 @@ static struct async *async_getpending(struct dev_state *ps,
 
 static void snoop_urb(struct usb_device *udev,
                void __user *userurb, int pipe, unsigned length,
-               int timeout_or_status, enum snoop_when when)
+               int timeout_or_status, enum snoop_when when,
+               unsigned char *data, unsigned data_len)
 {
        static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
        static const char *dirs[] = {"out", "in"};
@@ -344,6 +343,11 @@ static void snoop_urb(struct usb_device *udev,
                                        "status %d\n",
                                        ep, t, d, length, timeout_or_status);
        }
+
+       if (data && data_len > 0) {
+               print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+                       data, data_len, 1);
+       }
 }
 
 #define AS_CONTINUATION        1
@@ -403,22 +407,26 @@ static void async_completed(struct urb *urb)
                sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
                sinfo.si_addr = as->userurb;
-               pid = as->pid;
+               pid = get_pid(as->pid);
                uid = as->uid;
                euid = as->euid;
                secid = as->secid;
        }
        snoop(&urb->dev->dev, "urb complete\n");
        snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
-                       as->status, COMPLETE);
+                       as->status, COMPLETE,
+                       ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
+                               NULL : urb->transfer_buffer, urb->actual_length);
        if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
                        as->status != -ENOENT)
                cancel_bulk_urbs(ps, as->bulk_addr);
        spin_unlock(&ps->lock);
 
-       if (signr)
+       if (signr) {
                kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
                                      euid, secid);
+               put_pid(pid);
+       }
 
        wake_up(&ps->wait);
 }
@@ -601,9 +609,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
 }
 
 static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
-                          unsigned int index)
+                          unsigned int request, unsigned int index)
 {
        int ret = 0;
+       struct usb_host_interface *alt_setting;
 
        if (ps->dev->state != USB_STATE_UNAUTHENTICATED
         && ps->dev->state != USB_STATE_ADDRESS
@@ -612,6 +621,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
        if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
                return 0;
 
+       /*
+        * check for the special corner case 'get_device_id' in the printer
+        * class specification, where wIndex is (interface << 8 | altsetting)
+        * instead of just interface
+        */
+       if (requesttype == 0xa1 && request == 0) {
+               alt_setting = usb_find_alt_setting(ps->dev->actconfig,
+                                                  index >> 8, index & 0xff);
+               if (alt_setting
+                && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
+                       index >>= 8;
+       }
+
        index &= 0xff;
        switch (requesttype & USB_RECIP_MASK) {
        case USB_RECIP_ENDPOINT:
@@ -653,8 +675,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
        const struct cred *cred = current_cred();
        int ret;
 
-       lock_kernel();
-
        ret = -ENOMEM;
        ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
        if (!ps)
@@ -713,7 +733,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
        usb_unlock_device(dev);
        snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
                        current->comm);
-       unlock_kernel();
        return ret;
 
  out_unlock_device:
@@ -721,7 +740,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
        usb_put_dev(dev);
  out_free_ps:
        kfree(ps);
-       unlock_kernel();
        return ret;
 }
 
@@ -768,7 +786,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 
        if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                return -EFAULT;
-       ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+       ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
+                             ctrl.wIndex);
        if (ret)
                return ret;
        wLength = ctrl.wLength;         /* To suppress 64k PAGE_SIZE warning */
@@ -778,6 +797,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
        if (!tbuf)
                return -ENOMEM;
        tmo = ctrl.timeout;
+       snoop(&dev->dev, "control urb: bRequestType=%02x "
+               "bRequest=%02x wValue=%04x "
+               "wIndex=%04x wLength=%04x\n",
+               ctrl.bRequestType, ctrl.bRequest,
+               __le16_to_cpup(&ctrl.wValue),
+               __le16_to_cpup(&ctrl.wIndex),
+               __le16_to_cpup(&ctrl.wLength));
        if (ctrl.bRequestType & 0x80) {
                if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
                                               ctrl.wLength)) {
@@ -785,15 +811,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                        return -EINVAL;
                }
                pipe = usb_rcvctrlpipe(dev, 0);
-               snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
 
                usb_unlock_device(dev);
                i = usb_control_msg(dev, pipe, ctrl.bRequest,
                                    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
                                    tbuf, ctrl.wLength, tmo);
                usb_lock_device(dev);
-               snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
-
+               snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
+                         tbuf, max(i, 0));
                if ((i > 0) && ctrl.wLength) {
                        if (copy_to_user(ctrl.data, tbuf, i)) {
                                free_page((unsigned long)tbuf);
@@ -808,14 +834,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                        }
                }
                pipe = usb_sndctrlpipe(dev, 0);
-               snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
+                       tbuf, ctrl.wLength);
 
                usb_unlock_device(dev);
                i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
                                    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
                                    tbuf, ctrl.wLength, tmo);
                usb_lock_device(dev);
-               snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
+               snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
        }
        free_page((unsigned long)tbuf);
        if (i < 0 && i != -EPIPE) {
@@ -861,12 +888,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                        kfree(tbuf);
                        return -EINVAL;
                }
-               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
 
                usb_unlock_device(dev);
                i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
                usb_lock_device(dev);
-               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
 
                if (!i && len2) {
                        if (copy_to_user(bulk.data, tbuf, len2)) {
@@ -881,12 +908,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                                return -EFAULT;
                        }
                }
-               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
 
                usb_unlock_device(dev);
                i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
                usb_lock_device(dev);
-               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
        }
        kfree(tbuf);
        if (i < 0)
@@ -954,10 +981,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 
 static int proc_connectinfo(struct dev_state *ps, void __user *arg)
 {
-       struct usbdevfs_connectinfo ci;
+       struct usbdevfs_connectinfo ci = {
+               .devnum = ps->dev->devnum,
+               .slow = ps->dev->speed == USB_SPEED_LOW
+       };
 
-       ci.devnum = ps->dev->devnum;
-       ci.slow = ps->dev->speed == USB_SPEED_LOW;
        if (copy_to_user(arg, &ci, sizeof(ci)))
                return -EFAULT;
        return 0;
@@ -1089,7 +1117,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        kfree(dr);
                        return -EINVAL;
                }
-               ret = check_ctrlrecip(ps, dr->bRequestType,
+               ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
                                      le16_to_cpup(&dr->wIndex));
                if (ret) {
                        kfree(dr);
@@ -1105,6 +1133,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        is_in = 0;
                        uurb->endpoint &= ~USB_DIR_IN;
                }
+               snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
+                       "bRequest=%02x wValue=%04x "
+                       "wIndex=%04x wLength=%04x\n",
+                       dr->bRequestType, dr->bRequest,
+                       __le16_to_cpup(&dr->wValue),
+                       __le16_to_cpup(&dr->wIndex),
+                       __le16_to_cpup(&dr->wLength));
                break;
 
        case USBDEVFS_URB_TYPE_BULK:
@@ -1188,6 +1223,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        free_async(as);
                        return -ENOMEM;
                }
+               /* Isochronous input data may end up being discontiguous
+                * if some of the packets are short.  Clear the buffer so
+                * that the gaps don't leak kernel data to userspace.
+                */
+               if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
+                       memset(as->urb->transfer_buffer, 0,
+                                       uurb->buffer_length);
        }
        as->urb->dev = ps->dev;
        as->urb->pipe = (uurb->type << 30) |
@@ -1248,7 +1290,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                }
        }
        snoop_urb(ps->dev, as->userurb, as->urb->pipe,
-                       as->urb->transfer_buffer_length, 0, SUBMIT);
+                       as->urb->transfer_buffer_length, 0, SUBMIT,
+                       is_in ? NULL : as->urb->transfer_buffer,
+                               uurb->buffer_length);
        async_newpending(as);
 
        if (usb_endpoint_xfer_bulk(&ep->desc)) {
@@ -1286,7 +1330,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                dev_printk(KERN_DEBUG, &ps->dev->dev,
                           "usbfs: usb_submit_urb returned %d\n", ret);
                snoop_urb(ps->dev, as->userurb, as->urb->pipe,
-                               0, ret, COMPLETE);
+                               0, ret, COMPLETE, NULL, 0);
                async_removepending(as);
                free_async(as);
                return ret;
@@ -1324,10 +1368,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
-       if (as->userbuffer && urb->actual_length)
-               if (copy_to_user(as->userbuffer, urb->transfer_buffer,
-                                urb->actual_length))
+       if (as->userbuffer && urb->actual_length) {
+               if (urb->number_of_packets > 0)         /* Isochronous */
+                       i = urb->transfer_buffer_length;
+               else                                    /* Non-Isoc */
+                       i = urb->actual_length;
+               if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
                        goto err_out;
+       }
        if (put_user(as->status, &userurb->status))
                goto err_out;
        if (put_user(urb->actual_length, &userurb->actual_length))
@@ -1637,10 +1685,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
        default:
                if (intf->dev.driver)
                        driver = to_usb_driver(intf->dev.driver);
-               if (driver == NULL || driver->ioctl == NULL) {
+               if (driver == NULL || driver->unlocked_ioctl == NULL) {
                        retval = -ENOTTY;
                } else {
-                       retval = driver->ioctl(intf, ctl->ioctl_code, buf);
+                       retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
                }
@@ -1723,6 +1771,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 
        if (!(file->f_mode & FMODE_WRITE))
                return -EPERM;
+
        usb_lock_device(dev);
        if (!connected(ps)) {
                usb_unlock_device(dev);
@@ -1889,9 +1938,7 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd,
 {
        int ret;
 
-       lock_kernel();
        ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
-       unlock_kernel();
 
        return ret;
 }
@@ -1902,9 +1949,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
 {
        int ret;
 
-       lock_kernel();
        ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
-       unlock_kernel();
 
        return ret;
 }