Re: [PATCH] USB: fix invalid memory access in hub_activate()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2015-12-17 00:02, Alan Stern wrote:
Commit 8520f38099cc ("USB: change hub initialization sleeps to
delayed_work") changed the hub_activate() routine to make part of it
run in a workqueue.  However, the commit failed to take a reference to
the usb_hub structure or to lock the hub interface while doing so.  As
a result, if a hub is plugged in and quickly unplugged before the work
routine can run, the routine will try to access memory that has been
deallocated.  Or, if the hub is unplugged while the routine is
running, the memory may be deallocated while it is in active use.

This patch fixes the problem by taking a reference to the usb_hub at
the start of hub_activate() and releasing it at the end (when the work
is finished), and by locking the hub interface while the work routine
is running.  It also adds a check at the start of the routine to see
if the hub has already been disconnected, in which nothing should be
done.

Could this change result in below mutex lock that I am seeing:
"kworker/3:2" call stack:
{code}
-000|__switch_to(prev = 0xFFFFFFC032EAAA00, next = 0xFFFFFFC075D59C00)
-001|context_switch(inline)
-001|__schedule()
-002|schedule()
-003|schedule_preempt_disabled()
-004|__mutex_lock_common(inline)
-004|__mutex_lock_slowpath(lock_count = 0xFFFFFFC07BE94580)
-005|current_thread_info(inline)
-005|mutex_set_owner(inline)
-005|mutex_lock(
    |    lock = 0xFFFFFFC00255EE90 -> (
    |      count = (counter = -1),
| wait_lock = (rlock = (raw_lock = (owner = 4, next = 4), magic = 3735899821, owner_cpu = 4294967295, owner = 0xFFFFFFFFFFFFFFFF)), | wait_list = (next = 0xFFFFFFC0457DBC78, prev = 0xFFFFFFC0457DBC78),
    |      owner = 0xFFFFFFC075CD5400,
    |      name = 0x0,
    |      magic = 0xFFFFFFC00255EE90))
-006|hub_activate(hub = 0xFFFFFFC00253A680, type = 472914991)
-007|hub_init_func2(?)
-008|static_key_count(inline)
-008|static_key_false(inline)
-008|trace_workqueue_execute_end(inline)
-008|process_one_work(worker = 0xFFFFFFC017C8CA00, work = 0xFFFFFFC00253A848)
-009|worker_thread(__worker = 0xFFFFFFC017C8CA00)



"kworker/u16:0" call stack:
{code}
-000|__switch_to(prev = 0xFFFFFFC075CD5400, next = 0xFFFFFFC024510000)
-001|context_switch(inline)
-001|__schedule()
-002|schedule()
-003|schedule_timeout(timeout = -272798837376)
-004|do_wait_for_common(inline)
-004|__wait_for_common(inline)
-004|wait_for_common(x = 0xFFFFFFC075D3F928, timeout = 9223372036854775807, ?)
-005|wait_for_completion(?)
-006|flush_work( <---------- wq is already blocked for the mutex above
    |    work = 0xFFFFFFC00253A848 -> (
    |      data = (counter = 417),
| entry = (next = 0xFFFFFFC00253A850, prev = 0xFFFFFFC00253A850),
    |      func = 0xFFFFFFC000659B20 -> ))
| barr = (work = (data = (counter = -272799003163), entry = (next = 0xFFFFFFC017C8CA30, prev = 0xFFFFFFC017C8CA30), func =
    |  pool = 0xFFFFFFC0703784C0
    |  pwq = 0xFFFFFFC07BE98C00
    |  linked = 26644480
    |  __key = ()
-007|clear_work_data(inline)
-007|__cancel_work_timer(work = 0xFFFFFFC00253A848, is_dwork = FALSE)
-008|cancel_delayed_work_sync(?)
-009|hub_quiesce(hub = 0xFFFFFFC00253A680, ?)
-010|hub_disconnect(intf = 0xFFFFFFC00255EE00)
-011|usb_unbind_interface(dev = 0xFFFFFFC00255EE30)
-012|__device_release_driver(dev = 0xCB88537FDC8CAE50)
-013|device_unlock(inline)
-013|device_release_driver(dev = 0xFFFFFFC00255EE30)
-014|bus_remove_device(dev = 0xFFFFFFC00255EE30)
-015|device_del(dev = 0xFFFFFFC00255EE30)
-016|usb_disable_device(dev = 0xFFFFFFC032C42600, skip_ep0 = 0)
-017|usb_disconnect(pdev = 0xFFFFFFC075D3FCA0)
-018|usb_remove_hcd(hcd = 0xFFFFFFC0700AE880)



Should we rather have device_trylock instead of device_lock


Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Reported-by: Alexandru Cornea <alexandru.cornea@xxxxxxxxx>
Tested-by: Alexandru Cornea <alexandru.cornea@xxxxxxxxx>
Fixes: 8520f38099cc ("USB: change hub initialization sleeps to delayed_work")
CC: <stable@xxxxxxxxxxxxxxx>


[as1791]


 drivers/usb/core/hub.c |   22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

Index: usb-4.3/drivers/usb/core/hub.c
===================================================================
--- usb-4.3.orig/drivers/usb/core/hub.c
+++ usb-4.3/drivers/usb/core/hub.c
@@ -1031,10 +1031,20 @@ static void hub_activate(struct usb_hub
 	unsigned delay;

 	/* Continue a partial initialization */
-	if (type == HUB_INIT2)
-		goto init2;
-	if (type == HUB_INIT3)
+	if (type == HUB_INIT2 || type == HUB_INIT3) {
+		device_lock(hub->intfdev);

device_trylock?? If failed to acquire then treat that as disconnect?

+
+		/* Was the hub disconnected while we were waiting? */
+		if (hub->disconnected) {
+			device_unlock(hub->intfdev);
+			kref_put(&hub->kref, hub_release);
+			return;
+		}
+		if (type == HUB_INIT2)
+			goto init2;
 		goto init3;
+	}

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux