DF-2944 / verdict.json
{ "finding_id": "DF-2944", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "acct_process() (sys/kern/kern_acct.c:195-282) fills a stack-local 'struct acct acct;' field-by-field and vn_rdwr()s all sizeof(acct)=56 bytes to the accounting file (kern_acct.c:276) without zeroing the struct. On x86_64 the struct has 9 bytes of alignment padding no field covers (offsets 22-23 before the 8-byte-aligned ac_btime, and 49-55 after ac_flag), so every accounting record written at every process exit discloses 9 bytes of the exiting thread's kernel-stack residue. Live-verified on the audit guest (DragonFly 6.5-DEVELOPMENT x86_64, stock kernel): 49-50 of 50 records per run carried non-zero padding across 3/3 runs, including pointer-shaped contents (tail pad '78 78 18 01 f8 ff ff' = qword 0xfffff80118787800 in DF KVA space) and natural variance across records. Records are generated by unprivileged exiting processes (records observed with ac_uid=65534), but exposure requires read access to the admin-created accounting file, hence Low severity.", "exploit_chain": "", "evidence": "run.log (full 50-record dump; records 33 & 48 show variance incl. kernel-pointer residue in pad[49:56]); run.2.log (2 further runs, LEAK-CONFIRMED); leak_sample.txt (raw hexdump of /var/acct_leak.dat showing 'ff ff' at offset 0x16 of each 56-byte record and the 2800=50x56 framing); build.log (layout _Static_asserts passed); VERDICT.md for the full narrative", "kernel_refs": [ "sys/kern/kern_acct.c:198", "sys/kern/kern_acct.c:225", "sys/kern/kern_acct.c:276", "sys/sys/acct.h:53", "sys/sys/stat.h:61" ], "poc_changes": "seed sketch rewritten entirely: raw syscall(51) for acct(2) (libc wrapper presence uncertain), _Static_assert proof of struct layout against guest headers, two churn waves (fork + execve) to vary kernel-stack residue, setuid(65534) children to prove unpriv-origin records, in-band b64decode file transfer (vm.sh run_root does not forward stdin)", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026\troot@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC\t x86_64", "runtime_sec": 420, "guest_dirty": 0, "build_cmd": "cc -O -o /tmp/acct_leak /root/poc/acct_leak.c && cc -O -o /tmp/acct_helper /root/poc/acct_helper.c", "run_cmd": "rm -f /var/acct_leak.dat && /tmp/acct_leak", "code_hash": "92d40b55fb9f0697cd43ba4ec3335b60af8baa5a32388248770df934d43c4f9f", "notes": "Accounting disabled and all guest artifacts removed after the runs (guest left up, clean). Fix validation kernel rebuild skipped per contract (Low-severity non-corruption finding; fix is a one-line zeroing provable by inspection of the assignment list at kern_acct.c:225-264).", "recommended_fix": "bzero(&acct, sizeof(acct)) at the top of acct_process() before filling the record (see fix.diff)", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored post-verification (bzero of the record before field assignment zeroes both padding runs; all fields are subsequently overwritten so record semantics are unchanged). Patched-kernel rebuild not performed: Low-severity leak, not a memory-corruption finding, and the fix is provably sufficient by inspection; no fix_run.log/fix_build.log generated.", "fix_evidence": "fix.diff; VERDICT.md 'Fix' section" } |