CVE-2026-89732 Overview
CVE-2026-89732 is a kernel deadlock vulnerability in the Linux usb: gadget: f_fs (FunctionFS) subsystem. The flaw resides in the ffs_ep0_read() function, which incorrectly holds ffs->mutex while sleeping in a wait queue. When a userspace daemon polls the ep0 endpoint via read() and the gadget is asynchronously torn down through configfs, the kernel enters an unrecoverable deadlock. The configfs teardown thread blocks uninterruptibly waiting for the mutex, while the userspace daemon sleeps interruptibly holding it. This results in a local denial-of-service condition affecting systems that use USB gadget FunctionFS with dynamic UDC binding.
Critical Impact
A local userspace process interacting with a USB gadget ep0 endpoint can trigger a kernel deadlock during asynchronous gadget teardown, freezing kernel threads and preventing further USB gadget operations.
Affected Products
- Linux kernel builds shipping the usb: gadget: f_fs (FunctionFS) driver prior to the fix commits
- Stable kernel branches referenced by patch commits 30430509, 34e88f53, 569dd7e5, b0a6bfac, bafddd0f, eac233e6, fbe3db4b, and fd20cc68
- Distributions and embedded systems using FunctionFS with configfs-managed UDC binding
Discovery Timeline
- 2026-09-11 - CVE-2026-89732 published to NVD
- 2026-09-14 - Last updated in NVD database
Technical Details for CVE-2026-89732
Vulnerability Analysis
The vulnerability is a race-induced deadlock [Deadlock] in the FunctionFS USB gadget driver. The ffs_ep0_read() function acquires ffs->mutex and, when no setup events are pending, calls wait_event_interruptible_exclusive_locked_irq() to sleep. That wait macro drops the waitqueue spinlock before sleeping but does not release the outer mutex. Any concurrent code path that needs ffs->mutex to make progress will therefore stall indefinitely.
The deadlock manifests during asynchronous gadget teardown via configfs, for example when an administrator writes an empty string to the UDC attribute. The teardown path calls functionfs_unbind(), which queues a FUNCTIONFS_UNBIND event. The userspace daemon wakes, consumes the event, and drops the mutex. If the daemon immediately loops into another read() before the unbind completes, it reacquires the mutex and sleeps again. functionfs_unbind() then tries to acquire the same mutex to tear down ep0req and blocks in uninterruptible sleep, while the daemon holds the mutex waiting for events that will never arrive.
Root Cause
The root cause is improper lock ordering during a blocking wait. ffs_ep0_read() sleeps while still holding ffs->mutex, coupling the userspace polling lifecycle to the gadget teardown path. Because the teardown thread requires the same mutex, there is no forward-progress guarantee once the daemon re-enters the wait after consuming the unbind event.
Attack Vector
Exploitation requires local access with permission to open the FunctionFS ep0 character device and the ability to trigger a gadget teardown through configfs. A local user or malicious daemon that races read() calls against a UDC unbind can freeze kernel threads that hold or wait for ffs->mutex, producing a denial-of-service condition. No remote attack vector or memory corruption primitive is described in the advisory. The fix drops both the waitqueue spinlock and ffs->mutex before sleeping, uses wait_event_interruptible_exclusive(), and jumps back to the retry label to reacquire the mutex and re-evaluate state.
Detection Methods for CVE-2026-89732
Indicators of Compromise
- Kernel task hangs in functionfs_unbind reported by the hung-task watchdog, with stack traces referencing mutex_lock and ffs_ep0_read.
- Persistent D state (uninterruptible sleep) processes associated with USB gadget configfs writes such as echo "" > UDC.
- Userspace gadget daemons blocked in ep0read() calls that never return after a UDC teardown attempt.
Detection Strategies
- Monitor dmesg for INFO: task ... blocked for more than N seconds messages that reference FunctionFS symbols.
- Audit kernel versions across Linux hosts and embedded devices against the fix commits listed in the kernel.org stable tree.
- Correlate configfs write events on /sys/kernel/config/usb_gadget/*/UDC with subsequent kernel soft-lockup or hung-task alerts.
Monitoring Recommendations
- Enable CONFIG_DETECT_HUNG_TASK and forward hung-task warnings to centralized logging for kernel telemetry review.
- Track process states and stack traces of daemons interacting with /dev/ffs-* endpoints to identify anomalous blocking.
- Alert on repeated FunctionFS bind and unbind cycles that could indicate fuzzing or exploitation attempts against the gadget subsystem.
How to Mitigate CVE-2026-89732
Immediate Actions Required
- Apply the upstream stable kernel patches that drop ffs->mutex before sleeping in ffs_ep0_read() and switch to wait_event_interruptible_exclusive().
- Rebuild and redeploy custom kernels for embedded and Android-based devices that use FunctionFS with configfs UDC management.
- Restrict access to FunctionFS device nodes and configfs UDC attributes to trusted system components only.
Patch Information
The fix is distributed across multiple stable kernel commits, including Kernel Git Commit 30430509, Kernel Git Commit 34e88f5, Kernel Git Commit 569dd7e, Kernel Git Commit b0a6bfa, Kernel Git Commit bafddd0, Kernel Git Commit eac233e, Kernel Git Commit fbe3db4, and Kernel Git Commit fd20cc6. Consult your distribution's security tracker for backported package versions.
Workarounds
- Avoid asynchronous teardown of USB gadgets while userspace daemons are actively polling ep0; stop the daemon before writing to the UDC attribute.
- Disable or unload the usb_f_fs module on systems that do not require FunctionFS functionality.
- Constrain file permissions on /dev/ffs-* and /sys/kernel/config/usb_gadget/ to prevent unprivileged users from triggering the race.
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.