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

fiji_get_dependency_volt_by_clk fall-through reads dep_table->entries[count] twice (one-entry heap OOB read)

Summary

When the requested clock exceeds every entry, the loop falls through with i==count and the tail block reads entries[i].vddc and entries[i].mvdd - one entry past the exact-size kmalloc. Sibling reads correctly use entries[i-1]. Hot path; upstream-4.x-carried; value used only as a branch condition - Low. entries[i-1] fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4005 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.5 KB ↓ raw
VERDICT.md β€” 1.4 KB ↓ raw
build.sh β€” 65 B view raw
run.sh β€” 89 B view raw
run.log β€” 3.8 KB view raw
env.txt β€” 493 B view raw
fix.diff β€” 7.7 KB view raw
trigger_analysis.c β€” 17.3 KB view raw

DF-4005 β€” fiji_get_dependency_volt_by_clk fall-through reads dep_table->entries[count] (one-entry heap OOB read Γ—2)

File: sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:404-414 (reads at :406 and :413) Class: kernel heap OOB read (kernleak-class; value used only as a branch condition) Severity: Low Β· Confidence: certain (source) Β· runtime hardware-gated

Build / Run / Expected

Same demonstrator as DF-4001 (./build.sh && ./run.sh, section === DF-4005 ===):

count=3, i=3 after fall-through; entries[i].mvdd reads bytes at +60, 12 bytes past the 3-entry heap object
value read = 0x0001 (poisoned adjacent-slab byte) β€” kernel heap adjacent-slab bytes consumed as a branch condition

Source chain

When the requested clock exceeds every entry (loop :368-396 falls through), i == dep_table->count and the tail block reads - :406 dep_table->entries[i].vddc (inside the vddci lookup), - :413 dep_table->entries[i].mvdd (mvdd condition), both one entry past the kmalloc(count * sizeof(entry)) allocation made in process_pptables_v1_0.c:425-436/378-391. The in-bounds twin reads correctly use entries[i - 1] (:399, :404, :414). The OOB bytes only select whether *mvdd gets set β€” no direct disclosure, but a genuine heap OOB read on the hot per-level voltage path. Carried from the upstream 4.x code as-is.

Fix

fix.diff (shared): use entries[i - 1] at both sites. Compile-validated via nativekernel rebuild (fix_build.log).

VERDICT.md
↓ download raw

VERDICT β€” DF-4005

Status: inconclusive at runtime (hardware-gated); source-certain.

Demonstrated (run.log, section DF-4005): the fall-through tail of fiji_get_dependency_volt_by_clk (fiji_smumgr.c:398-416) executes with i == dep_table->count when the requested clock exceeds every entry; it reads dep_table->entries[i].vddc at :406 and dep_table->entries[i].mvdd at :413 β€” one entry (12 B of a 16 B record) past the exact-size heap allocation made by process_pptables_v1_0.c:425-436/378-391. The demonstrator's poisoned redzone byte (0x0001) shows adjacent-slab content being consumed as the branch condition that decides whether *mvdd is populated. All sibling reads in the same block correctly use entries[i - 1] (:399/:404/:414) β€” an off-by-one carried from the 4.x upstream code. Impact is a bounded kernel heap OOB read with no direct disclosure channel β†’ Low.

Called on every graphics/memory level population (:957, :1181) β€” hot path, not error path. Hardware-gated (env.txt).

Fix: fix.diff uses entries[i - 1] at both sites; nativekernel rebuild OK (fix_build.log), reverted.

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

fixed
baseline no→ patch + rebuild →patched clean

fixed (compile-validated): both diffs applied to clean guest /usr/src (fiji_smumgr.c md5 800babd0..->d50bdc81.., i915_gem_execbuffer.c 334c7bd9..->dc882976..), make nativekernel KERNCONF=X86_64_GENERIC completed with error_count=0 under -Werror (fix_build.log); behavior additionally model-verified for DF-4007 (PATCHED run balanced). Runtime re-test impossible on this guest (no AMD/Intel GPU). Patch reverted after validation.

findings/poc/DF-4005/fix.diff; findings/poc/DF-4001/fix_build.log; findings/poc/DF-4007/run.log (PATCHED model run for DF-4007)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT (nativekernel X86_64_GENERIC, patched, -Werror; see fix_build.log)

Confirmed kernel references

Detail

Exploit chain

crafted vBIOS -> any graphics/memory level population -> get_dependency_volt_by_clk fall-through -> 2x one-entry heap OOB reads consumed as branch conditions

Evidence (decisive lines)

run.log (DF-4005 section: entries[count].mvdd read 12B past the exact-size allocation, poisoned redzone byte consumed as branch condition); VERDICT.md; fix_build.log; env.txt

PoC changes

Pass-2 reviewer authored demonstrator compiling the kernel's own smu73.h/smu73_discrete.h (packed) so sizeof/offsets are the kernel's; fix.diff generated mechanically against the pristine file and compile-validated via full nativekernel rebuild on the guest (shared build with DF-4001..DF-4007).

Verified recommended fix

Use dep_table->entries[i - 1] at fiji_smumgr.c:406 and :413 (fix.diff)

Verdict

Source-certain one-entry heap OOB reads (x2) in the fall-through tail of fiji_get_dependency_volt_by_clk (fiji_smumgr.c:406 entries[i].vddc, :413 entries[i].mvdd with i==dep_table->count after the loop): both read one 16-byte record slot (12 bytes in) past the exact-size kmalloc made by process_pptables_v1_0.c:425-436. Demonstrator shows adjacent-slab bytes (poisoned 0x0001) consumed as the condition deciding whether *mvdd is set. Sibling reads correctly use entries[i-1]; upstream-4.x-carried off-by-one. Hot path (every level population). Bounded read, no direct disclosure -> Low. Hardware-gated: inconclusive at runtime, source-certain.