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

amdgpu_amdkfd_gfx_v9: entire KFD backend is dead code on DragonFly; latent unvalidated vmid/engine_id index arithmetic should be guarded before KFD is ever enabled

Summary

CONFIG_HSA_AMD is undefined tree-wide, kgd2kfd=NULL, probe early-returns, no /dev/kfd - unreachable today (verified 3 ways). Latent hazards for the enable-day: get_sdma_base_addr indexes stack base[2] with MQD-sourced engine_id unbounded; set_pasid_vmid_mapping computes 1U<<(vmid+16) with no local bound; is_kfd_vmid's (1<<vmid) is UB for vmid>=32 and x86 shift-wrap lets vmid==40 pass the 0xFF00 test, feeding +80-dword offsets into set_vm_context_page_table_base. Add-local-guards fix authored.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4499 Β· 5 files
FileTypeDescriptionSize
README.md readme dead-code proof + latent hazards + in-bounds confirmations 3.4 KB ↓ raw
VERDICT.md verdict verification narrative 1.9 KB ↓ raw
env.txt env guest: no AMD HW / no kfd / no dri 129 B view raw
fix.diff hardening-fix engine_id and vmid guards 980 B view raw
verdict.json verdict-json machine verdict (strict status set) 2.3 KB view raw
README.md readme dead-code proof + latent hazards + in-bounds confirmations
↓ download raw

DF-4499 β€” amdgpu_amdkfd_gfx_v9.c is dead code on DragonFly; latent unvalidated index arithmetic for the day KFD is enabled

File: sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c (pass 2)

What (dead-code proof)

