[PATCH v4 01/12] usb: usbip: introduce usbip_event_mutex for serialization
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Date: 2021-03-04 15:27:32
Subsystem:
the rest, usb over ip driver, usb subsystem · Maintainers:
Linus Torvalds, Valentina Manea, Shuah Khan, Greg Kroah-Hartman
syzbot is reporting a NULL pointer dereference [1] because usbip modules
do not use serialization when attaching/detaching. As a preparation for
serializing attach/detach operations, introduce a global mutex, export
it via usbip_event_lock_killable()/usbip_event_unlock(), and use it in
event_handler().
We don't need to use per a device mutex because event_handler() is
processed by a singlethreaded workqueue and ud->tcp_{tx,rx} must not
wait for event_handler() to flush.
[1] https://syzkaller.appspot.com/bug?extid=95ce4b142579611ef0a9
Reported-by: syzbot <redacted>
Tested-by: syzbot <redacted>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
drivers/usb/usbip/usbip_common.h | 2 ++
drivers/usb/usbip/usbip_event.c | 15 +++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index a7dd6c66aee5..f8e16c75b154 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h@@ -327,6 +327,8 @@ void usbip_stop_eh(struct usbip_device *ud); void usbip_event_add(struct usbip_device *ud, unsigned long event); int usbip_event_happened(struct usbip_device *ud); int usbip_in_eh(struct task_struct *task); +int usbip_event_lock_killable(void); +void usbip_event_unlock(void); static inline int interface_to_busnum(struct usb_interface *interface) {
diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c
index 5d88917c9631..e05b858f346d 100644
--- a/drivers/usb/usbip/usbip_event.c
+++ b/drivers/usb/usbip/usbip_event.c@@ -58,6 +58,19 @@ static struct usbip_device *get_event(void) } static struct task_struct *worker_context; +static DEFINE_MUTEX(usbip_event_mutex); + +int usbip_event_lock_killable(void) +{ + return mutex_lock_killable(&usbip_event_mutex); +} +EXPORT_SYMBOL_GPL(usbip_event_lock_killable); + +void usbip_event_unlock(void) +{ + mutex_unlock(&usbip_event_mutex); +} +EXPORT_SYMBOL_GPL(usbip_event_unlock); static void event_handler(struct work_struct *work) {
@@ -68,6 +81,7 @@ static void event_handler(struct work_struct *work) } while ((ud = get_event()) != NULL) { + mutex_lock(&usbip_event_mutex); usbip_dbg_eh("pending event %lx\n", ud->event); /*
@@ -91,6 +105,7 @@ static void event_handler(struct work_struct *work) unset_event(ud, USBIP_EH_UNUSABLE); } + mutex_unlock(&usbip_event_mutex); wake_up(&ud->eh_waitq); } }
--
2.18.4