amdgpu_amdkfd_gfx_v8: entire gfx8 KFD backend is dead code on DragonFly; latent unvalidated vmid/engine index arithmetic and a structurally broken fw-NULL guard must be fixed before KFD is ever enabled (gfx8 sibling of DF-4499)
Summary
Not compiled (absent from Makefile SRCS) and unreachable even if it were (CONFIG_HSA_AMD undefined -> kgd2kfd NULL -> probe early-return). On enable-day five hazards ship unguarded: pasid_vmid_mapping with no vmid<16 check (OOB MMIO writes past 16-entry banks + 1U<<vmid UB + unbounded cpu_relax poll); uint8_t vmid unchecked in the ATC getters (OOB read to +255 dwords); get_fw_version derefs fw->data in every case BEFORE the hdr==NULL check that can never fire (mec2/sdma1 NULL on single-MEC/single-SDMA parts -> panic); MQD-sourced engine/queue ids multiplied into MMIO offsets unchecked; division by num_pipe_per_mec with no zero check. Enable-day guards fix authored (git-apply-verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4578 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 5.9 KB | β raw | |
| VERDICT.md | β | 5.0 KB | β raw | |
| env.txt | β | 1.7 KB | view raw | |
| run.log | β | 518 B | view raw | |
| fix.diff | β | 22.2 KB | view raw | |
| manifest.json | β | 1.8 KB | view raw | |
| verdict.json | β | 3.9 KB | view raw |
DF-4578 β amdgpu_amdkfd_gfx_v8.c: KFD gfx8 backend is dead code on DragonFly; latent enable-day hazards must be guarded
File: sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c (885 LOC) β pass 2 (GLM 5.3 re-audit).
Sibling of DF-4499 (gfx_v9, same verdict class).
Build/run/expected
There is nothing to build or run: this file is not part of any DragonFly build and its only call path is compiled out tree-wide. Verification is by source trace + guest inspection:
# host (source of truth)
grep -rn "amdgpu_amdkfd_gfx_v8" sys/dev/drm/amd/amdgpu/Makefile sys/dev/drm/amd/Makefile # no hits => not compiled
grep -rn "define CONFIG_HSA_AMD\|CONFIG_HSA_AMD=" sys/ # no hits => KFD never enabled
# guest
pciconf -l | grep 1002 # no ATI hardware present
ls /dev/dri # absent
kldstat | grep -i drm # no drm KLDs loaded
Expected: all three confirm dead code / no reachable path (see env.txt, run.log).
Liveness proof (why this is dead)
sys/dev/drm/amd/amdgpu/Makefile:155-156β the amdkfd block adds onlySRCS+= amdgpu_amdkfd.c.amdgpu_amdkfd_gfx_v8.c(and_gfx_v9.c, and the gfx7 backend, which does not exist in this tree at all) are absent from every SRCS list; the lists are explicit, there are no wildcards. The translation unit is never compiled.CONFIG_HSA_AMDis defined nowhere undersys/(grep returns nothing), soamdgpu_amdkfd_init()(amdgpu_amdkfd.c:34-47) setskgd2kfd = NULLand returns-ENOENT.amdgpu_amdkfd_device_probe()(amdgpu_amdkfd.c:57-71) returns atif (!kgd2kfd) return;βamdgpu_amdkfd_gfx_8_0_get_functions()(the real one, gfx_v8.c:183) is unreachable; the#ifndef CONFIG_HSA_AMDstub (amdgpu_amdkfd.c:554-557) is what links instead.- The KFD frontend (
amd/amdkfd/,/dev/kfd, the kfd ioctl entry) does not exist anywhere in the DragonFly tree β there is no possible caller of thekfd2kgdops table even if the backend were compiled.
Latent hazards for the day KFD is enabled (fix before flipping CONFIG_HSA_AMD)
Hazards are not reachable today (dead code). They are the gfx8 analogues of the DF-4499 list plus one gfx8-specific NULL-deref:
kgd_set_pasid_vmid_mapping(gfx_v8.c:245-270) β no localvmid < 16check.mmATC_VMID0_PASID_MAPPING + vmid(:260) andmmIH_VMID_0_LUT + vmid(:267) are 16-entry register banks; an out-of-range vmid writes/reads unrelated MMIO.1U << vmid(:262) is UB for vmid >= 32. Also thecpu_relax()status poll (:262-263) has no timeout β a hung GPU wedges the calling thread forever.get_atc_vmid_pasid_mapping_valid/get_atc_vmid_pasid_mapping_pasid(gfx_v8.c:702-720) βvmidisuint8_t(0..255) and unchecked:RREG32(mmATC_VMID0_PASID_MAPPING + vmid)OOB-reads up to 255 dwords past the 16-entry bank.get_fw_version(gfx_v8.c:778-833) β each switch case dereferences the firmware pointer before the NULL check at :828 (if (hdr == NULL)can only catchfw->data == NULL, neverfw == NULL). Concretely NULL on real parts:adev->gfx.mec2_fwis NULL onnum_mec == 1VI ASICs (gfx_v8_0.c:2029-2041: TOPAZ/STONEY/default β 1; STONEY is upstream-KFD-supported and one probe-list entry away), andadev->sdma.instance[1].fwis NULL on single-SDMA-instance parts (sdma_v3_0.c:1114-1118: STONEY β 1 instance).get_sdma_base_addr(gfx_v8.c:291-300) /kgd_hqd_sdma_dump(:486-492) βsdma_engine_id/sdma_queue_id(MQD-sourced) andengine_id/queue_id(caller-sourced) are multiplied into MMIO offsets with no bound check (engine_id * SDMA1_REGISTER_OFFSET + queue_id * KFD_VI_SDMA_QUEUE_OFFSET). gfx8 uses multiplication rather than v9's array, so it is an MMIO-offset hazard rather than a kernel-memory OOB β same DF-4499 class.acquire_queue(gfx_v8.c:211-220) /kgd_init_interrupts(:272-279) /kgd_hqd_load(:331-332) β divide byadev->gfx.mec.num_pipe_per_mecwith no zero check (div-by-zero if called before gfx sw_init populates it).- Note-only:
set_scratch_backing_va(:768-776) truncates the 64-bitvato 32 bits inWREG32(mmSH_HIDDEN_PRIVATE_BASE_VMID, va)β upstream-identical (scratch backing VA is a <4GB aperture offset by KFD design), not a DF divergence.
Verified-in-bounds (pass-2 negative results, with evidence)
- MQD walks in
kgd_hqd_load(:345-360) β walk 1mmCP_MQD_BASE_ADDR..mmCP_HQD_EOP_CONTROL= 0x3245..0x326c (indices 0..39) and walk 2mmCP_HQD_EOP_EVENTS..mmCP_HQD_ERROR= 0x326f..0x3278 (indices 42..51) againststruct vi_mqdfield positions (vi_structs.h:289-340): exact 1:1 layout match, and the struct continues past index 51 up toreserved_t[256](:417), so no OOB even for a barevi_mqd. kgd_hqd_dump(:387-421) β count is exactly 54+4 (0x3245..0x327a = 54 regs + 4 STATIC_THREAD_MGMT);DUMP_REGis additionallyWARN_ON_ONCE(i >= HQD_N_REGS)bounds-guarded. No overflow possible.get_tile_config(:108-128) βARRAY_SIZEover the fixed arraystile_mode_array[32]/macrotile_mode_array[16](amdgpu_gfx.h:175-176), not over a pointer; counts are always 32/16 and match the arrays exported.invalidate_tlbs(:848-871) β vmid loop bounded 0..15,is_kfd_vmid-gated,1 << vmidsafe for vmid < 16; PASID compare masked withPASID_MASKvs uint16_t.invalidate_tlbs_vmid(:873-885) /set_vm_context_page_table_base(:835-846) β both gate onamdgpu_amdkfd_is_kfd_vmid()(compute_vmid_bitmap 0xFF00 β vmid 8..15), so+vmid-8stays in 0..7 ofmmVM_CONTEXT8_PAGE_TABLE_BASE_ADDRand1 << vmidin 1<<8..1<<15. Safe.
Fix
fix.diff adds the local bounds/NULL guards (vmid < 16 in the pasid-mapping writer
and both ATC mapping getters, per-case firmware-pointer NULL checks, engine/queue
bounds in the SDMA paths). Authored against the read-only sys/ tree; not applied.
VERDICT DF-4578 β gfx8 KFD backend dead on DragonFly; latent index/NULL hazards
Status: untested (no PoC is applicable β the dead-code claim itself is the verified fact). Severity Info, confidence certain. Mirror of DF-4499 (gfx_v9) for the gfx8 backend.
What was verified, and how
-
Dead code β certain. -
sys/dev/drm/amd/amdgpu/Makefile:155-156:# add amdkfd interfacesblock addsSRCS+= amdgpu_amdkfd.conly.amdgpu_amdkfd_gfx_v8.cappears in no Makefile in the tree (checkedsys/dev/drm/amd/Makefile,sys/dev/drm/amd/amdgpu/Makefile,sys/dev/drm/Makefile); SRCS lists are explicit enumerations, no wildcards. The translation unit is never compiled into drm.ko/amdgpu.ko. -grep -rn "CONFIG_HSA_AMD" sys/β only#ifdef/#ifndefguards (amdgpu_amdkfd.c:38,524; amdgpu_drv.c:553,1383); nothing defines it.amdgpu_amdkfd_init()(amdgpu_amdkfd.c:34-47) therefore forceskgd2kfd = NULL; ret = -ENOENT;. -amdgpu_amdkfd_device_probe()(amdgpu_amdkfd.c:57-71) returns before the CHIP_CARRIZO/TONGA/FIJI/POLARIS10/11 case that would callamdgpu_amdkfd_gfx_8_0_get_functions(). The linked symbol is the#ifndef CONFIG_HSA_AMDstub at amdgpu_amdkfd.c:554-557 returning NULL. - Noamd/amdkfd/frontend exists in the tree (only the fouramdgpu_amdkfd*.[ch]glue files): no/dev/kfd, no kfd ioctls, no queue manager β nothing can invoke thekfd2kgdtable even if it were reachable. - Guest (env.txt): no 0x1002 PCI devices (virtio-gpu only),/dev/driabsent, no drm KLDs loaded β no runtime path either. -
Latent hazards (unreachable today; guard when enabling) β certain by inspection. -
kgd_set_pasid_vmid_mappinggfx_v8.c:245-270: unvalidated vmid βmmATC_VMID0_PASID_MAPPING + vmid(:260) /mmIH_VMID_0_LUT + vmid(:267) OOB MMIO writes past 16-entry banks;1U << vmid(:262) UB at vmidβ₯32; unboundedcpu_relax()poll (:262-263) = permanent thread wedge on GPU hang. -get_atc_vmid_pasid_mapping_valid/pasidgfx_v8.c:702-720:uint8_t vmidunchecked β OOB MMIO read up to +255 dwords. -get_fw_versiongfx_v8.c:778-833:fw->datadereferenced in every case before theif (hdr == NULL)guard (:828).adev->gfx.mec2_fwis NULL onnum_mec==1VI parts (gfx_v8_0.c:2029-2041 β TOPAZ/STONEY/default; STONEY is upstream-KFD-supported, one probe-list entry away from this tree's list at amdgpu_amdkfd.c:65-68),adev->sdma.instance[1].fwNULL on single-instance parts (sdma_v3_0.c:1114-1118) β NULL-deref panic on enable-day. -get_sdma_base_addrgfx_v8.c:291-300 /kgd_hqd_sdma_dump:486-492: MQD/caller-sourced engine_id/queue_id multiplied into MMIO offsets unchecked (DF-4499 hazard #1, multiplication flavour). -acquire_queue:211-220,kgd_init_interrupts:272-279,kgd_hqd_load:331-332: division byadev->gfx.mec.num_pipe_per_mecwithout a zero check. - Note-only:set_scratch_backing_va:768-776 truncates 64-bit va to 32 bits β upstream-identical code, not a DF divergence. -
In-bounds confirmations (negative results with line evidence) β see README.md: MQD register walks 0x3245..0x326c / 0x326f..0x3278 β vi_structs.h:289-340 exact (max index 51, struct extends to :417); hqd_dump 54+4 exact + WARN_ON_ONCE-guarded; get_tile_config ARRAY_SIZE over fixed arrays (amdgpu_gfx.h:175-176); invalidate_tlbs loop 0..15 gated; set_vm_context_page_table_base / invalidate_tlbs_vmid is_kfd_vmid-gated (vmid 8..15 β +vmid-8 in 0..7).
Why not reproduced / not falsified on the guest
There is no trigger to run: the code is absent from every build and the guest has no AMD hardware (env.txt). A PoC would require (a) adding the file to the build, (b) defining CONFIG_HSA_AMD, (c) porting the KFD frontend, and (d) an AMD gfx8 APU β none of which exist on this system. The verification deliverable is the reachability analysis above plus the hardening diff.
Exploit chain
None β dead code today. On enable-day without the guards: hazards 1-2 give attacker-influenced OOB MMIO read/write (register-space corruption, GPU lockup / potential system instability) from whatever privilege the kfd frontend grants its callers; hazard 3 gives a NULL-deref panic.
Fix
fix.diff (not applied; authored against read-only sys/): vmid<16 guards in kgd_set_pasid_vmid_mapping and both ATC mapping getters; per-case firmware pointer NULL checks before deref; engine/queue bounds in the SDMA MMIO-offset paths. Recommended one-liner: "when enabling KFD add vmid<16, engine/queue bounds and fw NULL checks to the gfx8 kfd backend (fix.diff)".
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_testablefix.diff authored against read-only sys/ as hardening for currently dead code; no runtime validation applicable on this guest (no AMD hardware, file not built)
fix.diff
Confirmed kernel references
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c:245-270
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c:291-300
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c:486-492
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c:702-720
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c:778-833
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd.c:34-47
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd.c:57-71
- sys/dev/drm/amd/amdgpu/amdgpu_amdkfd.c:554-557
- sys/dev/drm/amd/amdgpu/Makefile:155-156
- sys/dev/drm/amd/amdgpu/gfx_v8_0.c:2029-2041
- sys/dev/drm/amd/amdgpu/sdma_v3_0.c:1114-1118
Detail
Evidence (decisive lines)
env.txt (guest: no 0x1002 devices, /dev/dri absent, no drm KLDs; build tree: no Makefile reference, no CONFIG_HSA_AMD); run.log; VERDICT.md (in-bounds confirmations + latent hazards with path:line); fix.diff (vmid<16, engine/queue<2, fw-NULL guards)
PoC changes
not applicable (no trigger exists; verification = dead-code proof + guest device-absence evidence)
Verified recommended fix
when enabling KFD: apply fix.diff guards (vmid<16 in set_pasid_vmid_mapping and both ATC mapping getters, fw-pointer NULL checks before deref in get_fw_version, engine/queue<2 bounds in SDMA paths) and bound the cpu_relax poll with a timeout
Verdict
Info finding verified by source and guest inspection (sibling of DF-4499): the entire gfx8 kfd2kgd backend of amdgpu_amdkfd_gfx_v8.c is dead code on DragonFly β the file is not in any SRCS list (only amdgpu_amdkfd.c is built, Makefile:155-156), CONFIG_HSA_AMD is undefined tree-wide so amdgpu_amdkfd_init() forces kgd2kfd=NULL and device_probe() early-returns, the #ifndef stub provides the linking get_functions(), and no amd/amdkfd frontend exists at all. No PoC is applicable: the unreachability itself is the verified fact; the guest has no AMD PCI device and no /dev/dri. Latent enable-day hazards are documented and guarded by fix.diff: (1) kgd_set_pasid_vmid_mapping unvalidated vmid -> OOB MMIO writes past the 16-entry ATC/IH banks + 1U<
No comments yet.