USB: mos7720: fix broken control requests
authorJohan Hovold <jhovold@gmail.com>
Tue, 13 Aug 2013 11:27:34 +0000 (13:27 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Aug 2013 15:26:28 +0000 (08:26 -0700)
commit ef6c8c1d733e244f0499035be0dabe1f4ed98c6f upstream.

The parallel-port code of the drivers used a stack allocated
control-request buffer for asynchronous (and possibly deferred) control
requests. This not only violates the no-DMA-from-stack requirement but
could also lead to corrupt control requests being submitted.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/serial/mos7720.c

index 77d974d..cdde45d 100644 (file)
@@ -97,6 +97,7 @@ struct urbtracker {
        struct list_head        urblist_entry;
        struct kref             ref_count;
        struct urb              *urb;
+       struct usb_ctrlrequest  *setup;
 };
 
 enum mos7715_pp_modes {
@@ -279,6 +280,7 @@ static void destroy_urbtracker(struct kref *kref)
        struct mos7715_parport *mos_parport = urbtrack->mos_parport;
        dbg("%s called", __func__);
        usb_free_urb(urbtrack->urb);
+       kfree(urbtrack->setup);
        kfree(urbtrack);
        kref_put(&mos_parport->ref_count, destroy_mos_parport);
 }
@@ -363,7 +365,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
        struct urbtracker *urbtrack;
        int ret_val;
        unsigned long flags;
-       struct usb_ctrlrequest setup;
        struct usb_serial *serial = mos_parport->serial;
        struct usb_device *usbdev = serial->dev;
        dbg("%s called", __func__);
@@ -382,14 +383,20 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
                kfree(urbtrack);
                return -ENOMEM;
        }
-       setup.bRequestType = (__u8)0x40;
-       setup.bRequest = (__u8)0x0e;
-       setup.wValue = get_reg_value(reg, dummy);
-       setup.wIndex = get_reg_index(reg);
-       setup.wLength = 0;
+       urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_KERNEL);
+       if (!urbtrack->setup) {
+               usb_free_urb(urbtrack->urb);
+               kfree(urbtrack);
+               return -ENOMEM;
+       }
+       urbtrack->setup->bRequestType = (__u8)0x40;
+       urbtrack->setup->bRequest = (__u8)0x0e;
+       urbtrack->setup->wValue = get_reg_value(reg, dummy);
+       urbtrack->setup->wIndex = get_reg_index(reg);
+       urbtrack->setup->wLength = 0;
        usb_fill_control_urb(urbtrack->urb, usbdev,
                             usb_sndctrlpipe(usbdev, 0),
-                            (unsigned char *)&setup,
+                            (unsigned char *)urbtrack->setup,
                             NULL, 0, async_complete, urbtrack);
        kref_init(&urbtrack->ref_count);
        INIT_LIST_HEAD(&urbtrack->urblist_entry);