diff options
author | Oliver Neukum <oneukum@suse.de> | 2014-03-26 17:32:51 +0400 |
---|---|---|
committer | Jiri Slaby <jslaby@suse.cz> | 2014-04-18 13:07:13 +0400 |
commit | 0631987d442761501dc65c8ecb9a1267e0b2050d (patch) | |
tree | de2502b77c33892cc8edc2550a95b5bb98e11476 /include/linux/usb/usbnet.h | |
parent | 3552f3fcb4da06e0129eb4a66c31ad410ecbb9e4 (diff) | |
download | linux-0631987d442761501dc65c8ecb9a1267e0b2050d.tar.xz |
usbnet: include wait queue head in device structure
[ Upstream commit 14a0d635d18d0fb552dcc979d6d25106e6541f2e ]
This fixes a race which happens by freeing an object on the stack.
Quoting Julius:
> The issue is
> that it calls usbnet_terminate_urbs() before that, which temporarily
> installs a waitqueue in dev->wait in order to be able to wait on the
> tasklet to run and finish up some queues. The waiting itself looks
> okay, but the access to 'dev->wait' is totally unprotected and can
> race arbitrarily. I think in this case usbnet_bh() managed to succeed
> it's dev->wait check just before usbnet_terminate_urbs() sets it back
> to NULL. The latter then finishes and the waitqueue_t structure on its
> stack gets overwritten by other functions halfway through the
> wake_up() call in usbnet_bh().
The fix is to just not allocate the data structure on the stack.
As dev->wait is abused as a flag it also takes a runtime PM change
to fix this bug.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Reported-by: Grant Grundler <grundler@google.com>
Tested-by: Grant Grundler <grundler@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Diffstat (limited to 'include/linux/usb/usbnet.h')
-rw-r--r-- | include/linux/usb/usbnet.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index e303eef94dd5..0662e98fef72 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -30,7 +30,7 @@ struct usbnet { struct driver_info *driver_info; const char *driver_name; void *driver_priv; - wait_queue_head_t *wait; + wait_queue_head_t wait; struct mutex phy_mutex; unsigned char suspend_count; unsigned char pkt_cnt, pkt_err; |