⬢ DragonFlyBSD Kernel Audit
DF-3891 / verdict.json
← back to finding ↓ download raw
{
  "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"
}