From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, Alan Stern <stern@rowland.harvard.edu>,
Andrey Konovalov <andreyknvl@google.com>,
Felipe Balbi <felipe.balbi@linux.intel.com>
Subject: [PATCH 3.18 02/32] USB: gadgetfs: Fix crash caused by inadequate synchronization
Date: Tue, 10 Oct 2017 21:50:23 +0200 [thread overview]
Message-ID: <20171010184827.098765335@linuxfoundation.org> (raw)
In-Reply-To: <20171010184827.005589196@linuxfoundation.org>
3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern <stern@rowland.harvard.edu>
commit 520b72fc64debf8a86c3853b8e486aa5982188f0 upstream.
The gadgetfs driver (drivers/usb/gadget/legacy/inode.c) was written
before the UDC and composite frameworks were adopted; it is a legacy
driver. As such, it expects that once bound to a UDC controller, it
will not be unbound until it unregisters itself.
However, the UDC framework does unbind function drivers while they are
still registered. When this happens, it can cause the gadgetfs driver
to misbehave or crash. For example, userspace can cause a crash by
opening the device file and doing an ioctl call before setting up a
configuration (found by Andrey Konovalov using the syzkaller fuzzer).
This patch adds checks and synchronization to prevent these bad
behaviors. It adds a udc_usage counter that the driver increments at
times when it is using a gadget interface without holding the private
spinlock. The unbind routine waits for this counter to go to 0 before
returning, thereby ensuring that the UDC is no longer in use.
The patch also adds a check in the dev_ioctl() routine to make sure
the driver is bound to a UDC before dereferencing the gadget pointer,
and it makes destroy_ep_files() synchronize with the endpoint I/O
routines, to prevent the user from accessing an endpoint data
structure after it has been removed.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: Andrey Konovalov <andreyknvl@google.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/usb/gadget/legacy/inode.c | 41 +++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -26,7 +26,7 @@
#include <linux/poll.h>
#include <linux/mmu_context.h>
#include <linux/aio.h>
-
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
@@ -113,6 +113,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
atomic_t count;
+ int udc_usage;
enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
@@ -620,9 +621,9 @@ static void ep_aio_complete(struct usb_e
priv->actual = req->actual;
schedule_work(&priv->work);
}
- spin_unlock(&epdata->dev->lock);
usb_ep_free_request(ep, req);
+ spin_unlock(&epdata->dev->lock);
put_ep(epdata);
}
@@ -1020,9 +1021,11 @@ ep0_read (struct file *fd, char __user *
struct usb_request *req = dev->req;
if ((retval = setup_req (ep, req, 0)) == 0) {
+ ++dev->udc_usage;
spin_unlock_irq (&dev->lock);
retval = usb_ep_queue (ep, req, GFP_KERNEL);
spin_lock_irq (&dev->lock);
+ --dev->udc_usage;
}
dev->state = STATE_DEV_CONNECTED;
@@ -1214,6 +1217,7 @@ ep0_write (struct file *fd, const char _
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
dev->state = STATE_DEV_CONNECTED;
+ ++dev->udc_usage;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@@ -1225,6 +1229,7 @@ ep0_write (struct file *fd, const char _
GFP_KERNEL);
}
spin_lock_irq(&dev->lock);
+ --dev->udc_usage;
if (retval < 0) {
clean_req (dev->gadget->ep0, dev->req);
} else
@@ -1321,9 +1326,21 @@ static long dev_ioctl (struct file *fd,
struct usb_gadget *gadget = dev->gadget;
long ret = -ENOTTY;
- if (gadget->ops->ioctl)
+ spin_lock_irq(&dev->lock);
+ if (dev->state == STATE_DEV_OPENED ||
+ dev->state == STATE_DEV_UNBOUND) {
+ /* Not bound to a UDC */
+ } else if (gadget->ops->ioctl) {
+ ++dev->udc_usage;
+ spin_unlock_irq(&dev->lock);
+
ret = gadget->ops->ioctl (gadget, code, value);
+ spin_lock_irq(&dev->lock);
+ --dev->udc_usage;
+ }
+ spin_unlock_irq(&dev->lock);
+
return ret;
}
@@ -1554,10 +1571,12 @@ delegate:
if (value < 0)
break;
+ ++dev->udc_usage;
spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, dev->req,
GFP_KERNEL);
spin_lock (&dev->lock);
+ --dev->udc_usage;
if (value < 0) {
clean_req (gadget->ep0, dev->req);
break;
@@ -1581,8 +1600,12 @@ delegate:
req->length = value;
req->zero = value < w_length;
+ ++dev->udc_usage;
spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
+ spin_lock(&dev->lock);
+ --dev->udc_usage;
+ spin_unlock(&dev->lock);
if (value < 0) {
DBG (dev, "ep_queue --> %d\n", value);
req->status = 0;
@@ -1609,21 +1632,24 @@ static void destroy_ep_files (struct dev
/* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
+ spin_unlock_irq (&dev->lock);
+
dentry = ep->dentry;
ep->dentry = NULL;
parent = dentry->d_parent->d_inode;
/* break link to controller */
+ mutex_lock(&ep->lock);
if (ep->state == STATE_EP_ENABLED)
(void) usb_ep_disable (ep->ep);
ep->state = STATE_EP_UNBOUND;
usb_ep_free_request (ep->ep, ep->req);
ep->ep = NULL;
+ mutex_unlock(&ep->lock);
+
wake_up (&ep->wait);
put_ep (ep);
- spin_unlock_irq (&dev->lock);
-
/* break link to dcache */
mutex_lock (&parent->i_mutex);
d_delete (dentry);
@@ -1694,6 +1720,11 @@ gadgetfs_unbind (struct usb_gadget *gadg
spin_lock_irq (&dev->lock);
dev->state = STATE_DEV_UNBOUND;
+ while (dev->udc_usage > 0) {
+ spin_unlock_irq(&dev->lock);
+ usleep_range(1000, 2000);
+ spin_lock_irq(&dev->lock);
+ }
spin_unlock_irq (&dev->lock);
destroy_ep_files (dev);
next prev parent reply other threads:[~2017-10-10 19:51 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-10 19:50 [PATCH 3.18 00/32] 3.18.75-stable review Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 01/32] usb: gadget: inode.c: fix unbalanced spin_lock in ep0_write Greg Kroah-Hartman
2017-10-10 19:50 ` Greg Kroah-Hartman [this message]
2017-10-10 19:50 ` [PATCH 3.18 03/32] USB: gadgetfs: fix copy_to_user while holding spinlock Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 04/32] usb-storage: unusual_devs entry to fix write-access regression for Seagate external drives Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 05/32] usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 06/32] usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 07/32] ALSA: usb-audio: Check out-of-bounds access by corrupted buffer descriptor Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 08/32] usb: pci-quirks.c: Corrected timeout values used in handshake Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 09/32] USB: dummy-hcd: fix connection failures (wrong speed) Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 10/32] USB: dummy-hcd: fix infinite-loop resubmission bug Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 11/32] USB: devio: Dont corrupt user memory Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 12/32] USB: uas: fix bug in handling of alternate settings Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 13/32] usb: Increase quirk delay for USB devices Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 14/32] USB: fix out-of-bounds in usb_set_configuration Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 15/32] xhci: fix finding correct bus_state structure for USB 3.1 hosts Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 16/32] iio: ad_sigma_delta: Implement a dedicated reset function Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 17/32] staging: iio: ad7192: Fix - use the dedicated reset function avoiding dma from stack Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 18/32] iio: core: Return error for failed read_reg Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 19/32] iio: ad7793: Fix the serial interface reset Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 20/32] iio: adc: mcp320x: Fix oops on module unload Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 21/32] uwb: properly check kthread_run return value Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 22/32] uwb: ensure that endpoint is interrupt Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 23/32] lsm: fix smack_inode_removexattr and xattr_getsecurity memleak Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 24/32] ALSA: usx2y: Suppress kernel warning at page allocation failures Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 25/32] driver core: platform: Dont read past the end of "driver_override" buffer Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 26/32] HID: i2c-hid: allocate hid buffers for real worst case Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 28/32] ext4: only call ext4_truncate when size <= isize Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 29/32] fs/super.c: fix race between freeze_super() and thaw_super() Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 30/32] ext4: fix data corruption for mmap writes Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 31/32] ext4: Dont clear SGID when inheriting ACLs Greg Kroah-Hartman
2017-10-10 19:50 ` [PATCH 3.18 32/32] ext4: validate s_first_meta_bg at mount time Greg Kroah-Hartman
2017-10-11 0:20 ` [PATCH 3.18 00/32] 3.18.75-stable review Shuah Khan
2017-10-11 13:11 ` Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171010184827.098765335@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=andreyknvl@google.com \
--cc=felipe.balbi@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).