CVE-2024-26939: drm/i915/vma: Fix UAF on destroy against retire race
In the Linux kernel, the following vulnerability has been resolved:
drm/i915/vma: Fix UAF on destroy against retire race
Object debugging tools were sporadically reporting illegal attempts to free a still active i915 VMA object when parking a GT believed to be idle.
[161.359441] ODEBUG: free active (active state 0) object: ffff88811643b958 object type: i915active hint: i915vmaactive+0x0/0x50 [i915] [161.360082] WARNING: CPU: 5 PID: 276 at lib/debugobjects.c:514 debugprintobject+0x80/0xb0 ... [161.360304] CPU: 5 PID: 276 Comm: kworker/5:2 Not tainted 6.5.0-rc1-CIDRM13375-g003f860e5577+ #1 [161.360314] Hardware name: Intel Corporation Rocket Lake Client Platform/RocketLake S UDIMM 6L RVP, BIOS RKLSFWI1.R00.3173.A03.2204210138 04/21/2022 [161.360322] Workqueue: i915-unordered intelwakerefputwork [i915] [161.360592] RIP: 0010:debugprintobject+0x80/0xb0 ... [161.361347] debugobjectfree+0xeb/0x110 [161.361362] i915activefini+0x14/0x130 [i915] [161.361866] releasereferences+0xfe/0x1f0 [i915] [161.362543] i915vmaparked+0x1db/0x380 [i915] [161.363129] gtpark+0x121/0x230 [i915] [161.363515] intelwakerefputlast+0x1f/0x70 [i915]
That has been tracked down to be happening when another thread is deactivating the VMA inside activeretire() helper, after the VMA's active counter has been already decremented to 0, but before deactivation of the VMA's object is reported to the object debugging tool.
We could prevent from that race by serializing i915activefini() with activeretire() via ref->treelock, but that wouldn't stop the VMA from being used, e.g. from i915vmaretire() called at the end of activeretire(), after that VMA has been already freed by a concurrent i915vmadestroy() on return from the i915activefini(). Then, we should rather fix the issue at the VMA level, not in i915active.
Since i915vmaparked() is called from gtpark() on last put of the GT's wakeref, the issue could be addressed by holding the GT wakeref long enough for activeretire() to complete before that wakeref is released and the GT parked.
I believe the issue was introduced by commit d93939730347 ("drm/i915: Remove the vma refcount") which moved a call to i915activefini() from a dropped i915vmarelease(), called on last put of the removed VMA kref, to i915vmaparked() processing path called on last put of a GT wakeref. However, its visibility to the object debugging tool was suppressed by a bug in i915active that was fixed two weeks later with commit e92eb246feb9 ("drm/i915/active: Fix missing debug object activation").
A VMA associated with a request doesn't acquire a GT wakeref by itself. Instead, it depends on a wakeref held directly by the request's active intelcontext for a GT associated with its VM, and indirectly on that intelcontext's engine wakeref if the engine belongs to the same GT as the VMA's VM. Those wakerefs are released asynchronously to VMA deactivation.
Fix the issue by getting a wakeref for the VMA's GT when activating it, and putting that wakeref only after the VMA is deactivated. However, exclude global GTT from that processing path, otherwise the GPU never goes idle. Since i915vmaretire() may be called from atomic contexts, use async variant of wakeref put. Also, to avoid circular locking dependency, take care of acquiring the wakeref before VM mutex when both are needed.
v7: Add inline comments with justifications for: - using untracked variants of intelgtpmget/put() (Nirmoy), - using async variant of put(), - not getting the wakeref in case of a global GTT, - always getting the first wakeref outside vm->mutex. v6: Since i915vmaactive/retire() callbacks are not serialized, storing a wakeref tracking handle inside struct i915vma is not safe, and there is no other good place for that. Use untracked variants of intelgtpmget/putasync(). v5: Replace "tile" with "GT" across commit description (Rodrigo), - ---truncated---
Other sources
In the Linux kernel, the following vulnerability has been resolved:
drm/i915/vma: Fix UAF on destroy against retire race
The Linux kernel CVE team has assigned CVE-2024-26939 to this issue.
Upstream advisory: https://lore.kernel.org/linux-cve-announce/2024050124-CVE-2024-26939-5314@gregkh/T
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
debian/linuxto a version that resolves this vulnerability.Fixed in 5.10.223-1Fixed in 5.10.234-1Fixed in 6.1.129-1Fixed in 6.1.135-1Fixed in 6.12.25-1 - Upgrade
Upgrade
redhat/kernelto a version that resolves this vulnerability.Fixed in 6.1.88 - Upgrade
Upgrade
redhat/kernelto a version that resolves this vulnerability.Fixed in 6.6.29 - Upgrade
Upgrade
redhat/kernelto a version that resolves this vulnerability.Fixed in 6.8.3 - Upgrade
Upgrade
redhat/kernelto a version that resolves this vulnerability.Fixed in 6.9 - Upgrade
Upgrade
drm/i915/active: Fix missing debug object activationto a version that resolves this vulnerability.Patch e92eb246feb9 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Patch d93939730347 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Patch CVE-2024-26939 - Configuration
Exclude global GTT from the processing path that gets a GT wakeref for a VMA when activating it; otherwise the GPU never goes idle.
Intel i915 VMA/GT wakeref handling Exclude global GTT from VMA GT wakeref processing path = exclude - Configuration
When releasing the GT wakeref, put that wakeref only after the VMA is deactivated (not earlier) to avoid UAF during destroy vs retire races.
Intel i915 VMA deactivation wakeref put timing = after VMA deactivation - Configuration
Fix the issue by getting a wakeref for the VMA's GT when activating it, and hold the GT wakeref long enough for __active_retire() to complete before the GT is parked.
Intel i915 VMA activation wakeref acquisition for VMA's GT = hold during __active_retire() completion - Configuration
In __i915_vma_retire(), use the async variant of wakeref put since __i915_vma_retire() may be called from atomic contexts.
Intel i915 wakeref put use async variant of wakeref put = async - Configuration
Use untracked variants of intel_gt_pm_get/put_async() (i.e., intel_gt_pm_get/put_async()) as described in the upstream advisory.
Intel i915 wakeref get/put intel_gt_pm_get/put variant = untracked variants - Configuration
When both the wakeref and VM mutex are needed, acquire the wakeref before VM mutex to avoid circular locking dependency and ensure correct wakeref acquisition (including not relying on getting the first wakeref outside vm->mutex incorrectly).
Intel i915 wakeref locking order acquire wakeref before vm->mutex = before - Operational
Validate that object debugging tools (ODEBUG) no longer report illegal attempts to free an active i915_active object during GT parking; the reported UAF symptom should cease after applying the e92eb246feb9 fix.
Event History
Frequently Asked Questions
What is the severity of CVE-2024-26939?
CVE-2024-26939 is classified as a medium severity vulnerability in the Linux kernel.
How do I fix CVE-2024-26939?
To mitigate CVE-2024-26939, update the Linux kernel to versions 6.1.88, 6.6.29, 6.8.3, or 6.9 from Red Hat, or applicable versions from Debian.
What type of vulnerability is CVE-2024-26939?
CVE-2024-26939 is a use-after-free (UAF) vulnerability that occurs during the destruction of i915 VMA objects.
Which Linux kernel versions are affected by CVE-2024-26939?
CVE-2024-26939 affects specific versions of the kernel prior to the fixes in 6.1.88, 6.6.29, 6.8.3, and 6.9.
Is CVE-2024-26939 exploitable?
Yes, CVE-2024-26939 can potentially be exploited if an attacker can trigger the race condition in the Linux kernel during the VMA object's lifecycle.