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

Error path leaves half-initialized device on hive list and masks subsequent failures

Summary

amdgpu_xgmi_add_device adds device to hive->device_list at line 85 BEFORE attempting psp_xgmi_get_topology_info (line 89). If that call fails goto exit (95/114) without removing device so hive contains entry whose topology never fetched/set. On next add for another node stale entry device_id copied into tmp_topology (line 87) and psp_xgmi_set_topology_info driven across every node including half-baked one (line 99). ret only re-checked once (!ret at 109) so set_topology failure on later node still leaves earlier nodes state partially applied. Silent topology inconsistency across hive rather than clean failure. Amplifies UAF/leak issue DF-2204 by guaranteeing stale entries persist.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2205 Β· 8 files
FileTypeDescriptionSize
README.md readme claim, source-trace pointers, fix summary 2.9 KB ↓ raw
VERDICT.md verdict half-init error-path trace + amplification of DF-2204 + list_del fix 3.2 KB ↓ raw
fix.diff suggested-fix list_del + INIT_LIST_HEAD on psp_xgmi_get_topology_info failure path 948 B view raw
build.sh build-script applies fix.diff + rebuilds amdgpu.ko in guest 538 B view raw
run.sh run-script HW-gated no-op runner 404 B view raw
build_baseline.log build-log unpatched amdgpu.ko build, rc=0, -Werror 1.0 MB ↓ download
build_patched.log build-log patched amdgpu.ko rebuild, only amdgpu_xgmi.o recompiled, rc=0, -Werror 12.6 KB view raw
env.txt environment uname, cc, kern.version 376 B view raw
README.md readme claim, source-trace pointers, fix summary
↓ download raw

DF-2205 β€” amdgpu_xgmi: error path leaves device half-initialized on hive list (Low)

Claim

amdgpu_xgmi_add_device() in sys/dev/drm/amd/amdgpu/amdgpu_xgmi.c list_add_tail()s the device into hive->device_list (line 85) before attempting psp_xgmi_get_topology_info() (line 89). If that call fails, the goto exit at line 95 (and a second one at 114) does not remove the device, so the hive permanently contains an entry whose topology was never fetched or set. The next amdgpu_xgmi_add_device() for any other node then copies that stale device_id into tmp_topology (line 87) and drives psp_xgmi_set_topology_info across the half-baked node (line 99). ret is only re-checked once (if (!ret) at line 109), so a set_topology_info failure on a later node still leaves earlier nodes' state partially applied.

Verification approach

HW-gated / source-only. Reachable only on Vega20 hardware with a PSP topology fetch that fails (faulty PSP firmware / bad hardware link). No GPU on this audit guest. Per the task brief, source-only confirmation is acceptable.

  1. Confirm the list_add_tail precedes the psp_xgmi_get_topology_info call.
  2. Confirm the error-path goto exit does not call list_del.
  3. Confirm the subsequent list_for_each_entry would re-enter the stale node.
  4. Author fix.diff (undo the linkage on error).
  5. Phase 8 β€” apply all 5 batched fixes and rebuild amdgpu.ko with -Werror.

Source trace (confirmed)

Files

  • VERDICT.md β€” full narrative.
  • fix.diff β€” on the psp_xgmi_get_topology_info failure path, list_del(&adev->gmc.xgmi.head) + INIT_LIST_HEAD(...) before the existing dev_err / goto exit.
  • build_baseline.log β€” unpatched amdgpu.ko build, rc=0, -Werror.
  • build_patched.log β€” patched amdgpu.ko rebuild (only amdgpu_xgmi.o recompiled), rc=0, -Werror.
  • env.txt β€” guest environment.

Reproduce

./build.sh    # applies fix.diff + rebuilds amdgpu.ko
./run.sh      # HW-gated no-op (see VERDICT.md)
VERDICT.md verdict half-init error-path trace + amplification of DF-2204 + list_del fix
↓ download raw

DF-2205 β€” VERDICT

