diff options
| author | Hemant Kumar <hemantk@codeaurora.org> | 2016-07-28 12:00:36 -0700 |
|---|---|---|
| committer | Hemant Kumar <hemantk@codeaurora.org> | 2016-07-29 11:46:23 -0700 |
| commit | d5ccebfe354149e263b380c2958aa452a80c3ef9 (patch) | |
| tree | fbbee7fb417635eca049f6a593cbacbdf2626c8e /drivers/usb/gadget/function | |
| parent | 956d9b1ab3db6c7fef95964f7f6be8860433b74e (diff) | |
usb: gadget: f_cdev: Fix NULL ptr dereference in usb_cser_notify
Upon usb disconnect or composition switch notify ep request buffer
as well as the request are freed. This is racing with user space
ioctl on character device trying to send the notification to USB
host. As a result notify ep request buffer is being dereferenced
causing NULL pointer dereference. Fix the issue by checking
is_connected flag by taking port lock before accessing notify
ep request and request buffer.
Change-Id: I380efdf90305a65d4cde46dfe44762ac11c87678
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Diffstat (limited to 'drivers/usb/gadget/function')
| -rw-r--r-- | drivers/usb/gadget/function/f_cdev.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 0a9a3afd72dd..b22ea656367e 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -529,6 +529,14 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value, const unsigned len = sizeof(*notify) + length; void *buf; int status; + unsigned long flags; + + spin_lock_irqsave(&port->port_lock, flags); + if (!port->is_connected) { + spin_unlock_irqrestore(&port->port_lock, flags); + pr_debug("%s: port disconnected\n", __func__); + return -ENODEV; + } req = port->port_usb.notify_req; port->port_usb.notify_req = NULL; @@ -544,7 +552,9 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value, notify->wValue = cpu_to_le16(value); notify->wIndex = cpu_to_le16(port->port_usb.data_id); notify->wLength = cpu_to_le16(length); + /* 2 byte data copy */ memcpy(buf, data, length); + spin_unlock_irqrestore(&port->port_lock, flags); status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status < 0) { |
