A brief window during a DRM handle swap lets a local attacker free an object out from under the kernel and ride it to root
CVE-2026-46215 is a use-after-free in the Linux kernel's Direct Rendering Manager (DRM) GEM subsystem, specifically in the change_handle ioctl path. When a GEM object is moved from one handle to another during a prime swap, the object briefly holds two IDR entries while its handle_count remains at 1. A concurrent DRM_IOCTL_GEM_CLOSE on the old handle drives the count to zero and frees the object, leaving the new handle dangling into freed slab memory. The bug was introduced in v6.18-rc1 and is fixed in 6.18.32, 7.0.9, and 7.1-rc3. Debian Bullseye, Bookworm, and Trixie are explicitly not affected because their kernels predate the vulnerable code. RHEL 8/9 and Ubuntu 22.04/24.04 LTS ship older kernel series and are likewise unaffected.
The vendor CVSS of 7.8 HIGH is mathematically correct — local, low-complexity, low-privilege, full CIA impact — but it significantly overstates the real-world risk. The affected kernel range (6.18+) is deployed almost exclusively on rolling-release desktops (Fedora 42+, Arch, Manjaro) and developer workstations. Enterprise infrastructure — hypervisors, Kubernetes nodes, database servers, CI runners — overwhelmingly runs LTS kernels well below 6.18. The EPSS of 0.0017 (bottom 15th percentile) confirms the market agrees: this is not an actively sought-after target. A public PoC exists and grants root, which prevents further downgrade, but the narrow blast radius justifies treating this as MEDIUM for fleet prioritization.
5 steps from start to impact.
Obtain local shell on host running kernel 6.18–7.0.8
- Local (or SSH) shell access to target host
- Host runs Linux kernel ≥6.18, <6.18.32 or ≥7.0, <7.0.9 or 7.1-rc1/rc2
- Most enterprise hosts run RHEL/Ubuntu LTS/Debian stable with kernels far below 6.18
- Gaining a local shell on a managed host implies the attacker has already bypassed endpoint controls
Access DRM render node (/dev/dri/renderD*)
- DRM kernel modules loaded (e.g., i915, amdgpu, virtio-gpu, vgem)
- Render node device file exists and is accessible to the attacker's user
- Minimal server installs may not load DRM modules at all
- Container runtimes with default seccomp profiles block DRM ioctls
- Hardened hosts may restrict /dev/dri access via udev rules
Race DRM_IOCTL_GEM_CHANGE_HANDLE against DRM_IOCTL_GEM_CLOSE
DRM_IOCTL_GEM_CHANGE_HANDLE and DRM_IOCTL_GEM_CLOSE concurrently on the same GEM handle. When the close wins the race, the object is freed while the new handle still references it. The bluedragonsecurity PoC (adapted for kernel 7.0) demonstrates this reliably within seconds using a tight ioctl loop.- Ability to issue DRM ioctls (open render node fd)
- Sufficient CPU time to win the race (typically <10 seconds on multi-core)
- Race conditions may be less reliable on single-core VMs or under heavy load
- Kernel hardening features (KASAN, SLUB debug) may detect the UAF and panic instead of allowing exploitation
Heap spray via pipe pages to reclaim freed slab
pipe() / splice() to reclaim the freed slab with attacker-controlled data. The dangling handle now points to attacker-controlled memory. The PoC uses this to overwrite credentials or function pointers to escalate to root.- Standard unprivileged syscalls (pipe, splice) available
- Slab allocator layout is predictable for the target kernel build
- CONFIG_SLAB_FREELIST_RANDOM and CONFIG_SLAB_FREELIST_HARDENED reduce spray reliability
- Different distro kernel configs may change slab layout, requiring PoC adaptation
Achieve root shell
su. Full local privilege escalation is achieved.- Successful heap reclaim from step 4
- Exploit is kernel-version-specific; the published PoC targets 7.0.x and may need adaptation for 6.18.x
- SMEP/SMAP/KASLR add complexity but are routinely bypassed in modern kernel exploits
/etc/udev/rules.d/99-restrict-renderD.rules) setting SUBSYSTEM=="drm", KERNEL=="renderD*", MODE="0660", GROUP="render" and ensure only GPU-workload users are in the render group. This breaks step 2 of the attack path by denying the attacker the file descriptor needed to issue DRM ioctls. No mitigation SLA applies at MEDIUM — go straight to the 365-day remediation window, but this control is low-effort and can be deployed immediately.echo 'blacklist drm' > /etc/modprobe.d/no-drm.conf) and unload them (modprobe -r drm). This eliminates the attack surface entirely on affected servers. Requires a reboot or module unload. Apply within the 365-day remediation window.ioctl calls to DRM device numbers, or do not mount /dev/dri into containers. Default Docker/containerd seccomp profiles already restrict most DRM ioctls; verify your runtime's policy. This prevents container-to-host escalation via this CVE.dnf update or pacman -Syu pulls the fix.- Network firewalls / WAF / IDS — This is a local privilege escalation; there is no network component to filter or inspect.
- SELinux in default targeted policy — Default RHEL/Fedora SELinux policy permits confined users to access DRM render nodes. A custom policy restricting ioctl classes on renderD* would help but is non-trivial to write and test.
- KASLR alone — Kernel address space layout randomization adds entropy to exploit development but is routinely bypassed in modern kernel exploits, including the published PoC. It slows but does not prevent exploitation.
The supporting signals.
| In-the-Wild Exploitation | None observed. Not on CISA KEV. No GreyNoise or Shadowserver sightings. No campaign attribution. |
|---|---|
| Proof of Concept | Public PoC available. bluedragonsecurity/CVE-2026-46215-EXPLOIT (C, Makefile; July 11 2026) by Antonius (ev1lut10n/sw0rdm4n), adapted for kernel 7.0. Also 0xCyberstan/CVE-2026-46215-POC. Races DRM ioctls, pipe-sprays slab, spawns root shell. |
| EPSS | 0.0017 (0.17%) — bottom ~15th percentile. Market consensus: low exploitation probability. |
| CISA KEV | Not listed as of 2026-10-02. |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H → 7.8 HIGH. Local vector, low complexity, low privilege, no user interaction. Scope unchanged limits blast radius to the exploited host. |
| Affected Versions | Introduced in v6.18-rc1. Affected: 6.18.0–6.18.31, 7.0.0–7.0.8, 7.1-rc1/rc2. Debian Bullseye/Bookworm/Trixie explicitly *not affected* (vulnerable code not present). RHEL 8/9, Ubuntu 22.04/24.04 LTS ship older kernel series and are unaffected. |
| Fixed Versions | 6.18.32, 7.0.9, 7.1-rc3. Debian unstable/sid fixed in kernel package 7.0.9-1. Upstream commits: 5e28b7b94408, 61bd96d3e547, 672464dd5323. |
| Scanning / Exposure | Local-only vulnerability — no network exposure surface. Standard vulnerability scanners (Qualys, Nessus, Rapid7) detect via kernel package version. No Shodan/Censys/FOFA relevance (not remotely exploitable). |
| Disclosure Date | 2026-05-28 (linux-cve-announce). Patch commits landed in stable trees the same week. |
| Researcher / Reporter | Reported via linux-cve-announce. PoC authored by Antonius (ev1lut10n/sw0rdm4n) of bluedragonsecurity. |
Sources.
Why this verdict
- Local-only attack vector: Requires an existing shell on the target host, meaning the attacker has already cleared initial access — this is purely a post-compromise escalation primitive, not a remotely exploitable entry point.
- Extremely narrow affected kernel range: Only kernels 6.18.0–6.18.31, 7.0.0–7.0.8, and 7.1-rc1/rc2 are vulnerable. RHEL 8/9 (kernel 4.18/5.14), Ubuntu 22.04 LTS (5.15/6.5), Ubuntu 24.04 LTS (6.8), Debian Bullseye/Bookworm/Trixie (5.10/6.1/6.12) are all explicitly unaffected. In a typical 10,000-host enterprise fleet, estimated <3% of Linux hosts run an affected kernel.
- Public PoC prevents further downgrade: The bluedragonsecurity exploit is functional, well-documented, and grants root. This keeps the rating at MEDIUM rather than LOW — on any host where the conditions are met, exploitation is straightforward.
- EPSS confirms low real-world risk: At 0.0017, the exploit prediction model places this in the bottom ~15th percentile. No KEV listing, no in-the-wild campaigns, no threat-actor tooling integration observed.
- Role multiplier: The Linux kernel is canonically a high-value-role component (hypervisors, k8s nodes, CI runners). However, enterprise high-value Linux hosts overwhelmingly run LTS kernels (RHEL 5.14, Ubuntu 5.15/6.5/6.8, Debian 6.1) that are *far below* the 6.18 introduction point. Estimated <2% of enterprise hypervisors and <1% of production k8s nodes run an affected kernel. This breaks the HIGH floor per the installed-base evidence requirement. On the rare high-value host running 6.18+ (e.g., a Fedora-based dev k8s cluster), the chain would succeed and yield host-level root — but this represents an edge case, not a fleet-wide concern.
Why not higher?
The vendor's 7.8 HIGH accurately reflects the CVSS math for a local LPE with full CIA impact. However, CVSS does not account for installed-base narrowness. The 6.18+ kernel requirement eliminates the vast majority of enterprise Linux deployments — all current RHEL, Ubuntu LTS, Debian stable, and SLES releases ship kernels well below the introduction point. Upgrading to HIGH would overstate urgency for fleets that are simply not running affected code.
Why not lower?
A public, functional PoC exists that reliably escalates to root in seconds. On any host where the kernel version and DRM access conditions are met, exploitation is trivial. The DRM render node is auto-granted on desktop distros, requiring no special privileges beyond a local session. Dropping to LOW would understate the risk for organizations running Fedora, Arch, or custom mainline kernels in any capacity.
Crowdsourced verification payload.
Run this script on each target Linux host as any user. No root privileges required. Usage: bash check_cve_2026_46215.sh. It checks the running kernel version against affected ranges and reports DRM render node availability.
#!/usr/bin/env bash
# CVE-2026-46215 checker - Linux kernel DRM GEM change_handle UAF
# Outputs: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
KVER=$(uname -r)
echo "[*] Running kernel: $KVER"
# Extract major.minor.patch
MAJOR=$(echo "$KVER" | cut -d. -f1)
MINOR=$(echo "$KVER" | cut -d. -f2)
PATCH=$(echo "$KVER" | cut -d. -f3 | grep -oE '^[0-9]+' || echo 0)
# Count DRM render nodes
RENDER_NODES=$(ls /dev/dri/renderD* 2>/dev/null | wc -l || echo 0)
echo "[*] DRM render nodes found: $RENDER_NODES"
vulnerable=0
if [ "$MAJOR" -eq 6 ] && [ "$MINOR" -eq 18 ]; then
if [ "$PATCH" -lt 32 ]; then
vulnerable=1
echo "[!] Kernel 6.18.x detected, patch level $PATCH < 32"
fi
elif [ "$MAJOR" -eq 7 ] && [ "$MINOR" -eq 0 ]; then
if [ "$PATCH" -lt 9 ]; then
vulnerable=1
echo "[!] Kernel 7.0.x detected, patch level $PATCH < 9"
fi
elif [ "$MAJOR" -eq 7 ] && [ "$MINOR" -eq 1 ]; then
if echo "$KVER" | grep -qE 'rc[12]([^0-9]|$)'; then
vulnerable=1
echo "[!] Kernel 7.1-rc1 or rc2 detected"
fi
fi
if [ "$vulnerable" -eq 1 ]; then
if [ "$RENDER_NODES" -gt 0 ]; then
echo "VULNERABLE - kernel $KVER is affected and $RENDER_NODES DRM render node(s) are accessible"
exit 1
else
echo "VULNERABLE (reduced risk) - kernel $KVER is affected but no DRM render nodes found"
exit 1
fi
else
if [ "$MAJOR" -lt 6 ] || { [ "$MAJOR" -eq 6 ] && [ "$MINOR" -lt 18 ]; }; then
echo "PATCHED - kernel $KVER predates vulnerable code (introduced in 6.18-rc1)"
exit 0
fi
echo "PATCHED - kernel $KVER is at or above the fixed version"
exit 0
fi