In the Linux kernel, the following vulnerability has been resolved: usb: gadget: f_fs: serialize DMABUF cancel against request completion… (CVE-2026-63894)
In the Linux kernel, the following vulnerability has been resolved: usb: gadget: f_fs: serialize DMABUF cancel against request completion ffs_epfile_dmabuf_io_complete() calls usb_ep_free_request() on the completed request but leaves priv->req, the back-pointer that ffs_dmabuf_transfer() set on submission, pointing at the freed memory. A later FUNCTIONFS_DMABUF_DETACH ioctl or ffs_epfile_release() on the close path still sees priv->req non-NULL under ffs->eps_lock: if (priv->ep && priv->req) usb_ep_dequeue(priv->ep, priv->req); so usb_ep_dequeue() is called on a freed usb_request. On dummy_hcd the dequeue path only walks a live queue and pointer-compares, so the freed pointer reads without faulting and KASAN requires an explicit check at the FunctionFS call site to surface the use-after-free. On SG-capable in-tree UDCs the dequeue path dereferences the supplied request immediately: * chipidea's ep_dequeue() does container_of(req, struct ci_hw_req, req) and reads hwreq->req.status before acquiring its own lock. * cdnsp's cdnsp_gadget_ep_dequeue() reads request->status first. The narrower option of clearing priv->req via cmpxchg() in the completion does not close the race: the completion runs without eps_lock, so a cancel path holding eps_lock can still observe priv->req non-NULL, race a concurrent completion that clears and frees, and pass the freed pointer to usb_ep_dequeue(). A slightly longer fix that moves the free into the cleanup work is needed. Same class of lifetime race as the recent usbip-vudc timer fix [1]. Take eps_lock in the sole place that mutates priv->req from the callback direction by moving usb_ep_free_request() out of the completion into ffs_dmabuf_cleanup(), the existing work handler scheduled by ffs_dmabuf_signal_done() on ffs->io_completion_wq. Clear priv->req there under eps_lock before freeing, and only clear if priv->req still names our request (a subsequent ffs_dmabuf_transfer() on the same attachment may have queued a new one). This keeps the existing dummy_hcd sync-dequeue invariant: the completion callback is still invoked by the UDC without eps_lock held (dummy_hcd drops its own lock before calling the callback), and the callback now takes no f_fs lock at all. Serialization against the cancel path happens in cleanup, which runs from the workqueue with no f_fs lock held on entry. The priv ref count protects the containing ffs_dmabuf_priv: ffs_dmabuf_transfer() takes a ref via ffs_dmabuf_get(), cleanup drops it via ffs_dmabuf_put(), so priv stays live for the cleanup even after the cancel path's list_del + ffs_dmabuf_put. The ffs_dmabuf_transfer() error path no longer frees usb_req inline: fence->req and fence->ep are set before usb_ep_queue(), so ffs_dmabuf_cleanup() (scheduled by the error-path ffs_dmabuf_signal_done()) owns the free regardless of whether the queue succeeded. Reproduced under KASAN on both detach and close paths against dummy_hcd with an observability hook (kasan_check_byte(priv->req) immediately before usb_ep_dequeue) at the two FunctionFS cancel sites to surface the stale-pointer access; the hook is not part of this patch. The KASAN allocator / free stacks in the captured splats identify the same request: alloc in dummy_alloc_request, free in dummy_timer, fault reached from ffs_epfile_release (close) and from the FUNCTIONFS_DMABUF_DETACH ioctl (detach). With the patch applied, both paths are silent under the same hook. The bug is reached from the FunctionFS device node, which in real deployments is owned by the privileged gadget daemon (adbd, UMS, composite gadget services, etc.); it is not reachable from unprivileged userspace or from a USB host on the cable. FunctionFS mounts default to GLOBAL_ROOT_UID, but the filesystem supports uid=, gid=, and fmode= delegation to a non-root gadget daemon, so on real deployments the attacker may be a less-privileged service rather than root.
AI Analysis
Technical Summary
The vulnerability in the Linux kernel's usb gadget FunctionFS (f_fs) subsystem involves a use-after-free condition where ffs_epfile_dmabuf_io_complete() frees a usb_request but leaves a back-pointer (priv->req) referencing the freed memory. Subsequent ioctl or close operations may call usb_ep_dequeue() on this freed request, causing a race condition. Different USB device controllers (UDCs) handle this differently, with some dereferencing the freed pointer immediately, leading to potential faults. The race is due to incomplete serialization between the completion callback and cancel paths, as the completion runs without holding the eps_lock. The patch moves the free operation into a cleanup work handler that takes the eps_lock, clears priv->req safely, and ensures serialization. The vulnerability is exploitable only by privileged gadget daemons via the FunctionFS device node, which is typically restricted to root or delegated privileged services. The patch prevents use-after-free faults and stabilizes the request lifecycle management.
Potential Impact
The vulnerability can cause use-after-free conditions in the USB gadget FunctionFS subsystem, potentially leading to kernel faults or crashes when usb_ep_dequeue() is called on freed memory. This can affect system stability and reliability. The attack surface is limited to privileged gadget daemons accessing the FunctionFS device node; unprivileged users and USB hosts cannot exploit this. There is no indication of remote exploitation or privilege escalation beyond the existing privilege of the gadget daemon.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. The vulnerability was resolved by moving the freeing of usb_request objects into a serialized cleanup work handler that properly synchronizes access. Users should monitor official Linux kernel advisories and apply the relevant kernel updates when available. Since the vulnerability is only reachable by privileged gadget daemons, restricting access to the FunctionFS device node and limiting gadget daemon privileges can reduce risk until patches are applied.
In the Linux kernel, the following vulnerability has been resolved: usb: gadget: f_fs: serialize DMABUF cancel against request completion… (CVE-2026-63894)
Description
In the Linux kernel, the following vulnerability has been resolved: usb: gadget: f_fs: serialize DMABUF cancel against request completion ffs_epfile_dmabuf_io_complete() calls usb_ep_free_request() on the completed request but leaves priv->req, the back-pointer that ffs_dmabuf_transfer() set on submission, pointing at the freed memory. A later FUNCTIONFS_DMABUF_DETACH ioctl or ffs_epfile_release() on the close path still sees priv->req non-NULL under ffs->eps_lock: if (priv->ep && priv->req) usb_ep_dequeue(priv->ep, priv->req); so usb_ep_dequeue() is called on a freed usb_request. On dummy_hcd the dequeue path only walks a live queue and pointer-compares, so the freed pointer reads without faulting and KASAN requires an explicit check at the FunctionFS call site to surface the use-after-free. On SG-capable in-tree UDCs the dequeue path dereferences the supplied request immediately: * chipidea's ep_dequeue() does container_of(req, struct ci_hw_req, req) and reads hwreq->req.status before acquiring its own lock. * cdnsp's cdnsp_gadget_ep_dequeue() reads request->status first. The narrower option of clearing priv->req via cmpxchg() in the completion does not close the race: the completion runs without eps_lock, so a cancel path holding eps_lock can still observe priv->req non-NULL, race a concurrent completion that clears and frees, and pass the freed pointer to usb_ep_dequeue(). A slightly longer fix that moves the free into the cleanup work is needed. Same class of lifetime race as the recent usbip-vudc timer fix [1]. Take eps_lock in the sole place that mutates priv->req from the callback direction by moving usb_ep_free_request() out of the completion into ffs_dmabuf_cleanup(), the existing work handler scheduled by ffs_dmabuf_signal_done() on ffs->io_completion_wq. Clear priv->req there under eps_lock before freeing, and only clear if priv->req still names our request (a subsequent ffs_dmabuf_transfer() on the same attachment may have queued a new one). This keeps the existing dummy_hcd sync-dequeue invariant: the completion callback is still invoked by the UDC without eps_lock held (dummy_hcd drops its own lock before calling the callback), and the callback now takes no f_fs lock at all. Serialization against the cancel path happens in cleanup, which runs from the workqueue with no f_fs lock held on entry. The priv ref count protects the containing ffs_dmabuf_priv: ffs_dmabuf_transfer() takes a ref via ffs_dmabuf_get(), cleanup drops it via ffs_dmabuf_put(), so priv stays live for the cleanup even after the cancel path's list_del + ffs_dmabuf_put. The ffs_dmabuf_transfer() error path no longer frees usb_req inline: fence->req and fence->ep are set before usb_ep_queue(), so ffs_dmabuf_cleanup() (scheduled by the error-path ffs_dmabuf_signal_done()) owns the free regardless of whether the queue succeeded. Reproduced under KASAN on both detach and close paths against dummy_hcd with an observability hook (kasan_check_byte(priv->req) immediately before usb_ep_dequeue) at the two FunctionFS cancel sites to surface the stale-pointer access; the hook is not part of this patch. The KASAN allocator / free stacks in the captured splats identify the same request: alloc in dummy_alloc_request, free in dummy_timer, fault reached from ffs_epfile_release (close) and from the FUNCTIONFS_DMABUF_DETACH ioctl (detach). With the patch applied, both paths are silent under the same hook. The bug is reached from the FunctionFS device node, which in real deployments is owned by the privileged gadget daemon (adbd, UMS, composite gadget services, etc.); it is not reachable from unprivileged userspace or from a USB host on the cable. FunctionFS mounts default to GLOBAL_ROOT_UID, but the filesystem supports uid=, gid=, and fmode= delegation to a non-root gadget daemon, so on real deployments the attacker may be a less-privileged service rather than root.
CVSS v3.1
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
The vulnerability in the Linux kernel's usb gadget FunctionFS (f_fs) subsystem involves a use-after-free condition where ffs_epfile_dmabuf_io_complete() frees a usb_request but leaves a back-pointer (priv->req) referencing the freed memory. Subsequent ioctl or close operations may call usb_ep_dequeue() on this freed request, causing a race condition. Different USB device controllers (UDCs) handle this differently, with some dereferencing the freed pointer immediately, leading to potential faults. The race is due to incomplete serialization between the completion callback and cancel paths, as the completion runs without holding the eps_lock. The patch moves the free operation into a cleanup work handler that takes the eps_lock, clears priv->req safely, and ensures serialization. The vulnerability is exploitable only by privileged gadget daemons via the FunctionFS device node, which is typically restricted to root or delegated privileged services. The patch prevents use-after-free faults and stabilizes the request lifecycle management.
Potential Impact
The vulnerability can cause use-after-free conditions in the USB gadget FunctionFS subsystem, potentially leading to kernel faults or crashes when usb_ep_dequeue() is called on freed memory. This can affect system stability and reliability. The attack surface is limited to privileged gadget daemons accessing the FunctionFS device node; unprivileged users and USB hosts cannot exploit this. There is no indication of remote exploitation or privilege escalation beyond the existing privilege of the gadget daemon.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. The vulnerability was resolved by moving the freeing of usb_request objects into a serialized cleanup work handler that properly synchronizes access. Users should monitor official Linux kernel advisories and apply the relevant kernel updates when available. Since the vulnerability is only reachable by privileged gadget daemons, restricting access to the FunctionFS device node and limiting gadget daemon privileges can reduce risk until patches are applied.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-xh4m-2r9c-xfr3
- Osv Schema Version
- 1.4.0
- Aliases
- ["CVE-2026-63894"]
- Ecosystems
- []
- Database Specific Severity
- null
- Cvss Version
- null
Threat ID: 6a5d27ab2a4a8d598912fc50
Added to database: 07/19/2026, 19:38:19 UTC
Last enriched: 07/19/2026, 20:10:53 UTC
Last updated: 07/20/2026, 21:52:34 UTC
Views: 12
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.