DF-4884 / verdict.json
{ "finding_id": "DF-4884", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Double-free of adev->bios when amdgpu_get_bios() fails: all five live VBIOS read methods kfree(adev->bios) without NULLing it (amdgpu_bios.c:116,145,185,354,428); the probe-failure teardown path amdgpu_kms.c:245 -> amdgpu_device_fini() -> unconditional kfree(adev->bios) (amdgpu_device.c:2762) frees the dangling pointer a second time (adev->rmmio is already mapped at amdgpu_device.c:2473, so the rmmio==NULL bypass is not taken). Deterministic given the precondition (AMD GPU whose VBIOS fails all six read methods: GPU-passthrough VM with garbage ROM BAR, crafted VFCT/ATRM ACPI, disabled ROM shadow). NOT reproduced on the audit guest: it has no AMD PCI device (env.txt: zero vendor-0x1002 devices; only QEMU std-VGA 0x1234), so amdgpu never attaches and the probe path is unreachable by construction. Every hop of the chain is verified by source trace in VERDICT.md; no runtime claim is made beyond that.", "exploit_chain": "", "evidence": "VERDICT.md (full path:line trace of both frees and the teardown chain); env.txt (guest PCI inventory proving hardware absence); trigger.sh + run.log (precondition check output); fix.diff (git-apply-clean fix, NULLs adev->bios at all 5 live kfree sites)", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:116", "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:145", "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:185", "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:354", "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:428", "sys/dev/drm/amd/amdgpu/amdgpu_bios.c:446", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2473", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2536", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2762", "sys/dev/drm/amd/amdgpu/amdgpu_kms.c:99", "sys/dev/drm/amd/amdgpu/amdgpu_kms.c:245", "sys/dev/drm/amd/amdgpu/cik.c:922", "sys/dev/drm/amd/amdgpu/vi.c:406", "sys/dev/drm/amd/amdgpu/soc15.c:236" ], "poc_changes": "n/a \u2014 no seeded PoC code existed; the bug is probe-time and hardware-preconditioned, so the pack carries a precondition checker + exhaustive trace instead of a runnable local trigger", "attempts": 1, "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": 30, "guest_dirty": 0, "build_cmd": "none (no AMD hardware on guest; see trigger.sh)", "run_cmd": "./trigger.sh", "code_hash": "", "notes": "Guest has amdgpu.ko available but zero AMD PCI devices; kldstat shows it unloaded. Bug mirrors upstream Linux (same kfree-without-NULL pattern in drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c + unconditional kfree in amdgpu_device_fini). Same-bug family as the known ATRM pair (DF-1950/DF-1951) but a distinct defect: lifetime bug on the failure path, not an ACPI-return-validation bug.", "recommended_fix": "Set adev->bios = NULL after every kfree(adev->bios) failure-site in amdgpu_bios.c (5 live sites) so amdgpu_device_fini()s unconditional kfree sees NULL \u2014 see fix.diff", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff verified git-apply --check clean against pristine sys/; correctness by inspection (NULLing breaks the only dangling path; no consumer of adev->bios exists between amdgpu_get_bios() failure and the fini kfree \u2014 amdgpu_atombios_init() is only reached on success at amdgpu_device.c:2542). A/B kernel-build validation impossible on this guest: no AMD hardware to reproduce the baseline.", "fix_evidence": "findings/poc/DF-4884/fix.diff (5 hunks, all +adev->bios = NULL)" } |