{
  "finding_id": "DF-5201",
  "status": "reproduced",
  "verdict": "REPRODUCED on the QEMU guest via a KLD driving the real linux_task_alloc (drm.ko) from pure kthreads created with kthread_create(). Every kernel thread that evaluates the current macro gets a task_struct installed at linux_sched.c:88, but the only drop path (linux_task_drop_callback) fires from lwp_exit (kern_exit.c:708-709), which pure kthreads never execute (they exit via kthread_exit -> lwkt_exit, lwkt_thread.c:1684-1744). Baseline: 8/8 exited kthreads left their parked td still carrying the leaked, never-dropped task_struct pointer (8 distinct leaked allocations, addresses never recycled). Suspected escalation to cross-thread current aliasing via recycled tds was investigated and KILLED: lwkt_init_thread (lwkt_thread.c:440) bzeroes the whole struct thread on reuse, so a recycled td always starts clean (observed: rounds where W2 received exactly W1s td entered clean) - the surviving defect is the unbounded permanent leak, one task_struct+spinlock per kernel thread that ever executes drm code (dma_fence_wait/prepare_to_wait/set_current_state/... on irq, callout, syncer, bufdaemon threads).",
  "reproduced": true,
  "impact": "leak",
  "confidence": "certain",
  "exploit_chain": "",
  "evidence": "run.log (baseline, original kernel: 8/8 PARKED: exited td=... still carries td_linux_task=... -> task LEAKED, plus W1/W2 td-recycling rounds entering clean); run_fixed.log (patched kernel: 8/8 exited td=... is clean (task dropped at lwkt_exit))",
  "kernel_refs": [
    "sys/dev/drm/linux_sched.c:58",
    "sys/dev/drm/linux_sched.c:88",
    "sys/dev/drm/include/asm/current.h:44",
    "sys/kern/kern_exit.c:708",
    "sys/kern/lwkt_thread.c:1684",
    "sys/kern/lwkt_thread.c:1740",
    "sys/kern/lwkt_thread.c:440"
  ],
  "poc_changes": "no seed PoC; authored fresh. Fixes during bring-up: sysctl node hw.df5201.test; sys/kthread.h include for kthread_create; ASCII-only comments; added deterministic parked-td metric (read W1s td_linux_task after exit) after the address-recycle indicator proved cpu-migration sensitive (0/8 on both kernels).",
  "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": 10,
  "guest_dirty": 1,
  "build_cmd": "kldload drm; cd /tmp/DF-5201 && make",
  "run_cmd": "kldload /tmp/DF-5201/df5201.ko; sysctl hw.df5201.test=1",
  "code_hash": "3c041c0e2e9f83842a2b43f560f0b967b61fd9f26de71e99a5206a8d3f5784f6",
  "notes": "Distinct from DF-2196 (kthread_runs task_struct): different alloc site (linux_task_alloc via the current macro), different trigger (any non-drm kernel thread touching drm code, no kthread_run involved). The same bzero that kills the aliasing also bounds DF-2196s dangling-pointer consequence - useful pass-2 intel. mm refcount protocol audited and found balanced for user threads (task ref + proc ref, ordered drops at kern_exit.c:708-711).",
  "recommended_fix": "Hook lwkt_exit() to call linux_task_drop_callback when td_linux_task is set (mirrors the lwp_exit hook), in the may-block cleanup region after dsched_exit_thread().",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff adds the lwkt_exit() drop hook; X86_64_GENERIC kernel rebuilt with it and booted: baseline (original kernel) 8/8 exited kthreads left leaked task_structs on their parked tds; patched 8/8 clean (task dropped at lwkt_exit), leak gone.",
  "fix_evidence": "run.log (baseline 8/8 task LEAKED) vs run_fixed.log (8/8 task dropped at lwkt_exit); objdump of lwkt_exit in the rebuilt kernel shows the td_linux_task check + linux_task_drop_callback indirect call"
}