DF-3891 / verdict.json
{ "finding_id": "DF-3891", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain double free + leak on the allocation-failure path; runtime-inconclusive on this guest (no AMD GPU, and the trigger needs a kzalloc failure mid-parse under memory pressure). kv_parse_power_table (kv_dpm.c:2748-2752) frees adev->pm.dpm.ps at :2750 without clearing the pointer or setting num_ps (assigned only at :2775), then returns -ENOMEM; kv_dpm_sw_init dpm_failed (:3034-3035) calls kv_dpm_fini which kfrees the same pointer again at :2919 (double free -> allocator freelist corruption) while the 0-iteration priv loop leaks every already-parsed ps_priv (:2916-2918). Harness replays the exact sequence: the second free() is accepted silently by the guest allocator (exit=0, no detection, no aliasing in a short probe - reported honestly); in-kernel kfree of a freed block is the classic latent freelist-corruption primitive. Robustness bug: requires OOM timing during driver init on a KV APU, hence Low.", "exploit_chain": "engineer kzalloc failure for a struct kv_ps during amdgpu load (memory pressure) -> kfree(dpm.ps) at :2750 -> return -ENOMEM -> kv_dpm_fini -> kfree(dpm.ps) again at :2919 -> same block twice on the freelist -> two future kernel allocations alias -> heap corruption (timing-dependent, not guest-verifiable).", "evidence": "run.log: kfree(ps) at :2750 (pointer left dangling; num_ps still 0) + kv_dpm_fini: kfree(ps) at :2919 on 0x8004904c0; run.2.log: second free() accepted silently (exit=0), no aliasing observed this run; VERDICT.md; fix.diff", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/kv_dpm.c:2750", "sys/dev/drm/amd/amdgpu/kv_dpm.c:2919", "sys/dev/drm/amd/amdgpu/kv_dpm.c:2775", "sys/dev/drm/amd/amdgpu/kv_dpm.c:3034" ], "poc_changes": "No seed (pass-2 self-authored). Fixed a nested block-comment typo that broke the first guest build; extended crash mode with an aliasing probe after observing the silent second free.", "attempts": 4, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64", "runtime_sec": 90, "guest_dirty": 0, "build_cmd": "cd /tmp/DF-3891 && cc -Wall -O0 -o t h.c", "run_cmd": "cd /tmp/DF-3891 && ./t && ./t crash", "code_hash": "11b6b8d8a7ee53b24c5efac2acb34c5423a6ea3e59d068b02328dc5681ca5b6c", "notes": "Guest virtio-only (no AMD GPU). Userspace free() cannot emulate kmalloc zone freelist effects 1:1; the decisive, honestly-reported observation is that the second free is not detected/failed - in the kernel it corrupts the freelist. Same code exists in Linux amdgpu kv_dpm.c (worth an upstream report).", "recommended_fix": "On kzalloc failure in kv_parse_power_table set adev->pm.dpm.num_ps = i and return -ENOMEM without freeing, so kv_dpm_fini releases the privs and the array exactly once.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree after source+harness verification; not built (no AMD hardware on guest).", "fix_evidence": "findings/poc/DF-3891/fix.diff" } |