{
  "finding_id": "DF-5007",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "tpm20_read() stops the discard-buffer callout at tpm20.c:78 BEFORE the sc->owner_tid check at :80-83, so a read(2) that fails EPERM still permanently disarms the only 0.5s recovery that clears pending_data_length; every later write(2) then blocks forever in the cv_wait loop at tpm20.c:126-127, and DragonFly cv_wait carries no PCATCH (kern_condvar.c:23-25,41) so the sleeper survives SIGKILL. Verified on the guest with the stock tpm20.c compiled verbatim into a KMOD harness (no physical TPM in the QEMU guest): victim stuck in state D1 on wchan TPM buff minutes after SIGKILL, device wedged for fresh processes until reboot, kernel alive (dos). Root-only trigger (/dev/tpm0 is 0600 root:wheel) -> severity Low.",
  "exploit_chain": "",
  "evidence": "run.log (POC_RC=42, RESULT: VICTIM 1010 STILL STUCK AFTER SIGKILL, dmesg shows exactly 2 discard msgs, none after the EPERM read); run.2.log (fresh process wedges at its first write: persistence; ps shows pids 1010/1038 state D1/D3 wchan TPM buff); fix_run.log (patched module: victim write completes rc=12, no stuck poc); build.log (stock tpm20.c sha256 b3eea3... provenance); VERDICT.md (full narrative + root-cause chain)",
  "kernel_refs": [
    "sys/dev/crypto/tpm/tpm20.c:78",
    "sys/dev/crypto/tpm/tpm20.c:80-83",
    "sys/dev/crypto/tpm/tpm20.c:126-127",
    "sys/dev/crypto/tpm/tpm20.c:137-141",
    "sys/dev/crypto/tpm/tpm20.c:147-166",
    "sys/dev/crypto/tpm/tpm20.h:88-95",
    "sys/kern/kern_condvar.c:23-25,41",
    "sys/dev/crypto/tpm/tpm_crb.c:384-402"
  ],
  "poc_changes": "Seed PoC concept kept; harness fixes required: (1) KMOD needed generated interface headers (device_if.h/bus_if.h/acpi_if.h copied from /usr/obj kernel tree); (2) first harness build crashed in the stock device_printf(sc->dev,...) at tpm20.c:164 because sc->dev was unset - real backends set it at attach; fixed by sc->dev = root_bus; (3) run.sh kldload made idempotent (|| true); (4) poc output redirected to a file for the fixed run because the unkillable victim holds ssh pipes open.",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 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": 2100,
  "guest_dirty": 1,
  "build_cmd": "sh /root/df5007/build.sh  (cp stock /usr/src/sys/dev/crypto/tpm/tpm20.c; make -m /usr/share/mk; cc -O2 -o poc poc.c)",
  "run_cmd": "kldload /root/df5007/hangsim.ko; sh /root/df5007/run.sh  (expect POC_RC=42; guest stays up)",
  "code_hash": "1ca60c5f79501874933be879b09f8fc05cfdf549ffee3ab88efc4d4b18d89b38 (poc.c), ef030c8e803d5682ec8aef1768fd50ac0390465cb5cd7b813565985b18b65370 (hangsim.c)",
  "notes": "tpm20.c is KMOD-only (not in X86_64_GENERIC), so fix validation was done at module level: fix.diff applied inside guest /usr/src, hangsim.ko rebuilt from the patched file (copied sha256 e132b7c3... recorded in fix_build.log), rebooted, same poc binary re-run. Also considered and downgraded (not filed): make_dev-before-si_drv1 NULL window (tpm20.c:203-205), dangling owner_tid thread pointer reuse (tpm20.c:121/140).",
  "recommended_fix": "Move callout_stop(&sc->discard_buffer_callout) in tpm20_read to after the owner_tid check (inside dev_lock), and make the write-side wait interruptible via cv_wait_sig.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applied to guest /usr/src/sys/dev/crypto/tpm/tpm20.c (3 hunks: callout_stop moved after the owner check inside dev_lock; cv_wait_sig in tpm20_write and in the harvest loop); hangsim.ko rebuilt from the patched file (sha256 e132b7c3... in fix_build.log), guest rebooted, module freshly loaded, identical poc binary re-run: ARM2 non-owner read still EPERM (no semantic regression) but the discard timer keeps firing (6 dmesg discard msgs); the victim write COMPLETED rc=12, victim exited cleanly (waitpid w=830 st=0), no stuck process. Baseline 2/2 wedge vs patched 1/1 clean.",
  "fix_evidence": "fix_run.log (patched run: victim exits, NO_STUCK_POC), run.log (baseline wedge), fix_build.log (patched tpm20.c provenance sha256), VERDICT.md Fix validation section"
}