CVE-2026-46215 (DRM GEM change_handle Use-After-Free) on Rocky Linux and RLC Pro Kernels
Introduction
CVE-2026-46215 is a local privilege escalation vulnerability in the Linux kernel's DRM (Direct Rendering Manager) subsystem. The DRM_IOCTL_GEM_CHANGE_HANDLE ioctl moves a GEM (Graphics Execution Manager) buffer object to a caller-chosen handle number, and its handler does not reconcile the handle-to-object mapping atomically. The handler allocates the new handle in the IDR (idr_alloc) and removes the old one (idr_remove) in separate steps. In the window between them the object holds two live IDR entries, the old handle and the new one, while its handle_count still reads 1. A DRM_IOCTL_GEM_CLOSE racing on the old handle drops what looks like the last handle reference, decrements handle_count to 0, and frees the object while the surviving new handle still points at it. Any subsequent use of that handle thus is a use-after-free exploit.
A public proof-of-concept and technical writeup are available. The exploit turns the use-after-free into a passwordless root account with a data-only technique that needs no memory-corruption gadgets. It reclaims the freed object into a kmalloc slab sprayed with pipe buffers, leaks a kernel pointer to defeat KASLR, bypasses the Dirty Pipe fix, and overwrites the page cache for /etc/passwd to add a passwordless UID 0 entry.
The scoping detail that matters for CIQ customers is where the vulnerable change_handle ioctl came from. It was introduced upstream in kernel 6.18, and it was also backported into the RHEL 9 and RHEL 10 kernel trees. That produces two exposure routes. The el9_8 and el10_2 backport exposes both the RLC Pro (9 and 10) and the Rocky Linux (9.8 and 10.2) kernels, and CIQ Linux Kernel 6.18 carries the feature natively until it is updated to a build that disables it. Most other CIQ kernels never carried the feature and are not affected. On every affected CIQ kernel the fix disables the ioctl outright (see Status).
This article describes what is affected, the current patch status, how to confirm exposure on a given host, how to install the patched kernel or apply an interim mitigation, and how to verify the result.
Problem
The flaw is reachable through the DRM render node. Both DRM_IOCTL_GEM_CHANGE_HANDLE and DRM_IOCTL_GEM_CLOSE are flagged DRM_RENDER_ALLOW, and drm_ioctl_permit() gates them on nothing else: no DRM master, no DRM_AUTH, no capability. Any process that can open /dev/dri/renderD* can call them. Two consequences are worth calling out during triage.
No graphical session is required. Render-node access is usually granted by systemd-logind on desktops, which is the source of most confusion around this CVE, but the bug is triggered by a plain ioctl() on a render node with no X11, Wayland, compositor, or logged-in graphical session running. The public proof-of-concept runs headless in a QEMU guest with virtio-gpu.
The render node is world-accessible by default. On stock Rocky Linux and RHEL 9/10, 50-udev-default.rules ships /dev/dri/renderD* as GROUP=render MODE=0666, so any local UID can open it. The card* nodes are seat- and uaccess-gated and do need a graphical login, which is why the render node, not card0, is the headless attack path.
The exploitable drivers are those that register GEM plus a render node (DRIVER_GEM | DRIVER_RENDER): virtio_gpu (common in cloud and virtualized guests), and bare-metal GPU drivers such as amdgpu, i915, nouveau, radeon, vmwgfx, and xe. NVIDIA's proprietary stack is a partial carve-out, since the GEM-create path at default modeset=0 is unproven and default CUDA containers expose only /dev/nvidia*.
Because the exposure depends on both an affected kernel and an openable render node, the highest real-world risk is on multi-tenant or shared hosts where untrusted local users can run code: virtualized guests using virtio-gpu, and GPU or AI compute servers where users legitimately hold render-node access.
Treat the following as affected unless running a patched kernel (see Status):
- RLC Pro 9 and Rocky Linux 9.8, via the RHEL 9 backport
- RLC Pro 10 and Rocky Linux 10.2, via the RHEL 10 backport
- CIQ Linux Kernel 6.18, which carries the feature natively (builds older than
6.18.36-1are affected)
The following CIQ kernels are not affected, because the change_handle feature was never present in them:
- RLC Pro 8 and RLC Pro LTS 8.6
- RLC Pro LTS 9.2 and RLC Pro LTS 9.6 (5.14-based, but before the RHEL backport)
- CIQ Bridge 7.9
- CIQ Linux Kernel 6.12 (the feature was introduced upstream in 6.18)
Confirming exposure on a specific host
First confirm the running kernel is on an affected line and older than the patched build:
uname -r
An el9_8 build older than 5.14.0-687.29.1, or an el10_2 build older than 6.12.0-211.37.1, is affected, on both RLC Pro (which adds a +2.1...el9_8_ciq or +2.1...el10_2_ciq suffix) and Rocky Linux. A CIQ Linux Kernel 6.18 build older than 6.18.36-1 is also affected. Any other CIQ kernel (LTS 8.6/9.2/9.6, RLC Pro 8, Bridge 7.9, CIQ Linux Kernel 6.12) is not affected by this CVE.
Then check whether a render node exists and which driver backs it, since exposure requires an openable render node bound to an affected driver:
ls -l /dev/dri/
lsmod | grep -E 'virtio_gpu|amdgpu|i915|nouveau|radeon|vmwgfx|^xe'
If there is no renderD* node under /dev/dri/ (common on stock cloud VMs with no GPU, for example default AWS Nitro or Azure hyperv_drm, and on GCP instances with no /dev/dri), the attack path is not present regardless of kernel version. If a renderD* node exists, check its permissions:
stat -c '%n %a %G' /dev/dri/renderD* 2>/dev/null
On a default install this reports mode 666 and group render, meaning any local user can open it. That is the exposed configuration.
Status
- Patched kernels are available for every affected line: RLC Pro 9 and 10, Rocky Linux 9.8 and 10.2, and CIQ Linux Kernel 6.18. See the Patched Kernels table below for exact versions. On all of them the fix disables the
change_handleioctl by pointing it atdrm_invalid_op, so the ioctl now returns-EINVALinstead of running the vulnerable handle swap. Every affected CIQ kernel ships the full five-commitchange_handlefix chain that ends in that disable, and there is no variant that keeps the ioctl live behind a narrower race fix. - One update clears the whole chain. The
change_handlefix chain's RPM changelog names four CVEs:CVE-2026-46215(the use-after-free),CVE-2026-52966,CVE-2026-53145, andCVE-2026-23149(a warning-hardening change). The same patched kernel resolves all four, so a scanner citing any of them on an affected line is cleared by the same update. - All other CIQ kernels are not affected (the feature is absent), and no action is required on them for this CVE.
- Recommended action: on any affected host, install the patched kernel and reboot (see Installing the Update). RLC Pro 9/10 and Rocky Linux 9.8/10.2 update via
dnf update kernel*, and CIQ Linux Kernel 6.18 hosts update to6.18.36-1or newer. If you cannot update immediately, see Mitigation for interim steps. - Open a support case if you need help confirming exposure on a specific host or validating a patched kernel against your workload.
Patched Kernels
| Variant | Patched Kernel Version | Released |
|---|---|---|
| RLC Pro 9 | kernel-5.14.0-687.29.1+2.1.el9_8_ciq |
2026-07-24 |
| RLC Pro 10 | kernel-6.12.0-211.37.1+2.1.el10_2_ciq |
2026-07-25 |
| CIQ Linux Kernel 6.18 | 6.18.39-1 |
2026-07-20 |
For Rocky Linux 9.8 and 10.2, the fixed kernels ship through the Rocky Linux errata. Refer to the Rocky Linux errata for the exact published build.
Confirm what is running on a given system with:
uname -r
If your system reports one of the patched versions above (or newer), the fix is in place and any interim mitigation can be reverted. See Resolution.
Installing the Update
RLC Pro 9 and 10
The patched kernel comes from the CIQ repositories your variant already uses, with no additional setup:
sudo dnf update kernel*
sudo reboot
If your RLC Pro variant draws the kernel from the Core Repo through depot channels, refresh metadata and enable the channel that matches your product before updating:
sudo dnf clean all && sudo dnf makecache
sudo depot enable rlc-pro-9 # use rlc-pro-10 on RLC Pro 10
sudo dnf update kernel*
sudo reboot
CIQ Linux Kernel 6.18
Update to 6.18.36-1 or newer through your configured CLK repository, then reboot. Any 6.18 build from 6.18.36-1 onward carries the fix:
sudo dnf update kernel*
sudo reboot
Rocky Linux (Community)
On Rocky Linux 9.8 and 10.2, the fixed kernel ships through the Rocky Linux errata in the standard BaseOS repository, with no additional configuration:
sudo dnf update kernel*
sudo reboot
Mitigation
Warning: The steps below are interim measures for hosts that cannot be patched immediately. Each one trades off GPU or display functionality. The fix is the patched kernel in Installing the Update. Test in a non-production environment before applying fleet-wide, and revert once the patched kernel is installed.
The exposure requires an unprivileged user to open a render node bound to an affected driver. The two options below each remove one side of that condition. Pick based on whether the host actually needs GPU or display functionality.
Option 1: Restrict access to the render node
By default /dev/dri/renderD* is world read/write (0666). Restricting it to the render group removes access from arbitrary local UIDs while leaving GPU access intact for accounts you place in that group. This does not fix the kernel bug; it narrows who can reach it. Use this on hosts that use the GPU only through specific accounts.
Step 1: install the udev rule.
cat <<'EOF' | sudo tee /etc/udev/rules.d/99-cve-2026-46215.rules
# Interim CVE-2026-46215 mitigation: remove world access to DRM render nodes
SUBSYSTEM=="drm", KERNEL=="renderD*", GROUP="render", MODE="0660"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=drm
Step 2: confirm the new mode and grant access to the accounts that need it.
stat -c '%n %a %G' /dev/dri/renderD*
# e.g. usermod -aG render <account> # for a service account that runs GPU/compute work
This leaves the flaw reachable by members of the render group, so it only helps where those members are trusted. On a host where every local user must have render access, this option provides no protection; use Option 2 or patch instead.
Option 2: Block the affected driver module
On a headless VM or server that does not need a display or GPU compute, preventing the affected driver from loading removes the render node entirely. The most common case is virtio_gpu on a virtualized guest with no graphical workload.
Warning: Blocking the driver removes the GPU/DRM device. On a guest that uses
virtio-gpufor its console this can affect the graphical console. Only apply where the host is genuinely headless and does not need the device. Do not use this option on GPU or AI compute nodes, since it removes the functionality they exist to provide.
Step 1: install the modprobe override.
# Replace virtio_gpu with the driver reported by the lsmod check above if different
echo "install virtio_gpu /bin/false" | sudo tee /etc/modprobe.d/cve-2026-46215.conf
Step 2: clear any resident copy of the module.
If the module is already loaded and not in use, unload it so the override takes effect immediately:
sudo rmmod virtio_gpu
If rmmod reports the module is in use, something is actively using the GPU or console framebuffer. Do not force the unload on a production host; schedule the change for a maintenance window, or install the patched kernel instead.
Verification
Use these checks to confirm an interim mitigation is active. For confirming the patched kernel is running, see Resolution.
After applying Option 1 (render node permissions)
stat -c '%n %a %G' /dev/dri/renderD*
The mode should read 660, not 666. Any local user outside the render group can no longer open the node.
After applying Option 2 (driver block)
Confirm the module is not loaded:
lsmod | grep virtio_gpu
No output means the module is not currently loaded. Confirm the modprobe override is in place:
sudo modprobe -n -v virtio_gpu
This should print install /bin/false. If it resolves to a .ko path, re-check /etc/modprobe.d/cve-2026-46215.conf and confirm it is present and readable. If the module still appears in lsmod after a reboot, the override is not catching the early boot load path; confirm the conf file is present and readable, rebuild the initramfs to include the modprobe config, and reboot again.
Resolution
After installing the patched kernel and rebooting, confirm the running kernel matches a patched version from the Patched Kernels table:
uname -r
If your system reports one of the patched versions (or newer), the fix is in place.
The one behavior change the fix introduces is that DRM_IOCTL_GEM_CHANGE_HANDLE now returns -EINVAL instead of running. The ioctl was added for a niche checkpoint/restore path and has no real userspace consumers, so the impact is negligible. Normal GPU, compute, and display workloads are unaffected.
If you applied either mitigation, revert it once the patched kernel is running:
# Revert Option 1 (render node permissions)
sudo rm /etc/udev/rules.d/99-cve-2026-46215.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=drm
# Revert Option 2 (driver block)
sudo rm /etc/modprobe.d/cve-2026-46215.conf
sudo modprobe virtio_gpu # or the driver you blocked
Notes
- Scanner hits. A vulnerability scanner flagging the kernel on an affected line (RLC Pro 9/10, Rocky Linux 9.8/10.2, or CIQ Linux Kernel 6.18 older than
6.18.36-1) is accurate. A scanner may cite any of the four CVEs the fix chain carries,CVE-2026-46215,CVE-2026-52966,CVE-2026-53145, orCVE-2026-23149, and the same patched kernel resolves all four. Real-world risk is highest where untrusted local users can run code and a render node is present and openable:virtio-gpuguests, shared GPU/AI compute nodes, CI runners. A host with no/dev/dri/renderD*node has no attack path here even on an affected kernel. - Backport versus native. The affected 5.14 (el9_8) and 6.12 (el10_2) kernels are vulnerable because the
change_handlefeature was backported into them, not because of their base version. That is why RLC Pro LTS 9.2 and 9.6 (also 5.14-based) and CIQ Linux Kernel 6.12 are not affected; they never received the backport. CIQ Linux Kernel 6.18 is the exception, since it carries the feature natively becausechange_handlewas introduced upstream in 6.18. - Not a display-only issue. The exploit does not need a desktop, compositor, or graphical login. Assume any affected host with an openable render node and local users is reachable.
- The mitigations are interim. Install the patched kernel and revert the workaround as soon as the build is applied.
References & related articles
- CVE-2026-46215 (NVD)
- CVE-2026-46215 (MITRE)
- Related CVEs in the same
change_handlefix chain, resolved by the same patched kernel: CVE-2026-52966, CVE-2026-53145, CVE-2026-23149 - Public technical writeup: cyberstan.co.uk/drm-lpe-linux
- Upstream fix commit (definitive, disables the ioctl): 1a4f03d22fb6
- Upstream race fix commit: 5e28b7b94408