USB: mos7720: fix broken control requests

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.

Cc: stable@vger.kernel.org
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Johan Hovold 2013-08-13 13:27:34 +02:00 committed by Greg Kroah-Hartman
parent 304ab4ab07
commit ef6c8c1d73

View File

@ -90,6 +90,7 @@ struct urbtracker {
struct list_head urblist_entry; struct list_head urblist_entry;
struct kref ref_count; struct kref ref_count;
struct urb *urb; struct urb *urb;
struct usb_ctrlrequest *setup;
}; };
enum mos7715_pp_modes { enum mos7715_pp_modes {
@ -271,6 +272,7 @@ static void destroy_urbtracker(struct kref *kref)
struct mos7715_parport *mos_parport = urbtrack->mos_parport; struct mos7715_parport *mos_parport = urbtrack->mos_parport;
usb_free_urb(urbtrack->urb); usb_free_urb(urbtrack->urb);
kfree(urbtrack->setup);
kfree(urbtrack); kfree(urbtrack);
kref_put(&mos_parport->ref_count, destroy_mos_parport); kref_put(&mos_parport->ref_count, destroy_mos_parport);
} }
@ -355,7 +357,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
struct urbtracker *urbtrack; struct urbtracker *urbtrack;
int ret_val; int ret_val;
unsigned long flags; unsigned long flags;
struct usb_ctrlrequest setup;
struct usb_serial *serial = mos_parport->serial; struct usb_serial *serial = mos_parport->serial;
struct usb_device *usbdev = serial->dev; struct usb_device *usbdev = serial->dev;
@ -373,14 +374,20 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
kfree(urbtrack); kfree(urbtrack);
return -ENOMEM; return -ENOMEM;
} }
setup.bRequestType = (__u8)0x40; urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_KERNEL);
setup.bRequest = (__u8)0x0e; if (!urbtrack->setup) {
setup.wValue = get_reg_value(reg, dummy); usb_free_urb(urbtrack->urb);
setup.wIndex = get_reg_index(reg); kfree(urbtrack);
setup.wLength = 0; 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_fill_control_urb(urbtrack->urb, usbdev,
usb_sndctrlpipe(usbdev, 0), usb_sndctrlpipe(usbdev, 0),
(unsigned char *)&setup, (unsigned char *)urbtrack->setup,
NULL, 0, async_complete, urbtrack); NULL, 0, async_complete, urbtrack);
kref_init(&urbtrack->ref_count); kref_init(&urbtrack->ref_count);
INIT_LIST_HEAD(&urbtrack->urblist_entry); INIT_LIST_HEAD(&urbtrack->urblist_entry);