DF-2684 / verdict.json
{ "finding_id": "DF-2684", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "sysctl kern.file (CTL_KERN/KERN_FILE) is world-readable: sysctl_root() gates only writes, and sysctl_kern_file_callback (kern_descrip.c:3453-3503) filters by prison only. kcore_make_file (subr_kcore.c:58-77) copies ufile->f_file = kfile and ufile->f_data = kfile->f_data -- raw kernel heap pointers -- into every exported kinfo_file. Unprivileged uid 1001 read 136 entries: 136 carried non-NULL kernel pointers (struct file and vnode/socket addresses) and 120 belonged to other uids including root's fd types/flags/offsets (off=112 on root's password-file read). Pointer disclosure aids KASLR defeat and heap grooming for memory-corruption exploits; cross-uid fd-offset disclosure is an information leak across uid boundaries. Validated fix masks f_file/f_data for uid!=0: post-fix unprivileged read shows 0 pointers while root still sees 143 -- baseline-vs-patched deterministic.", "exploit_chain": "unprivileged sysctl(3) {CTL_KERN, KERN_FILE} -> kernel-heap addresses of every struct file and its vnode/socket + other users' fd offsets; the addresses are direct-map slab pointers usable to defeat KASLR and to aim UAF-reclaim grooming (e.g. for DF-2682-class bugs) -- no further chain needed for the leak itself.", "evidence": [ "run.log: 'entries with kernel pointers: 136 / entries belonging to OTHER uids: 120 / RESULT: LEAK CONFIRMED' as uid 1001", "leak_sample.txt: pointer values across runs (0xfffff8xxxxxxxxxx direct-map slab addresses)", "run_fixed.log: post-fix 'entries with kernel pointers: 0' as uid 1001 and '143' as root", "VERDICT.md: root cause, why sysctl(8) hides it (opaque type), fix validation narrative" ], "kernel_refs": [ "sys/kern/kern_descrip.c:3490", "sys/kern/kern_descrip.c:3453", "sys/kern/kern_descrip.c:3464", "sys/kern/subr_kcore.c:58", "sys/kern/kern_sysctl.c:1427" ], "poc_changes": "Direct sysctl(3) consumer written from scratch (userland sysctl(8) discards CTLTYPE_OPAQUE output, so the seed idea of shelling out to sysctl(8) showed nothing).", "attempts": 1, "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": 90, "guest_dirty": 0, "build_cmd": "cc -O -o kfile_leak kfile_leak.c", "run_cmd": "./kfile_leak", "code_hash": "c421798533927eb911be78a96cef827e284b9cda8e1a90f60bc77a679b98ffcc", "notes": "Fix validated on the patched guest kernel: unprivileged readers get f_file=0x0/f_data=0x0, root unchanged. fix_status=fixed, fix_baseline_reproduced=1, fix_patched_reproduced=0 (leak gone). Upstream may additionally want p_cansee-style row filtering for the cross-uid offset disclosure. Guest reset with-src afterwards.", "recommended_fix": "Mask kinfo_file.f_file/f_data for unprivileged readers in sysctl_kern_file_callback (validated fix.diff); consider p_cansee()-based row filtering for cross-user fd state." } |