From 52fb743d3aa7ee27a4f3182816aa02dc3e513d9d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:41:14 -0500 Subject: USB: unify some error pathways in usbfs This patch (as1496) unifies the error-return pathways of several functions in the usbfs driver. This is not a very important change by itself; it merely prepares the way for the next patch in this series. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 96 +++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 46 deletions(-) (limited to 'drivers/usb/core/devio.c') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e3beaf229ee3..e8ade68f64e2 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -806,8 +806,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } pipe = usb_rcvctrlpipe(dev, 0); snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); @@ -821,15 +821,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) tbuf, max(i, 0)); if ((i > 0) && ctrl.wLength) { if (copy_to_user(ctrl.data, tbuf, i)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (ctrl.wLength) { if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } pipe = usb_sndctrlpipe(dev, 0); @@ -843,14 +843,16 @@ static int proc_control(struct dev_state *ps, void __user *arg) usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); } - free_page((unsigned long)tbuf); if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); } - return i; + ret = i; + done: + free_page((unsigned long) tbuf); + return ret; } static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -884,8 +886,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) tmo = bulk.timeout; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { - kfree(tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); @@ -896,15 +898,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); @@ -914,10 +916,10 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) usb_lock_device(dev); snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0); } + ret = (i < 0 ? i : len2); + done: kfree(tbuf); - if (i < 0) - return i; - return len2; + return ret; } static int proc_resetep(struct dev_state *ps, void __user *arg) @@ -1062,7 +1064,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; - struct async *as; + struct async *as = NULL; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; @@ -1108,19 +1110,17 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { - kfree(dr); - return -EINVAL; + ret = -EINVAL; + goto error; } ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, le16_to_cpup(&dr->wIndex)); - if (ret) { - kfree(dr); - return ret; - } + if (ret) + goto error; uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; @@ -1176,22 +1176,22 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { - kfree(isopkt); - return -EFAULT; + ret = -EFAULT; + goto error; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { /* arbitrary limit, * sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { - kfree(isopkt); - return -EINVAL; + ret = -EINVAL; + goto error; } totlen += isopkt[u].length; } /* 3072 * 64 microframes */ if (totlen > 196608) { - kfree(isopkt); - return -EINVAL; + ret = -EINVAL; + goto error; } uurb->buffer_length = totlen; break; @@ -1202,24 +1202,20 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { - kfree(isopkt); - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } as = alloc_async(uurb->number_of_packets); if (!as) { - kfree(isopkt); - kfree(dr); - return -ENOMEM; + ret = -ENOMEM; + goto error; } if (uurb->buffer_length > 0) { as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); if (!as->urb->transfer_buffer) { - kfree(isopkt); - kfree(dr); - free_async(as); - return -ENOMEM; + ret = -ENOMEM; + goto error; } /* Isochronous input data may end up being discontiguous * if some of the packets are short. Clear the buffer so @@ -1253,6 +1249,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; + dr = NULL; as->urb->start_frame = uurb->start_frame; as->urb->number_of_packets = uurb->number_of_packets; if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1268,6 +1265,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, totlen += isopkt[u].length; } kfree(isopkt); + isopkt = NULL; as->ps = ps; as->userurb = arg; if (is_in && uurb->buffer_length > 0) @@ -1282,8 +1280,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (!is_in && uurb->buffer_length > 0) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, uurb->buffer_length)) { - free_async(as); - return -EFAULT; + ret = -EFAULT; + goto error; } } snoop_urb(ps->dev, as->userurb, as->urb->pipe, @@ -1329,10 +1327,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, snoop_urb(ps->dev, as->userurb, as->urb->pipe, 0, ret, COMPLETE, NULL, 0); async_removepending(as); - free_async(as); - return ret; + goto error; } return 0; + + error: + kfree(isopkt); + kfree(dr); + if (as) + free_async(as); + return ret; } static int proc_submiturb(struct dev_state *ps, void __user *arg) -- cgit v1.2.3 From add1aaeabe6b08ed26381a2a06e505b2f09c3ba5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:41:25 -0500 Subject: USB: change the memory limits in usbfs URB submission For a long time people have complained about the limitations imposed by usbfs. URBs coming from userspace are not allowed to have transfer buffers larger than a more-or-less arbitrary maximum. While it is generally a good idea to avoid large transfer buffers (because the data has to be bounced to/from a contiguous kernel-space buffer), it's not the kernel's job to enforce such limits. Programs should be allowed to submit URBs as large as they like; if there isn't sufficient contiguous memory available then the submission will fail with a simple ENOMEM error. On the other hand, we would like to prevent programs from submitting a lot of small URBs and using up all the DMA-able kernel memory. To that end, this patch (as1497) replaces the old limits on individual transfer buffers with a single global limit on the total amount of memory in use by usbfs. The global limit is set to 16 MB as a nice compromise value: not too big, but large enough to hold about 300 ms of data for high-speed transfers. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 76 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 19 deletions(-) (limited to 'drivers/usb/core/devio.c') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e8ade68f64e2..b69768b7d226 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -86,6 +86,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + unsigned int mem_usage; int status; u32 secid; u8 bulk_addr; @@ -108,8 +109,26 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) -#define MAX_USBFS_BUFFER_SIZE 16384 +/* Limit on the total amount of memory we can allocate for transfers */ +#define MAX_USBFS_MEMORY_USAGE 16777216 /* 16 MB */ +static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ + +/* Check whether it's okay to allocate more memory for a transfer */ +static int usbfs_increase_memory_usage(unsigned amount) +{ + atomic_add(amount, &usbfs_memory_usage); + if (atomic_read(&usbfs_memory_usage) <= MAX_USBFS_MEMORY_USAGE) + return 0; + atomic_sub(amount, &usbfs_memory_usage); + return -ENOMEM; +} + +/* Memory for a transfer is being deallocated */ +static void usbfs_decrease_memory_usage(unsigned amount) +{ + atomic_sub(amount, &usbfs_memory_usage); +} static int connected(struct dev_state *ps) { @@ -253,6 +272,7 @@ static void free_async(struct async *as) kfree(as->urb->transfer_buffer); kfree(as->urb->setup_packet); usb_free_urb(as->urb); + usbfs_decrease_memory_usage(as->mem_usage); kfree(as); } @@ -792,9 +812,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ if (wLength > PAGE_SIZE) return -EINVAL; + ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + + sizeof(struct usb_ctrlrequest)); + if (ret) + return ret; tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); - if (!tbuf) - return -ENOMEM; + if (!tbuf) { + ret = -ENOMEM; + goto done; + } tmo = ctrl.timeout; snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " @@ -852,6 +878,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) ret = i; done: free_page((unsigned long) tbuf); + usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) + + sizeof(struct usb_ctrlrequest)); return ret; } @@ -879,10 +907,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 > MAX_USBFS_BUFFER_SIZE) + if (len1 > MAX_USBFS_MEMORY_USAGE) return -EINVAL; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) - return -ENOMEM; + ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); + if (ret) + return ret; + if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } tmo = bulk.timeout; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { @@ -919,6 +952,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) ret = (i < 0 ? i : len2); done: kfree(tbuf); + usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); return ret; } @@ -1097,14 +1131,14 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } if (!ep) return -ENOENT; + + u = 0; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; - /* min 8 byte setup packet, - * max 8 byte setup plus an arbitrary data stage */ - if (uurb->buffer_length < 8 || - uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) + /* min 8 byte setup packet */ + if (uurb->buffer_length < 8) return -EINVAL; dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); if (!dr) @@ -1138,6 +1172,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, __le16_to_cpup(&dr->wValue), __le16_to_cpup(&dr->wIndex), __le16_to_cpup(&dr->wLength)); + u = sizeof(struct usb_ctrlrequest); break; case USBDEVFS_URB_TYPE_BULK: @@ -1151,8 +1186,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, goto interrupt_urb; } uurb->number_of_packets = 0; - if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) - return -EINVAL; break; case USBDEVFS_URB_TYPE_INTERRUPT: @@ -1160,8 +1193,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; interrupt_urb: uurb->number_of_packets = 0; - if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) - return -EINVAL; break; case USBDEVFS_URB_TYPE_ISO: @@ -1188,17 +1219,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } totlen += isopkt[u].length; } - /* 3072 * 64 microframes */ - if (totlen > 196608) { - ret = -EINVAL; - goto error; - } + u *= sizeof(struct usb_iso_packet_descriptor); uurb->buffer_length = totlen; break; default: return -EINVAL; } + + if (uurb->buffer_length > MAX_USBFS_MEMORY_USAGE) { + ret = -EINVAL; + goto error; + } if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { @@ -1210,6 +1242,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ret = -ENOMEM; goto error; } + u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length; + ret = usbfs_increase_memory_usage(u); + if (ret) + goto error; + as->mem_usage = u; + if (uurb->buffer_length > 0) { as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); -- cgit v1.2.3 From 3f5eb8d5688a5266ab943cf94aebe4c0eea726a3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:41:35 -0500 Subject: USB: make the usbfs memory limit configurable The 16-MB global limit on memory used by usbfs isn't suitable for all people. It's a reasonable default, but there are applications (especially for SuperSpeed devices) that need a lot more. This patch (as1498) creates a writable module parameter for usbcore to control the global limit. The default is still 16 MB, but users can change it at runtime, even after usbcore has been loaded. As a special case, setting the value to 0 is treated the same as the hard limit of 2047 MB. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/usb/core/devio.c | 26 ++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/usb/core/devio.c') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a0c5c5f4fce6..72c68bbec5d4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2632,6 +2632,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. [USB] Start with the old device initialization scheme (default 0 = off). + usbcore.usbfs_memory_mb= + [USB] Memory limit (in MB) for buffers allocated by + usbfs (default = 16, 0 = max = 2047). + usbcore.use_both_schemes= [USB] Try the other device initialization scheme if the first one fails (default 1 = enabled). diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b69768b7d226..d8cf06f186f2 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -110,15 +110,33 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) /* Limit on the total amount of memory we can allocate for transfers */ -#define MAX_USBFS_MEMORY_USAGE 16777216 /* 16 MB */ +static unsigned usbfs_memory_mb = 16; +module_param(usbfs_memory_mb, uint, 0644); +MODULE_PARM_DESC(usbfs_memory_mb, + "maximum MB allowed for usbfs buffers (0 = no limit)"); + +/* Hard limit, necessary to avoid aithmetic overflow */ +#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ /* Check whether it's okay to allocate more memory for a transfer */ static int usbfs_increase_memory_usage(unsigned amount) { + unsigned lim; + + /* + * Convert usbfs_memory_mb to bytes, avoiding overflows. + * 0 means use the hard limit (effectively unlimited). + */ + lim = ACCESS_ONCE(usbfs_memory_mb); + if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) + lim = USBFS_XFER_MAX; + else + lim <<= 20; + atomic_add(amount, &usbfs_memory_usage); - if (atomic_read(&usbfs_memory_usage) <= MAX_USBFS_MEMORY_USAGE) + if (atomic_read(&usbfs_memory_usage) <= lim) return 0; atomic_sub(amount, &usbfs_memory_usage); return -ENOMEM; @@ -907,7 +925,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 > MAX_USBFS_MEMORY_USAGE) + if (len1 >= USBFS_XFER_MAX) return -EINVAL; ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) @@ -1227,7 +1245,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; } - if (uurb->buffer_length > MAX_USBFS_MEMORY_USAGE) { + if (uurb->buffer_length >= USBFS_XFER_MAX) { ret = -EINVAL; goto error; } -- cgit v1.2.3 From 1b41c8321e495337e877ca02d0b9680bc4112eff Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 16 Dec 2011 11:26:30 -0800 Subject: usbfs: Fix oops related to user namespace conversion. When running the Point Grey "flycap" program for their USB 3.0 camera (which was running as a USB 2.0 device for some reason), I trigger this oops whenever I try to open a video stream: Dec 15 16:48:34 puck kernel: [ 1798.715559] BUG: unable to handle kernel NULL pointer dereference at (null) Dec 15 16:48:34 puck kernel: [ 1798.719153] IP: [] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.720991] PGD 6f833067 PUD 6fc56067 PMD 0 Dec 15 16:48:34 puck kernel: [ 1798.722815] Oops: 0002 [#1] SMP Dec 15 16:48:34 puck kernel: [ 1798.724627] CPU 0 Dec 15 16:48:34 puck kernel: [ 1798.724636] Modules linked in: ecryptfs encrypted_keys sha1_generic trusted binfmt_misc sha256_generic aesni_intel cryptd aes_x86_64 aes_generic parport_pc dm_crypt ppdev joydev snd_hda_codec_hdmi snd_hda_codec_conexant arc4 iwlwifi snd_hda_intel snd_hda_codec snd_hwdep snd_pcm thinkpad_acpi mac80211 snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer btusb uvcvideo snd_seq_device bluetooth videodev psmouse snd v4l2_compat_ioctl32 serio_raw tpm_tis cfg80211 tpm tpm_bios nvram soundcore snd_page_alloc lp parport i915 xhci_hcd ahci libahci drm_kms_helper drm sdhci_pci sdhci e1000e i2c_algo_bit video Dec 15 16:48:34 puck kernel: [ 1798.734212] Dec 15 16:48:34 puck kernel: [ 1798.736162] Pid: 2713, comm: FlyCap2 Not tainted 3.2.0-rc5+ #28 LENOVO 4286CTO/4286CTO Dec 15 16:48:34 puck kernel: [ 1798.738148] RIP: 0010:[] [] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.740134] RSP: 0018:ffff88005715fd78 EFLAGS: 00010296 Dec 15 16:48:34 puck kernel: [ 1798.742118] RAX: 00000000fffffff4 RBX: ffff88006fe8f900 RCX: 0000000000004118 Dec 15 16:48:34 puck kernel: [ 1798.744116] RDX: 0000000001000000 RSI: 0000000000016390 RDI: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.746087] RBP: ffff88005715fd88 R08: 0000000000000000 R09: ffffffff8146f22e Dec 15 16:48:34 puck kernel: [ 1798.748018] R10: ffff88006e520ac0 R11: 0000000000000001 R12: ffff88005715fe28 Dec 15 16:48:34 puck kernel: [ 1798.749916] R13: ffff88005d31df00 R14: ffff88006fe8f900 R15: 00007f688c995cb8 Dec 15 16:48:34 puck kernel: [ 1798.751785] FS: 00007f68a366da40(0000) GS:ffff880100200000(0000) knlGS:0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.753659] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 Dec 15 16:48:34 puck kernel: [ 1798.755509] CR2: 0000000000000000 CR3: 00000000706bb000 CR4: 00000000000406f0 Dec 15 16:48:34 puck kernel: [ 1798.757334] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.759124] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Dec 15 16:48:34 puck kernel: [ 1798.760871] Process FlyCap2 (pid: 2713, threadinfo ffff88005715e000, task ffff88006c675b80) Dec 15 16:48:34 puck kernel: [ 1798.762605] Stack: Dec 15 16:48:34 puck kernel: [ 1798.764297] ffff88005715fe28 0000000000000000 ffff88005715fe08 ffffffff81479058 Dec 15 16:48:34 puck kernel: [ 1798.766020] 0000000000000000 ffffea0000004000 ffff880000004118 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.767750] ffff880000000001 ffff88006e520ac0 fffffff46fd81180 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.769472] Call Trace: Dec 15 16:48:34 puck kernel: [ 1798.771147] [] proc_do_submiturb+0x778/0xa00 Dec 15 16:48:34 puck kernel: [ 1798.772798] [] usbdev_do_ioctl+0x24d/0x1200 Dec 15 16:48:34 puck kernel: [ 1798.774410] [] usbdev_ioctl+0xe/0x20 Dec 15 16:48:34 puck kernel: [ 1798.775975] [] do_vfs_ioctl+0x99/0x600 Dec 15 16:48:34 puck kernel: [ 1798.777534] [] sys_ioctl+0x91/0xa0 Dec 15 16:48:34 puck kernel: [ 1798.779088] [] system_call_fastpath+0x16/0x1b ec 15 16:48:34 puck kernel: [ 1798.780634] Code: 51 ff ff ff e9 29 ff ff ff 0f 1f 40 00 55 48 89 e5 53 48 83 ec 08 66 66 66 66 90 48 89 fb 48 8b 7f 18 e8 a6 ea c0 ff 4 8 8b 7b 20 ff 0f 0f 94 c0 84 c0 74 05 e8 d3 99 c1 ff 48 8b 43 40 48 8b Dec 15 16:48:34 puck kernel: [ 1798.783970] RIP [] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.785630] RSP Dec 15 16:48:34 puck kernel: [ 1798.787274] CR2: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.794728] ---[ end trace 52894d3355f88d19 ]--- markup_oops.pl says the oops is in put_cred: ffffffff81478401: 48 89 e5 mov %rsp,%rbp ffffffff81478404: 53 push %rbx ffffffff81478405: 48 83 ec 08 sub $0x8,%rsp ffffffff81478409: e8 f2 c0 1a 00 callq ffffffff81624500 ffffffff8147840e: 48 89 fb mov %rdi,%rbx | %ebx => ffff88006fe8f900 put_pid(as->pid); ffffffff81478411: 48 8b 7f 18 mov 0x18(%rdi),%rdi ffffffff81478415: e8 a6 ea c0 ff callq ffffffff81086ec0 put_cred(as->cred); ffffffff8147841a: 48 8b 7b 20 mov 0x20(%rbx),%rdi | %edi => 0 %ebx = ffff88006fe8f900 */ static inline int atomic_dec_and_test(atomic_t *v) { unsigned char c; asm volatile(LOCK_PREFIX "decl %0; sete %1" *ffffffff8147841e: f0 ff 0f lock decl (%rdi) | %edi = 0 <--- faulting instruction ffffffff81478421: 0f 94 c0 sete %al static inline void put_cred(const struct cred *_cred) { struct cred *cred = (struct cred *) _cred; validate_creds(cred); if (atomic_dec_and_test(&(cred)->usage)) ffffffff81478424: 84 c0 test %al,%al ffffffff81478426: 74 05 je ffffffff8147842d __put_cred(cred); ffffffff81478428: e8 d3 99 c1 ff callq ffffffff81091e00 <__put_cred> kfree(as->urb->transfer_buffer); ffffffff8147842d: 48 8b 43 40 mov 0x40(%rbx),%rax ffffffff81478431: 48 8b 78 68 mov 0x68(%rax),%rdi ffffffff81478435: e8 a6 e1 ce ff callq ffffffff811665e0 kfree(as->urb->setup_packet); ffffffff8147843a: 48 8b 43 40 mov 0x40(%rbx),%rax ffffffff8147843e: 48 8b b8 90 00 00 00 mov 0x90(%rax),%rdi ffffffff81478445: e8 96 e1 ce ff callq ffffffff811665e0 usb_free_urb(as->urb); ffffffff8147844a: 48 8b 7b 40 mov 0x40(%rbx),%rdi ffffffff8147844e: e8 0d 6b ff ff callq ffffffff8146ef60 This bug seems to have been introduced by commit d178bc3a708f39cbfefc3fab37032d3f2511b4ec "user namespace: usb: make usb urbs user namespace aware (v2)" I'm not sure if this is right fix, but it does stop the oops. Unfortunately, the Point Grey software still refuses to work, but it's a closed source app, so I can't fix it. Signed-off-by: Sarah Sharp Acked-by: Serge Hallyn Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/core/devio.c') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d8cf06f186f2..3af5e2dd1d82 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -286,7 +286,8 @@ static struct async *alloc_async(unsigned int numisoframes) static void free_async(struct async *as) { put_pid(as->pid); - put_cred(as->cred); + if (as->cred) + put_cred(as->cred); kfree(as->urb->transfer_buffer); kfree(as->urb->setup_packet); usb_free_urb(as->urb); -- cgit v1.2.3