CVE-2026-89996 Overview
CVE-2026-89996 is a Linux kernel vulnerability in the dma-buf heap subsystem. The DMA_HEAP_IOCTL_ALLOC ioctl publishes a file descriptor via fd_install() before the trailing copy_to_user() call completes. When copy_to_user() fails, userspace never receives the file descriptor number, but the descriptor and the underlying dma-buf reference remain installed in the caller's file descriptor table. The leaked descriptor persists for the lifetime of the process. Userspace can reach this failure path reliably by flipping the target page to PROT_READ between copy_from_user() and copy_to_user() using mprotect(). Each successful trigger leaks one dma-buf file descriptor.
Critical Impact
Local users can leak dma-buf file descriptors and pin kernel memory for the process lifetime by forcing copy_to_user() failures during DMA_HEAP_IOCTL_ALLOC.
Affected Products
- Linux kernel — dma-buf heap subsystem (drivers/dma-buf/dma-heap.c)
- Linux kernel dma-buf core (drivers/dma-buf/dma-buf.c)
- Downstream distributions shipping the affected kernel versions
Discovery Timeline
- 2026-09-16 - CVE-2026-89996 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-89996
Vulnerability Analysis
The vulnerability lives in dma_heap_ioctl_allocate(). The original flow allocates a dma-buf via heap->ops->allocate(), then calls dma_buf_fd(), which internally invokes fd_install() to publish the file descriptor into the caller's file descriptor table. Only after this publication does the ioctl handler run copy_to_user() to hand the descriptor number back to userspace.
Once fd_install() completes, the descriptor is observable by other threads in the same process. Those threads can dup() it, transfer it via SCM_RIGHTS, or close() it and cause its number to be reused. Any recovery attempt from the failing ioctl path could therefore act on an unrelated file. This classifies as a Memory Leak and a Time-of-Check Time-of-Use (TOCTOU) design flaw in the resource publication sequence.
Root Cause
The root cause is ordering. fd_install() executes before copy_to_user(), so a failure in copy_to_user() leaves committed state in the process file descriptor table with no safe rollback. The fix restructures the allocation path so that get_unused_fd_flags() reserves an unpublished descriptor number, copy_to_user() runs next, and a new dma_buf_fd_install() helper performs the final unfailable publication.
Attack Vector
A local attacker with access to /dev/dma_heap/<name> triggers the failure deterministically. The attacker places a struct dma_heap_allocation_data in a page, issues the ioctl, and uses mprotect() from a second thread to flip the page to PROT_READ between copy_from_user() and copy_to_user(). The kernel installs the descriptor, then fails to write back the descriptor number. The descriptor and its dma-buf reference remain pinned. Repeated invocations exhaust the process file descriptor limit and pin kernel memory tied to the allocated buffers. Refer to the upstream fix commit 0d4a5d2 for the corrected ordering.
Detection Methods for CVE-2026-89996
Indicators of Compromise
- Processes holding an increasing count of anonymous dmabuf file descriptors visible under /proc/<pid>/fd/ with no matching userspace tracking.
- Repeated ioctl(DMA_HEAP_IOCTL_ALLOC) calls followed by mprotect() on the argument buffer within the same process.
- Growth in kernel dma-buf accounting reported by /sys/kernel/debug/dma_buf/bufinfo that is not released on process activity.
Detection Strategies
- Audit ioctl calls targeting /dev/dma_heap/* and correlate with concurrent mprotect() activity on the calling thread group.
- Track per-process file descriptor growth against baselines and alert on sustained growth in dmabuf-typed descriptors.
- Use bpftrace or perf probes on dma_heap_ioctl_allocate to record return paths that install a descriptor without a subsequent successful copy_to_user().
Monitoring Recommendations
- Collect kernel version inventory across Linux endpoints and flag hosts running unpatched dma-buf heap code.
- Ingest auditdSYSCALL records for ioctl on dma-heap character devices into a central data lake for hunting.
- Monitor cgroup and per-process kernel memory accounting for anomalous dma-buf residency.
How to Mitigate CVE-2026-89996
Immediate Actions Required
- Apply the upstream Linux kernel fix that introduces dma_buf_fd_install() and reorders the allocation path so fd_install() becomes the last step.
- Restrict access to /dev/dma_heap/* device nodes to trusted user groups using standard Unix permissions.
- Rebuild and redeploy any custom or embedded kernels that carry the affected dma-heap.c code.
Patch Information
The fix ships in the upstream stable tree. Review the following commits and apply the version matching your kernel branch: Kernel Git Commit 0d4a5d2, Kernel Git Commit 30d0aff, and Kernel Git Commit 69d57db. The patch introduces dma_buf_fd_install() in dma-buf.c and refactors dma_heap_ioctl_allocate() to return the struct dma_buf * so the caller holds the reference across copy_to_user() and the final fd_install(). No UAPI or heap-driver interface changes.
Workarounds
- Tighten permissions on /dev/dma_heap/* so only privileged services can issue DMA_HEAP_IOCTL_ALLOC.
- Apply per-process RLIMIT_NOFILE limits to bound the impact of leaked descriptors on multi-tenant hosts.
- Constrain untrusted workloads with seccomp filters that block ioctl on dma-heap file descriptors when not required.
# Configuration example: restrict /dev/dma_heap access to a trusted group
sudo groupadd dmaheap
sudo chgrp dmaheap /dev/dma_heap/*
sudo chmod 0660 /dev/dma_heap/*
# Persist across reboots via udev
cat <<'EOF' | sudo tee /etc/udev/rules.d/60-dma-heap.rules
KERNEL=="system", SUBSYSTEM=="dma_heap", GROUP="dmaheap", MODE="0660"
EOF
sudo udevadm control --reload-rules
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

