* [PATCH] usb: gadget: f_fs: check ffs->gadget in the DMABUF detach/find paths
@ 2026-10-20 5:19 Yu Zhang
2026-10-20 8:30 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Yu Zhang @ 2026-10-20 5:19 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, Yu Zhang, stable
ffs_dmabuf_detach() and ffs_dmabuf_find_attachment() dereference
ffs->gadget->dev.parent as their very first statement, without checking
that ffs->gadget is non-NULL:
static int ffs_dmabuf_detach(struct file *file, int fd)
{
...
struct device *dev = ffs->gadget->dev.parent;
ffs->gadget is only set between functionfs_bind() and
functionfs_unbind() (UDC bind/unbind). The epfile ioctls, however, are
gated only on ffs->state == FFS_ACTIVE, which userspace reaches by
writing the descriptors and strings and which is independent of the
gadget lifetime: an FFS instance is FFS_ACTIVE before it has ever been
bound to a UDC, and stays FFS_ACTIVE after unbind. So
FUNCTIONFS_DMABUF_DETACH (and the DMABUF transfer path, through
ffs_dmabuf_find_attachment()) can be issued while ffs->gadget is NULL,
dereferencing NULL:
BUG: kernel NULL pointer dereference, address: 00000000000000b0
RIP: 0010:ffs_epfile_ioctl+0x402/0x1700
__x64_sys_ioctl+0x120/0x170
do_syscall_64+0xf9/0x540
Reproduced by mounting functionfs, writing a descriptor+string blob so
the state becomes FFS_ACTIVE without ever binding a UDC, then issuing
FUNCTIONFS_DMABUF_DETACH on an endpoint file.
ffs_dmabuf_attach() already guards this with
"if (!gadget || !gadget->sg_supported) return -EPERM". Do the same in
ffs_dmabuf_detach() and ffs_dmabuf_find_attachment() (the latter also
covers ffs_dmabuf_transfer()): snapshot ffs->gadget, return -EPERM if it
is NULL, and use the snapshot.
Fixes: 7b07a2a7ca02 ("usb: gadget: functionfs: Add DMABUF import interface")
Cc: stable@vger.kernel.org
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
---
drivers/usb/gadget/function/f_fs.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 44218be..0976db7 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1473,9 +1473,15 @@ static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
static struct dma_buf_attachment *
ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf)
{
- struct device *dev = epfile->ffs->gadget->dev.parent;
+ struct usb_gadget *gadget = epfile->ffs->gadget;
struct dma_buf_attachment *attach = NULL;
struct ffs_dmabuf_priv *priv;
+ struct device *dev;
+
+ if (!gadget)
+ return ERR_PTR(-EPERM);
+
+ dev = gadget->dev.parent;
mutex_lock(&epfile->dmabufs_mutex);
@@ -1570,11 +1576,17 @@ static int ffs_dmabuf_detach(struct file *file, int fd)
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_data *ffs = epfile->ffs;
- struct device *dev = ffs->gadget->dev.parent;
+ struct usb_gadget *gadget = ffs->gadget;
struct ffs_dmabuf_priv *priv, *tmp;
struct dma_buf *dmabuf;
+ struct device *dev;
int ret = -EPERM;
+ if (!gadget)
+ return -EPERM;
+
+ dev = gadget->dev.parent;
+
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] usb: gadget: f_fs: check ffs->gadget in the DMABUF detach/find paths
2026-10-20 5:19 [PATCH] usb: gadget: f_fs: check ffs->gadget in the DMABUF detach/find paths Yu Zhang
@ 2026-10-20 8:30 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-10-20 8:30 UTC (permalink / raw)
To: Yu Zhang; +Cc: linux-usb
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] usb: gadget: f_fs: unsynchronized ffs->gadget access in DMABUF paths
--
commit 11858230a366468ebcd956f6817d9428b7b67ebc
Author: Yu Zhang <yuz08559@gmail.com>
usb: gadget: f_fs: check ffs->gadget in the DMABUF detach/find paths
This commit adds NULL checks on ffs->gadget in ffs_dmabuf_find_attachment()
and ffs_dmabuf_detach() to prevent a NULL pointer dereference when endpoint
DMABUF ioctls are issued while the functionfs instance is not bound to a UDC.
> diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
> index c64a268e98a43..52d486ec218a9 100644
> --- a/drivers/usb/gadget/function/f_fs.c
> +++ b/drivers/usb/gadget/function/f_fs.c
> @@ -1507,9 +1507,15 @@ static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
> static struct dma_buf_attachment *
> ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf)
> {
> - struct device *dev = epfile->ffs->gadget->dev.parent;
> + struct usb_gadget *gadget = epfile->ffs->gadget;
> struct dma_buf_attachment *attach = NULL;
> struct ffs_dmabuf_priv *priv;
> + struct device *dev;
> +
> + if (!gadget)
> + return ERR_PTR(-EPERM);
> +
> + dev = gadget->dev.parent;
>
> mutex_lock(&epfile->dmabufs_mutex);
>
> @@ -1604,11 +1610,17 @@ static int ffs_dmabuf_detach(struct file *file, int fd)
> {
> struct ffs_epfile *epfile = file->private_data;
> struct ffs_data *ffs = epfile->ffs;
> - struct device *dev = ffs->gadget->dev.parent;
> + struct usb_gadget *gadget = ffs->gadget;
> struct ffs_dmabuf_priv *priv, *tmp;
> struct dma_buf *dmabuf;
> + struct device *dev;
> int ret = -EPERM;
>
> + if (!gadget)
> + return -EPERM;
> +
> + dev = gadget->dev.parent;
> +
> dmabuf = dma_buf_get(fd);
> if (IS_ERR(dmabuf))
> return PTR_ERR(dmabuf);
[Severity: High]
Can reading ffs->gadget without holding ffs->mutex still race with a
concurrent UDC unbind, and does returning -EPERM in ffs_dmabuf_detach()
prevent userspace from detaching DMABUFs after unbind?
In functionfs_unbind(), ffs->gadget is cleared under ffs->mutex:
drivers/usb/gadget/function/f_fs.c:functionfs_unbind() {
...
mutex_lock(&ffs->mutex);
usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
ffs->ep0req = NULL;
ffs->gadget = NULL;
clear_bit(FFS_FL_BOUND, &ffs->flags);
mutex_unlock(&ffs->mutex);
}
In both ffs_dmabuf_find_attachment() and ffs_dmabuf_detach(), ffs->gadget is
read into a local variable without holding ffs->mutex and without READ_ONCE().
Without a lock or compiler barrier, the compiler may reload ffs->gadget after
the NULL check, or functionfs_unbind() and usb_del_gadget_udc() may complete
and free struct usb_gadget via usb_put_gadget() before gadget->dev.parent is
dereferenced.
Additionally, ffs_func_unbind() does not remove attached DMABUFs from
epfile->dmabufs when the UDC is unbound. Once functionfs_unbind() sets
ffs->gadget to NULL, returning -EPERM when !gadget in ffs_dmabuf_detach()
blocks userspace from detaching previously attached DMABUFs via
FUNCTIONFS_DMABUF_DETACH after receiving FUNCTIONFS_UNBIND (unlike
ffs_epfile_release(), which detaches entries from epfile->dmabufs without
checking ffs->gadget).
Could ffs_dmabuf_detach() match only on priv->attach->dmabuf == dmabuf
without consulting ffs->gadget, and could ffs_dmabuf_find_attachment()
synchronize against functionfs_unbind()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020051925.92294-1-yuz08559@gmail.com?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-20 8:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 5:19 [PATCH] usb: gadget: f_fs: check ffs->gadget in the DMABUF detach/find paths Yu Zhang
2026-10-20 8:30 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.