The Vega10/Vega20/Raven KFD backend compiled into the amdgpu KLD is unreachable on DragonFly:

  1. CONFIG_HSA_AMD is defined nowhere in the tree (no #define, no -DCONFIG_HSA_AMD in sys/dev/drm/amd/amdgpu/Makefile KCFLAGS).
  2. Therefore amdgpu_amdkfd_init() takes the #else branch: kgd2kfd = NULL (amdgpu_amdkfd.c:33-50).
  3. amdgpu_amdkfd_device_probe() returns at if (!kgd2kfd) return; before ever calling amdgpu_amdkfd_gfx_9_0_get_functions() (amdgpu_amdkfd.c:59-71) β€” so adev->kfd stays NULL.
  4. There is no KFD frontend in the tree (no sys/dev/drm/amd/amdkfd/, no /dev/kfd): nothing consumes the kfd2kgd table (amdgpu_amdkfd_gfx_v9.c:169-225).
  5. amdgpu_amdkfd_is_kfd_vmid() (amdgpu_amdkfd.c:514-523) gates every vmid-taking entry of this file on adev->kfd β€” always NULL here β†’ always false β†’ invalidate_tlbs_vmid() / set_vm_context_page_table_base() are no-ops even if reached.

Guest evidence: no AMD (0x1002) PCI devices, no /dev/dri, no /dev/kfd (env.txt).

Latent hazards (audit of the exported functions for the day it is enabled)

  • get_sdma_base_addr() (amdgpu_amdkfd_gfx_v9.c:372-390): indexes stack array uint32_t base[2] with engine_id taken from the MQD (m->sdma_engine_id) with no local bound; queue_id likewise scales the register stride unbounded. Validation currently lives only in the absent KFD frontend.
  • kgd_set_pasid_vmid_mapping() (:291-346): 1U << (vmid + 16) and register + vmid offsets rely entirely on the caller keeping vmid <= 15; a vmid β‰₯ 16 is silent UB / arbitrary adjacent MMIO writes.
  • amdgpu_amdkfd_is_kfd_vmid() (amdgpu_amdkfd.c:514): (1 << vmid) is UB for vmid >= 32; on x86 the shift wraps mod 32, so e.g. vmid=40 passes the 0xFF00 bitmap test and would feed vmid*2 (80 dwords) offsets into set_vm_context_page_table_base() (:1015-1052).
  • Unbounded cpu_relax() MMIO ACK polls in kgd_set_pasid_vmid_mapping() (:315-319, :332-336) and write_vmid_invalidate_request() (:830-837): a hung GPU wedges the calling kernel thread forever (same shape as upstream Linux; noted for completeness).

Verified in-bounds during this audit (negative results with weight)

  • kgd_hqd_load() MQDβ†’HQD register walk (:432-437): reads exactly the contiguous uint32_t span cp_mqd_base_addr_lo … cp_hqd_pq_wptr_hi (v9_structs.h:289-344), 56 dwords β€” matches HQD_N_REGS 56.
  • kgd_hqd_dump() / kgd_hqd_sdma_dump() (:497-531, :603-631): allocations sized to the walked ranges (56 and 42 pairs) and DUMP_REG bounds-checked with WARN_ON_ONCE.
  • amdgpu_amdkfd_get_tile_config() (:151-167): ARRAY_SIZE over genuine fixed-size arrays (tile_mode_array[32], macrotile_mode_array[16], amdgpu_gfx.h).
  • invalidate_tlbs() vmid loop is 0..15 with is_kfd_vmid + pasid match (:882-892).
  • get_fw_version() NULL-checks every firmware pointer before dereference (:1008-1009).

Fix

fix.diff: add explicit engine_id < 2 / vmid < 16 guards at the two latent index-arithmetic sites in this file. Info severity β€” defense-in-depth for a backend that is currently unreachable.

VERDICT.md verdict verification narrative
↓ download raw

VERDICT DF-4499 β€” gfx_v9 KFD backend dead on DF; latent index-arithmetic hazards

Bottom line

Info finding; PoC execution skipped (not applicable β€” the finding IS the unreachability). Verified at source and guest level:

  • CONFIG_HSA_AMD undefined tree-wide β†’ kgd2kfd = NULL (amdgpu_amdkfd.c:33-50) β†’ amdgpu_amdkfd_device_probe() early-returns (:59-71) β†’ adev->kfd NULL β†’ amdgpu_amdkfd_is_kfd_vmid() always false (:514-523) β†’ every kfd2kgd entry exported by amdgpu_amdkfd_gfx_v9.c:169-225 is unreachable, and no KFD frontend (amd/amdkfd/, /dev/kfd) exists in the tree to call them anyway.
  • Guest: no 0x1002 PCI devices, no /dev/dri, no /dev/kfd, no drm KLDs (env.txt).

Audit result for the exported functions (for the day KFD is enabled)

Confirmed in-bounds: hqd_load MQD walk (56 dwords, v9_structs.h:289-344), hqd_dump/sdma_dump allocations+guards, tile_config ARRAY_SIZE over real arrays, TLB vmid loop 0..15, fw_version NULL checks.

Latent hazards (unreachable today, fix when enabling): 1. get_sdma_base_addr base[engine_id] OOB for engine_id > 1 (MQD-sourced). 2. kgd_set_pasid_vmid_mapping 1U << (vmid+16) / +vmid register walks with no local vmid bound. 3. is_kfd_vmid (1 << vmid) UB at vmid β‰₯ 32 (x86 shift-wrap can pass the 0xFF00 test for vmid ≑ 8..15 mod 32 β†’ vmid*2 offsets up to +80 dwords in set_vm_context_page_table_base). 4. Unbounded cpu_relax() ACK polls (GPU hang β†’ kernel thread hang).

fix.diff adds explicit engine_id < 2 and vmid < 16 guards in this file.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored against read-only sys/ as hardening for currently dead code; no runtime validation applicable

fix.diff
↓ fix.diffper-fix-DF-4499

Confirmed kernel references

Detail

Evidence (decisive lines)

env.txt (guest: no 0x1002 devices, /dev/dri and /dev/kfd absent); amdgpu_amdkfd.c:33-50,59-71,514-523 (dead-code chain); VERDICT.md (in-bounds confirmations + latent hazards)

PoC changes

not applicable (no trigger; verification = dead-code proof + guest device-absence evidence)

Verified recommended fix

when enabling KFD: add engine_id<2 and vmid<16 guards (fix.diff) and fix the (1<<vmid) shift UB in amdgpu_amdkfd_is_kfd_vmid

Verdict

Info finding verified by source and guest inspection: the entire kfd2kgd backend of amdgpu_amdkfd_gfx_v9.c is dead code on DragonFly (CONFIG_HSA_AMD undefined tree-wide forces kgd2kfd=NULL, probe early-returns, adev->kfd NULL, and no amd/amdkfd frontend or /dev/kfd exists). No PoC is applicable - the unreachability itself is the verified fact; guest confirms no AMD PCI devices, no /dev/dri, no /dev/kfd, no drm KLDs. Latent hazards for the day KFD is enabled are documented and guarded by fix.diff.