Re: [PATCH 1/1] usb: gadget: inode: fix use-after-free of struct ep_data
From: Alan Stern <stern@rowland.harvard.edu>
Date: 2026-09-04 19:27:56
On Fri, Sep 04, 2026 at 01:31:29PM -0400, Adriano Córdova wrote:
Hi Alan, Right. But that patch makes the inode the sole lifetime owner of the ep_data (deletes the list call to 'put_ep'), but ep_data is also linked in the list dev->epfiles and that reference can outlive the inode (it doesn't happen now I think, but only incidentally).
Okay, I see.
So in the patch in here I decided to go with a refcount approach, just to be safe.
The patch description could be improved just a little...
El vie, 4 sept 2026 a las 12:50, Alan Stern ([off-list ref]) escribió:quoted
On Fri, Sep 04, 2026 at 12:38:27PM -0400, Adriano Cordova wrote:quoted
gadgetfs_unbind() -> destroy_ep_files() frees each struct ep_data via put_ep(), but the inode still points at that ep_data through ->i_private with no reference of its own. A concurrent openat() on an endpoint file can therefore reach ep_open() and dereference the freed ep_data (the mutex fast path), even while the inode outlives it.
You could mention something about the inode's lifetime and what causes it to be released (and when). This would make it clearer to people like me how a concurrent open() can race with inode destruction. But I agree, you're right that the inode's pointer should be counted in the ep_data's refcount.
quoted
quoted
Give the inode its own reference: take get_ep() when the endpoint inode is created and drop it again from a new gadgetfs_evict_inode(), so an ep_data can never be freed while any inode still points at it. This is also safe against dcache pruning, since the inode reference keeps the count >= 1 until the endpoint is removed from dev->epfiles.
Now it all makes sense. Your patch doesn't handle the case where the gadgetfs_make_inode() call in gadgetfs_create_file() fails. If that happens, the refcount will remain elevated because there is no inode to evict. I'll leave it to you to figure out the best solution. Alan Stern