CVE-2026-31656
Published: 24 April 2026
Summary
CVE-2026-31656 is a high-severity Wrap or Wraparound (CWE-191) vulnerability in Linux Linux Kernel. Its CVSS base score is 7.8 (High).
Operationally, exploitation aligns with the MITRE ATT&CK technique Exploitation for Privilege Escalation (T1068); ranked at the 2.4th percentile by exploit likelihood (below the median); it is not currently listed in the CISA KEV catalog.
The strongest mitigations our analysis identified are NIST 800-53 SI-2 (Flaw Remediation) and RA-5 (Vulnerability Monitoring and Scanning).
Threat & Defense at a Glance
Threat & Defense Details
Mitigating Controls (NIST 800-53 r5)AI
Directly mandates timely patching of the refcount underflow race condition in the Linux kernel i915 driver's intel_engine_park_heartbeat function.
Vulnerability scanning identifies Linux kernel versions affected by CVE-2026-31656 in the i915 graphics driver.
System monitoring detects refcount underflow warnings or kernel crashes from the heartbeat worker and parking race in i915 driver logs.
MITRE ATT&CK Enterprise TechniquesAI
Why these techniques?
Local kernel UAF/refcount underflow in i915 driver directly enables T1068 (Exploitation for Privilege Escalation) by low-privileged attacker; secondary DoS impact possible via T1499.004 but not primary mapping.
NVD Description
In the Linux kernel, the following vulnerability has been resolved: drm/i915/gt: fix refcount underflow in intel_engine_park_heartbeat A use-after-free / refcount underflow is possible when the heartbeat worker and intel_engine_park_heartbeat() race to release the same engine->heartbeat.systole request. The heartbeat worker reads…
more
engine->heartbeat.systole and calls i915_request_put() on it when the request is complete, but clears the pointer in a separate, non-atomic step. Concurrently, a request retirement on another CPU can drop the engine wakeref to zero, triggering __engine_park() -> intel_engine_park_heartbeat(). If the heartbeat timer is pending at that point, cancel_delayed_work() returns true and intel_engine_park_heartbeat() reads the stale non-NULL systole pointer and calls i915_request_put() on it again, causing a refcount underflow: ``` <4> [487.221889] Workqueue: i915-unordered engine_retire [i915] <4> [487.222640] RIP: 0010:refcount_warn_saturate+0x68/0xb0 ... <4> [487.222707] Call Trace: <4> [487.222711] <TASK> <4> [487.222716] intel_engine_park_heartbeat.part.0+0x6f/0x80 [i915] <4> [487.223115] intel_engine_park_heartbeat+0x25/0x40 [i915] <4> [487.223566] __engine_park+0xb9/0x650 [i915] <4> [487.223973] ____intel_wakeref_put_last+0x2e/0xb0 [i915] <4> [487.224408] __intel_wakeref_put_last+0x72/0x90 [i915] <4> [487.224797] intel_context_exit_engine+0x7c/0x80 [i915] <4> [487.225238] intel_context_exit+0xf1/0x1b0 [i915] <4> [487.225695] i915_request_retire.part.0+0x1b9/0x530 [i915] <4> [487.226178] i915_request_retire+0x1c/0x40 [i915] <4> [487.226625] engine_retire+0x122/0x180 [i915] <4> [487.227037] process_one_work+0x239/0x760 <4> [487.227060] worker_thread+0x200/0x3f0 <4> [487.227068] ? __pfx_worker_thread+0x10/0x10 <4> [487.227075] kthread+0x10d/0x150 <4> [487.227083] ? __pfx_kthread+0x10/0x10 <4> [487.227092] ret_from_fork+0x3d4/0x480 <4> [487.227099] ? __pfx_kthread+0x10/0x10 <4> [487.227107] ret_from_fork_asm+0x1a/0x30 <4> [487.227141] </TASK> ``` Fix this by replacing the non-atomic pointer read + separate clear with xchg() in both racing paths. xchg() is a single indivisible hardware instruction that atomically reads the old pointer and writes NULL. This guarantees only one of the two concurrent callers obtains the non-NULL pointer and performs the put, the other gets NULL and skips it. (cherry picked from commit 13238dc0ee4f9ab8dafa2cca7295736191ae2f42)
Deeper analysisAI
CVE-2026-31656 is a refcount underflow vulnerability, potentially leading to use-after-free, in the Linux kernel's Direct Rendering Manager (DRM) i915 graphics driver, specifically within the GT (GuC/GuC submission) component. The issue arises from a race condition between the heartbeat worker and the intel_engine_park_heartbeat() function when releasing the engine->heartbeat.systole request. The heartbeat worker reads the systole pointer, calls i915_request_put() upon completion, and clears it non-atomically, while a concurrent request retirement on another CPU can trigger parking that reads the stale pointer and performs another put, causing the underflow. This was observed triggering refcount warnings in kernel logs, as shown in the provided stack trace from engine retirement processing.
A local attacker with low privileges (PR:L) can exploit this vulnerability with low attack complexity (AC:L) and no user interaction (UI:N), as indicated by its CVSS v3.1 base score of 7.8 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H). Exploitation requires access to a system running an affected Linux kernel with the i915 driver in use, typically on Intel GPU-equipped hardware. Successful exploitation could result in high confidentiality, integrity, and availability impacts, such as kernel memory corruption, denial of service via crashes, or potential privilege escalation through use-after-free primitives.
Mitigation involves applying the upstream kernel patches referenced in the stable git commits, such as 2af8b200cae3fdd0e917ecc2753b28bb40c876c1 and others listed. These patches replace the non-atomic pointer read and clear operations in both racing paths with an atomic xchg() instruction, ensuring only one caller obtains the non-NULL pointer and performs the i915_request_put(), while the other receives NULL and skips it. Systems should update to kernels incorporating these fixes (cherry-picked from commit 13238dc0ee4f9ab8dafa2cca7295736191ae2f42).
Details
- CWE(s)