usb: serialize transfers against close to fix use-after-free - #89
Conversation
|
Thanks for digging into this. I don't like that the release ends up waiting on a transfer though, and moving that wait into a coroutine means it now happens after |
|
@amaanq I believe that the correct fix for this issue would be something like Please test it and feel free to adjust it. |
|
Thanks for the quick reply. I've played with your patch a bit, and it doesn't actually fix the UAF, but rather it just shifts the crash site, that being a segv in The reason your version still crashes is that // frameworks/base/core/jni/android_hardware_UsbDeviceConnection.cpp
struct usb_device* device = get_device_from_object(env, thiz);
if (!device) {
ALOGE("device is closed in native_request_wait");
return NULL;
}
// ...
request = usb_request_wait(device, timeout);And close() frees before it nulls the field: struct usb_device* device = get_device_from_object(env, thiz);
if (device) {
usb_device_close(device);
env->SetLongField(thiz, field_context, 0);
}Meaning, any thread that already got past the null check is holding a pointer that gets freed under it. I do agree not deferring Please take a look and let me know your thoughts |
|
Have you tried just adding a cancel before the close() in the block? |
|
Yeah I tried that, it still crashes at Tombstone |
|
Sorry. I meant |
I just tried this as well, and it still crashes unfortunately. |
Closing a transport mid-transfer frees the native `usb_device` while the transfer is still using it, and neither `bulkTransfer` nor `requestWait` checks that the connection is still open once it has read the pointer. I hit this on my phone with MTE enabled, where I ran into a SIGSEGV as soon as the freed struct was read. Each transfer now runs under a lock, and `close()` cancels the in-flight one before waiting on that same lock, so everything is released by the time `close()` returns. Co-authored-by: mimi89999 <michel@lebihan.pl>
Closing a transport mid-transfer frees the native
usb_devicewhile thetransfer is still using it, and neither
bulkTransfernorrequestWaitchecksthat the connection is still open once it has read the pointer. I hit this on my
phone with MTE enabled, where I ran into a SIGSEGV as soon as the freed struct
was read.
sendRawnow holds a lock across the whole exchange, andclose()cancels thein-flight transfer before waiting on that same lock, so everything is released by
the time
close()returns.I've been running this patch on my phone now and have not run into any more MTE issues. Please note that I did use an LLM to help me diagnose this and propose a fix, but I've reviewed the code myself & tested it locally with a reproducer that trigger the UAF reliably, and this patch no longer triggers it.
Full tombstone
Thanks