β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1988

radeon_sa_bo_manager_fini manipulates SA lists without holding wq.lock (race condition / potential UAF)

  • File: sys/dev/drm/radeon/radeon_sa.c
  • Lines: 82–91 (manager_fini without lock); cf. locked paths at 333, 386, 405
  • Severity: Low
  • CVSS 3.1: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U:C:N/I:N/A:H
  • CWE: CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization (Race Condition)
  • Confidence: likely
  • Status: new

Summary

radeon_sa_bo_manager_fini calls radeon_sa_bo_try_free and iterates sa_manager->olist calling radeon_sa_bo_remove_locked without acquiring sa_manager->wq.lock.

Every other function in this file that touches the olist/flist/hole (radeon_sa_bo_new at line 333, radeon_sa_bo_free at line 386, radeon_sa_bo_dump_debug_info at line 405) properly acquires the lock first.

If manager_fini races with a concurrent allocator operation, the lockless list traversal and node removal can corrupt the list, leading to use-after-free or double-free.

Root cause

At radeon_sa.c:82-91, radeon_sa_bo_manager_fini does:

(void) line 84: calls radeon_sa_bo_try_free(sa_manager)
                -- which reads/modifies sa_manager->hole, iterates olist,
                   calls radeon_sa_bo_remove_locked

lines 89-91: list_for_each_entry_safe over sa_manager->olist calling
             radeon_sa_bo_remove_locked
             -- which does list_del_init on both olist and flist,
                reads/modifies sa_manager->hole, and calls radeon_fence_unref

None of these operations are protected by lockmgr(&sa_manager->wq.lock, LK_EXCLUSIVE).

Contrast with radeon_sa_bo_new:333, radeon_sa_bo_free:386, and radeon_sa_bo_dump_debug_info:405 which all acquire the lock before touching the same data structures.

Threat model

Attacker position: local user who can trigger a GPU reset (e.g., by submitting a malicious command stream that causes a GPU lockup) while concurrent CS submissions are in flight.

radeon_ib_pool_fini (radeon_ib.c:238-245) calls radeon_sa_bo_manager_fini from ASIC hw_fini/suspend functions during GPU reset or device teardown.

If a CS submission thread is simultaneously inside radeon_sa_bo_new or radeon_sa_bo_free (holding wq.lock and manipulating the lists), the lockless traversal in manager_fini can dereference a freed sa_bo node or corrupt list pointers.

This is a narrow race requiring precise timing during GPU reset, hence Low severity.

Proof of concept

Difficult to reliably exploit due to narrow timing window during GPU reset. The attack would involve:

  1. Thread A: submit a continuous stream of DRM_IOCTL_RADEON_CS calls to keep the SA allocator busy.
  2. Thread B: submit a malicious IB that triggers a GPU lockup, causing radeon_gpu_reset to call hw_fini β†’ radeon_ib_pool_fini β†’ radeon_sa_bo_manager_fini.
  3. If manager_fini's lockless list traversal overlaps with Thread A's locked list manipulation in radeon_sa_bo_new, list corruption occurs.

Success: kernel panic from corrupted list pointers (e.g., page fault dereferencing a poisoned list_head). This is a reliability/DoS issue rather than a controlled exploitation primitive.

Acquire sa_manager->wq.lock before performing list operations in radeon_sa_bo_manager_fini, consistent with every other function in the file.

--- a/sys/dev/drm/radeon/radeon_sa.c
+++ b/sys/dev/drm/radeon/radeon_sa.c
@@ -77,11 +77,14 @@ void radeon_sa_bo_manager_fini(struct radeon_device *rdev,
    struct radeon_sa_bo *sa_bo, *tmp;

+   lockmgr(&sa_manager->wq.lock, LK_EXCLUSIVE);
    if (!list_empty(&sa_manager->olist)) {
        sa_manager->hole = &sa_manager->olist,
        radeon_sa_bo_try_free(sa_manager);
        if (!list_empty(&sa_manager->olist)) {
            dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n");
        }
    }
    list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) {
        radeon_sa_bo_remove_locked(sa_bo);
    }
+   lockmgr(&sa_manager->wq.lock, LK_RELEASE);
    radeon_bo_unref(&sa_manager->bo);
    sa_manager->size = 0;

References

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1988 Β· 5 files
FileTypeDescriptionSize
VERDICT.md verdict Source verification narrative 1.2 KB ↓ raw
fix.diff suggested-fix Fix: Acquire sa_manager->wq.lock before list operations; release at end. 570 B view raw
build.sh build-script Build/validation instructions 366 B view raw
run.sh run-script Run instructions (HW-gated, source-only) 184 B view raw
env.txt environment Guest environment 404 B view raw
VERDICT.md verdict Source verification narrative
↓ download raw

DF-1988 - Source Verification

Verdict: REPRODUCED (source-only confirmation)

Finding: sys/dev/drm/radeon/radeon_sa.c:82-91

Mechanism: radeon_sa_bo_manager_fini manipulates sa_manager->olist and calls radeon_sa_bo_try_free/list_for_each_entry_safe WITHOUT acquiring sa_manager->wq.lock. Race with concurrent allocator β†’ UAF/list corruption.

Hardware dependency: Requires radeon GPU with SA bo manager.

Fix: Acquire sa_manager->wq.lock before list operations; release at end.

Verification method

Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β€” the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.

Fix validation

fix.diff authored and applied to guest source. All 40 fixes in this batch compile cleanly in a single combined kernel build: make -j6 nativekernel KERNCONF=X86_64_GENERIC β†’ rc=0, zero -Werror violations.

Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026

Fix verification

not_testable
baseline reproduced→ patch + rebuild →patched clean

not_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.

Batch build: 40 fix.diffs applied, make nativekernel β†’ rc=0 -Werror. Bug at sys/dev/drm/radeon/radeon_sa.c:82-91 source-confirmed.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026

Confirmed kernel references

Detail

Exploit chain

none

Evidence (decisive lines)

Source trace sys/dev/drm/radeon/radeon_sa.c:82-91. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.

PoC changes

Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: manager_fini without wq.lock β†’ race UAF. Acquire lock.

Verified recommended fix

See fix.diff. manager_fini without wq.lock β†’ race UAF. Acquire lock.

Verdict

REPRODUCED (source-only). sys/dev/drm/radeon/radeon_sa.c:82-91: manager_fini without wq.lock β†’ race UAF. Acquire lock.