Verdict: REPRODUCED (source-only, HW-gated).

Class: silent state inconsistency / partial-init β†’ topology corruption.

Mechanism

amdgpu_xgmi_add_device() (sys/dev/drm/amd/amdgpu/amdgpu_xgmi.c) links the device into its hive before the topology-fetch step has been validated:

/* amdgpu_xgmi.c:85 */
list_add_tail(&adev->gmc.xgmi.head, &hive->device_list);
list_for_each_entry(entry, &hive->device_list, head)
    tmp_topology[count++].device_id = entry->device_id;

/* amdgpu_xgmi.c:89 */
ret = psp_xgmi_get_topology_info(&adev->psp, count, tmp_topology);
if (ret) {
    dev_err(...);
    goto exit;          /* <-- list_del missing here */
}

If psp_xgmi_get_topology_info() fails, the function logs an error and jumps to exit (mutex_unlock + return ret) without removing the device from hive->device_list. The hive now permanently contains an entry whose topology was never fetched or set.

The next amdgpu_xgmi_add_device() for any other device in the same hive:

  • Iterates hive->device_list at line 86 and copies the stale node's device_id into tmp_topology at line 87.
  • Drives psp_xgmi_set_topology_info across every node β€” including the half-baked one β€” at line 99.

Worse, ret from psp_xgmi_set_topology_info is only re-checked once (if (!ret) at line 109). If set_topology_info fails on a later node, the loop breaks but earlier nodes' partial state remains applied β€” the function returns the failure but the hive is left in a silently inconsistent state.

This defect amplifies DF-2204: combined with the missing removal path, half-baked entries never get cleaned up, so the inconsistency is permanent for the lifetime of the hive (and across driver reloads).

Trigger surface / reachability

psp_xgmi_get_topology_info() fails when the PSP firmware is faulty, the XGMI link is unhealthy, or the GPU is in an error state during probe. Vega20-only (the function early-returns for older ASICs and APUs). On this audit guest there is no GPU, so the partial-init cannot be exercised live; the bug is confirmed at the source level and the fix compiles cleanly (Phase 8).

Fix

fix.diff adds the missing cleanup on the error path:

ret = psp_xgmi_get_topology_info(&adev->psp, count, tmp_topology);
if (ret) {
    list_del(&adev->gmc.xgmi.head);
    INIT_LIST_HEAD(&adev->gmc.xgmi.head);
    dev_err(...);
    goto exit;
}

list_del + INIT_LIST_HEAD is the standard pattern: unlink from the hive, then mark the node empty so a later amdgpu_xgmi_remove_device (DF-2204's fix) and the idempotency guard both see it as unlinked. This prevents the half-baked node from being visible to subsequent adds and breaks the inconsistency amplification.

Phase 8 build validation

Applied fix.diff (plus the four other batched DRM fixes) to the in-guest /usr/src, rebuilt amdgpu.ko with -Werror: * baseline (unpatched) amdgpu.ko: rc=0 (build_baseline.log). * patched amdgpu.ko: rc=0, only amdgpu_xgmi.o recompiled (build_patched.log); no warnings, no errors.

Verdict

REPRODUCED at source level (HW-gated; no live repro possible on guest). The missing cleanup on the topology-fetch error path is unambiguous from the source; the fix compiles cleanly under -Werror.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched reproduced

amdgpu.ko baseline+patched rc=0 -Werror

amdgpu.ko baseline+patched rc=0 -Werror
↓ fix.diffmodule build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none (HW-gated)

Evidence (decisive lines)

HW-gated. Source-confirmed: psp_xgmi_get_topology_info failure path doesn't list_del -> stale half-baked entry.

Verified recommended fix

HW-gated. Source-confirmed: psp_xgmi_get_topology_info failure path doesn't list_del -> stale half-baked entry.

Verdict

HW-gated. Source-confirmed: psp_xgmi_get_topology_info failure path doesn't list_del -> stale half-baked entry.