{
  "finding_id": "DF-4144",
  "status": "reproduced",
  "verdict": "REPRODUCED via the verbatim-code rig (68 blocks byte-identical to the guests /usr/src/sys; same fidelity proof as DF-4143). Baseline production code with the 2nd per-state kzalloc fault-injected (the kernels genuine allocation-failure path): the verbatim trinity_parse_power_table kfrees rdev->pm.dpm.ps at :1781 without NULLing it, without freeing ps_priv[0..i-1], and with num_ps unset; boot_ps (set at :1705 for the BOOT state parsed before the failure) points into the freed array and the error is swallowed per radeon_pm.c:1448. The unconditional unload path (radeon_pm.c:1705) then runs the verbatim trinity_dpm_fini whose kfree(rdev->pm.dpm.ps) at :2089 frees the pointer a second time -- the rig allocator aborts with RESULT: DOUBLEFREE (96-byte allocation freed twice), and reports state 0s ps_priv (128 B) leaked (num_ps==0 hides it from finis loop). Driving enable instead (the swallowed-error chain): the verbatim trinity_dpm_enable reads boot_ps->ps_priv at :1129 and faults at freed_dpm.ps+40 -- +40 is exactly offsetof(struct radeon_ps, ps_priv), a literal use-after-free read that in-kernel feeds a 92-byte struct copy from freed heap. Gating: no AMD GPU on the audit guest (env.txt); in-kernel consequence is slab freelist corruption (double free) / UAF at driver unload or enable, under the crafted-VBIOS or memory-pressure threat model. fix.diff (error-path unwinding + idempotent fini) A/B-validated on the identical image and injection: no double free, zero leaked allocations, enable returns -EINVAL via the NULLed boot_ps.",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "exploit_chain": "Crafted VBIOS with a BOOT-classified state followed by enough states to hit a per-state kzalloc failure (255 ucNumEntries x 128 B makes that reachable at attach without global pressure) -> trinity_parse_power_table:1781 kfrees dpm.ps (dangling pointer kept; ps_priv[0..i-1] leaked; boot_ps -> freed array) -> radeon_pm.c:1448 swallows -ENOMEM -> unload: radeon_pm.c:1705 radeon_dpm_fini -> trinity_dpm_fini:2089 kfree of the dangling pointer = heap double free (slab freelist corruption -> panic or worse on the next bucket allocation); alternatively enable (radeon_pm.c:1453) -> trinity_dpm_enable:1129 reads boot_ps->ps_priv from freed memory = use-after-free read feeding pi->current_ps copy. No unprivileged-userland trigger: attacker data is the GPU ROM; the kzalloc failure is kernel memory pressure modeled by the rig injector.",
  "evidence": "run.log (mode 4144-doublefree: RESULT: DOUBLEFREE ptr=... 96 bytes freed a 2nd time, rc=89; mode 4144-uaf: RESULT: FAULT addr=...e028 USE-AFTER-FREE ... (+40 bytes in); FIXED: no double free, no leak, enable -EINVAL), run.2.log (stability), build.log (68x identical + DF-4144 fix lines == fix.diff additions (27 lines)), rig/ (sources; trinity_rig.c carries the guarded allocator with fault injection), VERDICT.md, env.txt",
  "kernel_refs": [
    "sys/dev/drm/radeon/trinity_dpm.c:1779",
    "sys/dev/drm/radeon/trinity_dpm.c:1781",
    "sys/dev/drm/radeon/trinity_dpm.c:1806",
    "sys/dev/drm/radeon/trinity_dpm.c:2086",
    "sys/dev/drm/radeon/trinity_dpm.c:2089",
    "sys/dev/drm/radeon/trinity_dpm.c:1705",
    "sys/dev/drm/radeon/trinity_dpm.c:1129",
    "sys/dev/drm/radeon/radeon_pm.c:1448",
    "sys/dev/drm/radeon/radeon_pm.c:1705"
  ],
  "poc_changes": "Seed pack had no runnable PoC (status untested, hardware-gated). Built the verbatim rig from scratch (shared with DF-4143/4145/4146); the novel piece for this finding is the deterministic fault-injecting guarded allocator (fails the nth kzalloc of a chosen size, poisons freed pages PROT_NONE, aborts with rc=89 on double free, reports live allocations for leak evidence) plus the radeon_pm.c:1448/1705 swallow/unload simulations.",
  "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": 150,
  "guest_dirty": 0,
  "build_cmd": "cd rig && sh ./build.sh /usr/src DF-4144",
  "run_cmd": "cd rig && sh ./run.sh",
  "code_hash": "trinity_rig.c a68eb1438bc82fb79063491af6293aeddf208ec2cf4f46f0c6040a1aed69e1a3; trinity_slice_verbatim.c 6afb17099769a0c4c9cd500356a757a12cf22d8e9bd67a710b452236019ba7c6",
  "notes": "The findings UAF-via-boot_ps and double-free-in-fini halves are BOTH demonstrated in separate modes with the same injection. The unwinding order in fix.diff matters: ps_priv[] must be freed while dpm.ps is still allocated (the naive placement reads freed memory -- caught and corrected during A/B). Guest left up and clean: /root/df-trinity removed after artifact retrieval.",
  "recommended_fix": "Unwind all trinity_parse_power_table error paths (free ps_priv[0..i-1], then NULL dpm.ps/boot_ps/uvd_ps after the production kfree) and make trinity_dpm_fini idempotent (ps=NULL, num_ps=0, priv=NULL) -- fix.diff, A/B validated.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "A/B validated in the verbatim rig on the identical crafted image and kzalloc injection: baseline aborts with DOUBLEFREE (rc=89) / UAF fault (rc=88) and leaks 128 B; fixed build unwinds cleanly (allocator: zero live), fini is idempotent, and enable returns -EINVAL via the NULLed boot_ps -- no fault of any class. Kernel-rebuild validation not performed (path executes only on AMD ASICs, absent from this guest); per the verbatim-rig protocol the fixed slice was validated in the same rig.",
  "fix_evidence": "run.log FIXED sections (RESULT: OK (fixed) unwind + idempotent fini, no double free, no leak / no UAF: dangling boot_ps cleared); build.log (DF-4144 fix lines == fix.diff additions (27 lines)); fix.diff"
}