DF-2695 / verdict.json
{ "finding_id": "DF-2695", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "Unprivileged kernel-stack info leak reproduced: sendfile(2) failing on an early-error path (bad socket fd, non-stream socket, unconnected socket, negative offset) copies out the never-initialized local 'off_t sbytes' (uipc_syscalls.c:1594) to the user's *sbytes pointer on every exit path (uipc_syscalls.c:1677-1680), because kern_sendfile() only zeroes *sbytes after its early error gotos (:1734 vs :1699-1732). Demonstrated stable leak of a kernel virtual address (0xfffff80117c88a40) as unprivileged uid 1001 by seeding the stack slot with a preceding socket(2) call; also captured 0xffffffff809a5db0 on the first-call variant.", "exploit_chain": "unpriv sendfile(valid_file_fd, -1, 0, 0, NULL, &sbytes, 0) -> EBADF -> 8 bytes of stale kernel stack returned in *sbytes; repeatable, includes kernel pointers (KASLR defeat); single stack slot per call, value controllable only via preceding-syscall stack residue.", "evidence": [ "run.log (root + unpriv runs; leak3.c stable KVA leak 0xfffff80117c88a40)", "poc_sendfile.c / leak3.c", "fix.diff + fix_run.log (patched kernel returns 0 on all paths)" ], "kernel_refs": [ "sys/kern/uipc_syscalls.c:1594", "sys/kern/uipc_syscalls.c:1645-1648", "sys/kern/uipc_syscalls.c:1674-1681", "sys/kern/uipc_syscalls.c:1699-1734" ], "poc_changes": "Added a second program (leak3.c): the initial PoC's printf-per-sample re-dirtied the stack slot and masked the leak after the first call; seeding the slot with a preceding socket(2) immediately before sendfile makes the KVA leak stable across samples.", "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": 300, "guest_dirty": 0, "build_cmd": "cc -O2 -o poc_sendfile poc_sendfile.c && cc -O2 -o leak3 leak3.c", "run_cmd": "./poc_sendfile && ./leak3", "code_hash": "9d905ab439c8c9d6d8d04b173a70028f0c37bdb7c4f6a84923641d46dc65c144 (poc_sendfile.c); 3b97269848f74194db2bc9a54205bd6023e19ebfb90e1c91502d95f553eef176 (leak3.c)", "notes": "FreeBSD's counterpart initializes *sbytes early and copies out only on success; the unconditional copyout of an uninitialized local is DragonFly-specific. Impact limited to one 8-byte stack slot per call -> Medium.", "recommended_fix": "Initialize 'off_t sbytes = 0;' in sys_sendfile() (and ideally copy out only when kern_sendfile was reached)", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sun Aug 30 23:56:25 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "One-line fix (off_t sbytes = 0). Patched kernel returns 0 in *sbytes on every early-error path; baseline stable KVA leak gone.", "fix_evidence": [ "fix.diff", "fix_run.log", "run.log" ] } |