Re: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()

From: Alan Stern

Date: Fri Jul 31 2026 - 09:37:45 EST


On Fri, Jul 31, 2026 at 02:43:16PM +0530, Deepanshu Kartikey wrote:
> ep_open() dereferenced inode->i_private and locked its embedded
> mutex before checking whether the underlying ep_data was still
> alive. destroy_ep_files(), called from gadgetfs_unbind(), can free
> that same ep_data concurrently, since nothing prevented an in-flight
> open() from racing the teardown. KASAN reports a slab-use-after-free
> in ep_open(), with the object freed by a concurrent gadgetfs_unbind()
> -> destroy_ep_files() -> put_ep() -> kfree().
>
> Fix it by adding an inode back-pointer to ep_data, having
> destroy_ep_files() clear inode->i_private to NULL under dev->lock
> before the object can be freed, and having ep_open() read
> inode->i_private and pin the result with get_ep() under that same
> lock, bailing out with -ENOENT if it finds NULL. This makes liveness
> self-evident at the point of use instead of being inferred from
> device state, so it holds regardless of which path frees the
> endpoint.

This is a brittle solution, because it depends critically on the fact
that there will never be more than one dev_data structure at any time.
Someone may want to change the driver in the future to support multiple
gadgetfs filesystems existing simultaneously, and your code would not
allow that.

The normal approach for fixing this sort of problem is to create a
single global mutex and use it to serialize all open and destroy
operations. Then it would not be possible to open an ep file at a time
when the ep_data structure had been deallocated but the inode's private
data still held a stale pointer to it.

Alan Stern