DF-4247 / verdict.json
{ "finding_id": "DF-4247", "status": "reproduced", "reproduced": true, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED via the DF-4165 verbatim-rig evidence class: the ENTIRE production parser (processpptables.c:37-1706, checker-proven byte-identical on the guest against /usr/src/sys, the tree its running kernel was built from) compiled into a harness and driven with crafted PowerPlay tables. 10/10 defect modes faulted at exactly the predicted offsets in verbatim code: u16 sub-table offsets dereferenced at base+0xFF00 (65280B past a 128B image), u8 entry-count copy loops reading linearly past the image, u8 record indices reaching +65025 (nonclock/clockinfo/uvd/vce), both one-past state-index guards (> at :913/:937, <= at :784), and the fw_info==NULL deref at :1066 (NULL+2). The leak leg is proven byte-exact: with ucNumEntries=40 and 5 records in image, 70/70 dyn_state field values equal the memory bytes past the table image -- kernel-heap info leak surfaced to userland via powerplay sysfs. Fix A/B-validated in the same rig: with fix.diff applied, all 10 modes are clean (offsets skipped, counts clamped to entries-that-fit, off-by-one rejected, indices clamped, NULL checked), 0 leaked values, and a fully valid table parses identically (no regression). Verification also found and fixed two compile bugs in the pre-verification fix.diff (numEntries->ucNumEntries at get_clock_voltage_limit; integer passed as const void* clock_info twice). In-kernel execution remains AMD-ASIC-gated on this guest (no 0x1002 device): threat model = crafted/corrupt VBIOS at driver attach or root-written pp_table sysfs re-parse; no unprivileged trigger on stock hardware. Recorded impact leak (proven ceiling of this files source-read defects; the downstream fixed-array write overflows are separate sink findings per the findings coverage assessment).", "exploit_chain": "crafted VBIOS PowerPlay table (flashed ROM / vfio-pci romfile / malicious device) -> amdgpu attach on smu7/smu8 -> pp_tables_initialize + pp_tables_get_entry/VCE getters -> OOB reads up to +65280 past the ~2-4KB soft_pp_table kernel heap image -> leaked bytes stored 1:1 in hwmgr->dyn_state clock/voltage tables -> readable by userland via pp_dpm_* sysfs (proven 70/70 byte-exact in rig); plus NULL-deref panic path when the ROM lacks FirmwareInfo. No unprivileged local trigger; no write primitive in this file.", "evidence": "run.log/run.2.log/run.3.log: 10/10 baseline SIGSEGVs classified with fault offsets (65280 vs 128; 146 vs 144; 142 vs 141; 136 vs 136; 65227 vs 242; 65187; 1662 vs 134; NULL+2) and 70/70 leak values byte-exact; fix_validation.log: FIXED half clean on identical inputs; build.log: ALL VERBATIM CHECKS PASSED (23 blocks vs /usr/src/sys) + both binaries; env.txt: guest uname, host<->guest SHA256 equality, no-AMD-GPU proof; rig/: gen_rig.sh/check_verbatim.sh/Makefile/pp_rig.c/rig_shims.h.", "kernel_refs": [ "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:61", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:383", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:784", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:827", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:875", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:913", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:923", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:929", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:937", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1062", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1099", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1122", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1279", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1304", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1379", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1473", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1520", "sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1571", "sys/dev/drm/amd/powerplay/amd_powerplay.c:672" ], "poc_changes": "Replaced the hardware-gated untested verdict with the DF-4165 verbatim-rig protocol: whole-file parser slice (37-1706) + 22 verbatim header slices, guard-page/canary harness with SIGSEGV classifier, 13 modes; built and run on the guest against /usr/src. Fixed two compile bugs in the packs own fix.diff (numEntries->ucNumEntries; const void* casts). Removed the stale hand-written processpptables_fixed.c (superseded by the checker-proven generated fixed slice).", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 420, "guest_dirty": 0, "build_cmd": "cd rig && sh ./build.sh /usr/src (check_verbatim + make -> rig_base, rig_fixed)", "run_cmd": "cd rig && sh ./run.sh (13 modes x baseline/fixed; see run.log, run.2.log, run.3.log)", "code_hash": "832d140e81104bcfd23e9bac0958e09d2d4cf16a50f88f642316f023af1a5cc0", "notes": "Verbatim-rig evidence class (DF-4165 precedent): production instructions, production struct layouts, out-of-kernel context. Off-by-one modes exercised by direct one-past calls (stock caller stays in range) - latent wrong-guard defects. clockinfo-index fault lands in the clock-info callback (harness mimics the smu7/smu8 deref). In-kernel run impossible: no AMD ASIC on guest (env.txt). Guest left up and clean (only /root/df4247 + /tmp artifacts).", "recommended_fix": "central pp_table_range_ok/pp_table_clamp_count layer exactly as in fix.diff (this packs corrected version), plus fw_info NULL check, >->>= off-by-one guards and get_state_entry_v2 <=-><", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "A/B in the same rig on identical crafted inputs: baseline (verbatim) faults 10/10 and leaks 70/70; slice+fix.diff is clean 10/10, clamps counts to entries-that-fit, rejects one-past indices, NULL-checks fw_info, leaks 0 values, and parses a valid table identically. Kernel-rebuild validation N/A on this guest (AMD-ASIC-gated path); fix.diff applies to the pristine tree with patch --fuzz=0 and reverse-applies byte-exactly.", "fix_evidence": "fix_validation.log (full FIXED half of the decisive run); build.log (bidirectional patch proof lines); VERDICT.md section 3; the two compile corrections made to fix.diff during verification are listed in README.md." } |