Re: [BUG] usb: gadgetfs: KASAN null-ptr-deref and intermittent UAF in ep_aio_cancel()

From: Minseo Kim

Date: Wed Sep 16 2026 - 10:15:52 EST


Hi Alan,

> Hmmm. Do you know where the unmount operation was getting stuck? Was
> it the usb_gadget_unregister_driver() call inside dev_release()? I just
> want to be sure about this.

In these reruns, I found that the unmount task was blocked in
synchronize_rcu_expedited(), called from namespace_unlock(), rather than
in usb_gadget_unregister_driver().

I reran the PWRITE callback tail test with both patches applied, using a
resident helper whose main thread invoked umount2() directly. A monitor
thread in the helper captured the blocked main thread's kernel stack. In
three runs from fresh boots, the relevant frames were:

synchronize_rcu_expedited
namespace_unlock
path_umount
__x64_sys_umount

In each of those three runs, the same umount2() call returned
successfully after I released the callback gate.

USB gadget request completion callbacks run with interrupts disabled, and
interrupt-disabled regions act as implicit RCU read-side critical
sections. The observed wait is therefore consistent with the diagnostic
gate delaying completion of the expedited grace period.

I also added diagnostic markers around dev_release() and
usb_gadget_unregister_driver(). The test harness signaled the resident
helper only after the reproducer had closed ep0. In five clean runs from
fresh boots with these markers, both usb_gadget_unregister_driver() and
dev_release() had returned before the resident helper invoked umount2(),
while ep_aio_complete() was still held immediately after
iocb->ki_complete().

The diagnostic gate used a bounded loop that did not sleep in the
dummy_hcd completion context. In three control runs with that gate
disabled, umount2() returned successfully without the prolonged wait seen
in the gated runs. The blocked task's stack identifies the wait point,
while the markers show that both usb_gadget_unregister_driver() and
dev_release() had already returned.

Thank you for asking me to verify this.

With sincere appreciation and great respect,
Minseo Kim

2026년 9월 15일 (화) 오전 1:01, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>님이 작성:
>
> On Mon, Sep 14, 2026 at 11:00:00PM +0900, Minseo Kim wrote:
> > Hi Alan,
> >
> > Thank you for the revised patch.
> >
> > Following your explanation, I focused this round of testing on how the
> > revised patch handles module lifetime.
> >
> > I applied your first patch followed by this revised second patch to
> > upstream v7.2-rc1, commit
> > dc59e4fea9d83f03bad6bddf3fa2e52491777482, using
> > CONFIG_USB_GADGETFS=m for the runtime tests.
>
> ...
>
> > I also held ep_aio_complete() immediately after iocb->ki_complete() on
> > the PWRITE path that does not queue copy_work. In two runs, each starting
> > from a fresh boot, after the reproducer consumed the AIO completion event
> > and closed all GadgetFS descriptors, unmount remained pending, at least
> > one concurrent delete_module() attempt failed with errno set to
> > EWOULDBLOCK, and gadgetfs_cleanup() did not begin while the callback tail
> > was held. After I released the gate, the callback returned, unmount
> > completed, and module removal succeeded.
>
> Hmmm. Do you know where the unmount operation was getting stuck? Was
> it the usb_gadget_unregister_driver() call inside dev_release()? I just
> want to be sure about this.
>
> > In another cancellation test, both unlink_work and copy_work were
> > outstanding on gadgetfs_wq when rmmod entered destroy_workqueue().
> > Releasing unlink_work alone did not allow cleanup to return; it returned
> > only after I released copy_work.
> >
> > Using the GadgetFS source with both patches applied and without the
> > diagnostic gates or markers, I reran the original NULL pointer dereference
> > and UAF reproducers and the relevant AIO cancellation, payload, teardown,
> > CPU hotplug, rebind, module reload, and partial read stress tests. All
> > completed with the expected results and without a KASAN report, Oops, or
> > LOCKDEP warning.
> >
> > In these x86-64 QEMU and dummy_hcd tests, module cleanup did not begin while
> > a callback still had work to publish, and destroy_workqueue() waited for the
> > remaining GadgetFS AIO work once module cleanup began. I did not find a new
> > failure attributable to the revised second patch in these tests.
>
> That all sounds very good.
>
> > Thank you for examining this issue with such care and for the time and
> > effort you have devoted to it.
>
> And the same to you.
>
> Alan Stern