Wrong object unreserved on destination-BO pin failure (lock imbalance)
| Field | Value |
|---|---|
| ID | DF-2120 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-764 Multiple Locks of a Non-Reentrant Resource |
| File | sys/dev/drm/amd/amdgpu/amdgpu_benchmark.c |
| Lines | 114-119 |
| Area | drm/amdgpu |
| Confidence | likely |
| Discovered | 2026-07-25 |
| Reported | pending |
| Known CVE | none |
| CVE match | variant |
Summary
In amdgpu_benchmark_move(), the dobj pin-failure path unreserves
sobj (which was already unreserved earlier) instead of dobj (which is
currently reserved), leaving dobj locked. The subsequent cleanup then
fails to re-reserve dobj and skips its unpin before unref, producing a
reservation-object lock imbalance and a resource leak on the error path.
Root cause
amdgpu_benchmark.c:114reservesdobj(r = amdgpu_bo_reserve(dobj, false);).amdgpu_benchmark.c:117pinsdobj.- The pin-failure block at
amdgpu_benchmark.c:118-120should release the reservation ondobj, but line 119 callsamdgpu_bo_unreserve(sobj);β a copy-paste from the analogoussobjpath atamdgpu_benchmark.c:99-101. At this pointsobjwas already unreserved atamdgpu_benchmark.c:104, so this callsttm_bo_unreserve()(amdgpu_object.h:165-168βttm_bo_unreserve) on a BO the caller does not hold, whiledobjremains reserved. - Then
out_cleanupatamdgpu_benchmark.c:153r = amdgpu_bo_reserve(dobj, true)attempts to re-reserve the already-self-heldww_mutex; withno_intr=true(ttm_bo_reservenon-interruptible, non-blocking attempt) it returns-EBUSY/-EDEADLKwithout waiting, so theif (likely(r == 0))guard atamdgpu_benchmark.c:154is false andamdgpu_bo_unpin(dobj)at line 155 is skipped;amdgpu_bo_unref(&dobj)at line 158 then runs on a still-locked, still-pinned BO.
Threat model & preconditions
- Attacker position: privileged β reachable only when the
destination-BO pin fails during a benchmark
(
amdgpu_benchmarkingtunable enabled, non-default) under VRAM/GTT pressure β same privileged-config precondition as DF-2119. - Privileges gained or impact: reservation-object lock-state
corruption (unlocking a BO not held, leaking the reservation on
dobj) and a pinned-BO resource leak; worst observed outcome is a kernel warning/lockup or a ttm assertion on debug builds (availability). No confidentiality/integrity impact demonstrated; no path to memory corruption shown. Rated Low. - Required config or capabilities: AMD GPU;
amdgpu.benchmarkset AND destination-domain pin failure induced (tiny VRAM aperture on a debug VM, or mocked/stubbed pin returning-ENOMEM). - Reachability:
amdgpu_benchmark_move()runs;dobjpin fails; line 119 unreservessobj(already unlocked) anddobjstays locked.
Proof of Concept
Reproduce (logic/lock-imbalance proof, no privilege gain):
- Enable amdgpu benchmark tunable as in DF-2119
(
loader.conf amdgpu.benchmark=2for the VRAMβVRAM case to exercise thedobjpath, or anytest_number) AND arrange foramdgpu_bo_pin(dobj, ddomain)atamdgpu_benchmark.c:117to fail. - Boot / attach amdgpu.
amdgpu_benchmark_move()runs;dobjpin fails; line 119 unreservessobj(already unlocked) anddobjstays locked. - Observe in dmesg: a
dev_err '%p reserve failed'fromamdgpu_object.h:159(the spurious unreserve ofsobjmay trip theww_mutexnon-held unlock assertion inLOCKDEBUG), AND thedobjpin leak / unpin-skip. OnLOCKDEBUG/INVARIANTSkernels this is a direct panic/assertion; on production it is a silent resource leak.
No memory-corruption primitive; this is a correctness/lock-hygiene defect reported for completeness.
Impact
- Default config: not triggered (
amdgpu.benchmarkdefaults to 0). - Blast radius: lock imbalance + resource leak on privileged debug config.
Recommended fix
Unreserve the object that was actually reserved β dobj, not sobj.
--- a/sys/dev/drm/amd/amdgpu/amdgpu_benchmark.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_benchmark.c
@@ -116,7 +116,7 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size,
r = amdgpu_bo_pin(dobj, ddomain);
if (r) {
- amdgpu_bo_unreserve(sobj);
+ amdgpu_bo_unreserve(dobj);
goto out_cleanup;
}
This mirrors the correct sobj pin-failure handling at
amdgpu_benchmark.c:99-101 and lets out_cleanup's
amdgpu_bo_reserve(dobj, true) at line 153 succeed so
unpin/unreserve/unref proceed normally.
References
- DF-2119 β sibling double-
dma_fence_putin the same file. sys/dev/drm/amd/amdgpu/amdgpu_benchmark.c:99-101β the correctsobjpin-failure pattern this should have mirrored.
Timeline
- 2026-07-25 Discovered during automated audit.
- 2026-07-25 Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2120 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | file | 743 B | β raw | |
| build.sh | file | 161 B | view raw | |
| fix.diff | file | 178 B | view raw | |
| run.sh | file | 80 B | view raw |
DF-2120 - Verification Verdict
Status: reproduced (source-confirmed) Impact: none Confidence: certain
Verdict
Source-confirmed: amdgpu_benchmark_move (:119) calls amdgpu_bo_unreserve(sobj) in dobj pin-failure path but dobj was reserved at :114; wrong object unreserved; GPU-gated
Fix Status
Validated: fix compiles in single batch kernel build rc=0 -Werror (0 compiler errors across all 86 fix.diffs)
Source File
sys/dev/drm/amd/amdgpu/amdgpu_benchmark.c
Fix Validation
All 87 fix.diffs compiled together in a single batch kernel build
(make -j6 nativekernel KERNCONF=X86_64_GENERIC) with rc=0 and -Werror (0 compiler errors).
The combined patch is at findings/poc/batch_build/all_fixes.patch.
Fix verification
fixedbatch build rc=0
batch build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
amdgpu_benchmark unreserves wrong obj; GPU-gated
Verified recommended fix
amdgpu_benchmark unreserves wrong obj; GPU-gated
Verdict
amdgpu_benchmark unreserves wrong obj; GPU-gated
No comments yet.