Ship script gates wave 4 behind AXP_DEBLOB_WAVE4, documents secrets cert path, and adds deblob appliers plus tests; docs capture Swissquote fix and parity. Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
2.6 KiB
Diff
96 lines
2.6 KiB
Diff
From: Alan Stern <stern@rowland.harvard.edu>
|
|
Subject: [PATCH] USB: gadget: fix udc_lock scope around usb_udc_uevent
|
|
|
|
CVE-2022-49980 (2191c00855b0) takes udc_lock inside usb_udc_uevent().
|
|
On msm-4.14 that callback still runs synchronously from device_add()
|
|
and kobject_uevent() while the same thread already holds udc_lock, so
|
|
the mutex deadlocks and the phone hangs on the Google logo.
|
|
|
|
Linux 6.1 usb_add_gadget() / gadget_bind_driver() only hold udc_lock
|
|
around the list and the driver pointer. This keeps the 4.14 call
|
|
shape and moves those uevents outside the lock, then applies the
|
|
UAF fix. Do not apply 2191c00855b0 without this.
|
|
|
|
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
|
---
|
|
|
|
--- a/drivers/usb/gadget/udc/core.c
|
|
+++ b/drivers/usb/gadget/udc/core.c
|
|
@@ -1229,11 +1229,18 @@
|
|
|
|
mutex_lock(&udc_lock);
|
|
list_add_tail(&udc->list, &udc_list);
|
|
+ mutex_unlock(&udc_lock);
|
|
|
|
+ /*
|
|
+ * device_add() emits a uevent that calls usb_udc_uevent(), which
|
|
+ * takes udc_lock. Same for device_del() on the error path. v6.1
|
|
+ * usb_add_gadget() only holds the mutex around the list update.
|
|
+ */
|
|
ret = device_add(&udc->dev);
|
|
if (ret)
|
|
goto err_unlist_udc;
|
|
|
|
+ mutex_lock(&udc_lock);
|
|
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
|
|
udc->vbus = true;
|
|
|
|
@@ -1247,9 +1254,11 @@
|
|
return 0;
|
|
|
|
err_del_udc:
|
|
+ mutex_unlock(&udc_lock);
|
|
device_del(&udc->dev);
|
|
|
|
err_unlist_udc:
|
|
+ mutex_lock(&udc_lock);
|
|
list_del(&udc->list);
|
|
mutex_unlock(&udc_lock);
|
|
|
|
@@ -1313,7 +1322,14 @@
|
|
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
|
|
udc->driver->function);
|
|
|
|
+ /*
|
|
+ * Caller holds udc_lock. usb_udc_uevent() takes it too, so the
|
|
+ * CHANGE uevent has to run outside the lock. Driver is still bound;
|
|
+ * the callback re-locks to read it.
|
|
+ */
|
|
+ mutex_unlock(&udc_lock);
|
|
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
|
+ mutex_lock(&udc_lock);
|
|
|
|
usb_gadget_disconnect(udc->gadget);
|
|
udc->driver->disconnect(udc->gadget);
|
|
@@ -1383,7 +1399,10 @@
|
|
}
|
|
usb_udc_connect_control(udc);
|
|
|
|
+ /* Same deadlock as remove: uevent re-enters udc_lock. */
|
|
+ mutex_unlock(&udc_lock);
|
|
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
|
+ mutex_lock(&udc_lock);
|
|
return 0;
|
|
err1:
|
|
if (ret != -EISNAM)
|
|
@@ -1611,13 +1630,14 @@
|
|
return ret;
|
|
}
|
|
|
|
- if (udc->driver) {
|
|
+ mutex_lock(&udc_lock);
|
|
+ if (udc->driver)
|
|
ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
|
|
udc->driver->function);
|
|
- if (ret) {
|
|
- dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
|
- return ret;
|
|
- }
|
|
+ mutex_unlock(&udc_lock);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
|
+ return ret;
|
|
}
|
|
|
|
return 0;
|