{
  "finding_id": "DF-2952",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "Every exec of a resident-registered binary forks the registration snapshot (whose vm_map contains the registering process's COW stack entry at [USRSTACK-maxssiz, USRSTACK)) and then vm_map_stack() for the same range fails with KERN_NO_SPACE because on pc64 USRSTACK == VM_MAX_USER_ADDRESS leaves no room; exec_resident_imgact (imgact_resident.c:185) discards the error, so the exec runs on the stale snapshot stack. An unprivileged user who execs the binary reads the registration-time (root) process's stack contents: 5/5 iterations leaked ~7600 marker hits (~140 KB unique root-env data), ~300 B even with a small root env, 0 hits after unregistering (control). The guest stayed healthy (INVARIANTS kernel). Fix validated: vm_map_remove() of the snapshot stack region + error propagation; patched kernel rebuilt in-guest, 0 hits 3/3, resident exec still functional.",
  "exploit_chain": "root runs 'resident <prog>' (SYSCAP_NOVM_RESIDENT) -> rtld calls exec_sys_register() from the root invocation (root env strings + rtld/libc frames on its stack) -> vmspace_fork snapshots the whole address space incl. stack (imgact_resident.c:236) -> any user execs the binary -> exec_new_vmspace forks the snapshot; vm_map_stack fails KERN_NO_SPACE (kern_exec.c:991, vm_map.c:4001-4046, pc64 USRSTACK==VM_MAX_USER_ADDRESS); error swallowed (imgact_resident.c:185) -> process runs on stale COW stack -> unprivileged process scans its own stack below/above SP and recovers the root registration run's stack contents (env strings, rtld frames, auxv region).",
  "evidence": "run.log (fresh pristine-guest decisive run: 7603 hits, RESULT: LEAK, exit 42); run.2.log/iter.log (5 iterations, 7603/7615/7601/7616/7580 hits, hit addresses logged); run.oneshot.log (small-payload variant, 11 hits; and unregister control, 0 hits); fix_run.log (patched kernel: 3/3 zero hits, resident -l shows registration, binary runs normally); fix_build.log (make -j6 nativekernel rc=0, -Werror clean); VERDICT.md (full narrative); env.txt",
  "kernel_refs": [
    "sys/kern/imgact_resident.c:185",
    "sys/kern/imgact_resident.c:236",
    "sys/kern/kern_exec.c:949",
    "sys/kern/kern_exec.c:956",
    "sys/kern/kern_exec.c:959",
    "sys/kern/kern_exec.c:991",
    "sys/vm/vm_map.c:4001",
    "sys/vm/vm_map.c:4042",
    "sys/vm/vm_map.c:3725",
    "sys/vm/vm_map.c:3865",
    "sys/vm/vm_map.c:4298",
    "sys/vm/vm_map.c:1546",
    "sys/platform/pc64/include/vmparam.h:142",
    "libexec/rtld-elf/rtld.c:675",
    "usr.sbin/resident/resident.c:148"
  ],
  "poc_changes": "Seed sketch assumed the registered program could place markers via its own code before exec_sys_register; in the stock flow registration happens inside rtld BEFORE main runs, so the markers had to be delivered through the root registration environment instead (poisoned DF2952_SECRET_* env). Scanner rewritten with SIGSEGV/siglongjmp page guards and both directions (below and above SP); discovered above-SP hits vary 0..30 with kern.stackgap_random=1024 while below-SP hits (~7600) are the stable bulk. One-shot script kept for documentation; iter.sh is the decisive driver.",
  "attempts": 12,
  "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": 300,
  "guest_dirty": 0,
  "build_cmd": "cc -O0 -o /tmp/df2952/victim /tmp/df2952/victim.c",
  "run_cmd": "sh /tmp/df2952/iter.sh 1   # root: registers with poisoned env, then: su -m nobody -c 'env -i /tmp/df2952/victim leakcheck'",
  "code_hash": "7d54931a69ed5052efe9e546047769635d50a6303210cd055a52e13a6f58be02",
  "notes": "Pass-2 context: known findings DF-0182/0183/0184 re-verified present in source (uninit xresident at :148 with error-path/padding variants; tsleep-wchan UAF at :291-311; lockless exec_res_id reads at :138/:143) - not re-reported. Negative results this pass: vnode-recycle stale v_resident impossible (allocvnode reuses only auxref-free vnodes and bzero()s them, vfs_lock.c:1170-1200); vget on reclaimed held vnode returns ENOENT not panic (vfs_lock.c:598); vmspace_exec forks rather than refs so no double-ref at exec (vm_map.c:4310); register has no fallible steps after vhold (M_WAITOK infallible) so no unwind leak; vr_refs handshake vs unregister is properly lock-serialized (only the known DF-0183 tsleep-wchan issue); exec_new_vmspace error swallow matches imgact_elf.c:706 style; exec_res_id int wrap needs 2^31 registrations (infeasible); fill_xresident res_file-tail/padding uninit is subsumed by DF-0182. Guest reset to with-src snapshot after fix validation.",
  "recommended_fix": "exec_new_vmspace(): vm_map_remove(map, stack_addr, USRSTACK) of the forked snapshot's stack region before vm_map_stack(); exec_resident_imgact(): propagate exec_new_vmspace() failure instead of returning 0 (see fix.diff)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Fri Sep  4 01:03:31 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applied to guest /usr/src; make -j6 nativekernel KERNCONF=X86_64_GENERIC rc=0 (-Werror clean, fix_build.log); make installkernel + reboot into #1 Fri Sep 4 01:03:31; identical PoC procedure: registration succeeds (resident -l lists id 1), resident exec succeeds (victim runs, argv parsed, exit 0), marker scan 0 hits in 3/3 iterations plus one extra confirmation (fix_run.log). Baseline 5/5 x ~7600 hits -> patched 3/3 x 0 hits. Guest reset to with-src afterwards.",
  "fix_evidence": "fix.diff, fix_build.log, fix_run.log"
}
