DF-2237 / verdict.json
{ "finding_id": "DF-2237", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Verified on stock DFly 6.5-DEVELOPMENT guest: iconv_xlat16_conv line 192 dereferences d_table[c1] without a NULL recheck after case conversion mutates c1/c2 at lines 155-158 (double-byte towlower via armed _wctype pair, fault VA 0xc) and lines 186-189 (single-byte XLAT16_HAS_FROM_LOWER_CASE flag path, fault VA 0x108). Both faults are supervisor READs of NULL plus a 0..0x1fc table-chosen offset. Tables were armed via the real kern.iconv.add sysctl byte format and the conv driven through the exported iconv KPI that msdosfs uses per filename char. Fix guard validated A/B: controls bit-identical, both triggers degrade to ret=-1, no panic.", "exploit_chain": "", "evidence": "panic.txt and t1_boot.log:210 (Fatal trap 12, fault VA 0x108, supervisor read, stopped at iconv_xlat16_conv+0x259 movl (%rdi,%rdx,1),%edi); panic2.txt and t2_boot.log:208 (fault VA 0xc); fix_run.log / fix_dmesg.txt (controls 41 42 / 63 / 12 34 identical pre and post fix, triggers SURVIVED ret=-1); fix.diff (guard before line 192); mmap0_user.log (unpriv user can map page 0 - read hits attacker-owned page, all code sinks are bounded <= 3-byte conversion outputs, so no escalation)", "kernel_refs": [ "sys/libiconv/iconv_xlat16.c:155-158", "sys/libiconv/iconv_xlat16.c:186-189", "sys/libiconv/iconv_xlat16.c:192", "sys/libiconv/iconv_xlat16.c:142", "sys/libiconv/iconv_xlat16.c:163", "sys/libiconv/iconv.c:397-443", "sys/vfs/msdosfs/msdosfs_conv.c:903", "sys/vfs/msdosfs/msdosfs_conv.c:988", "lib/libkiconv/xlat16_iconv.c:258-266" ], "poc_changes": "authored from scratch (no seed pack): armtbl.c registers 3 crafted sparse xlat16 pairs via the real sysctl wire format; df2237_mod.c KLD harness drives the real exported iconv KPI in 3 compile-time modes; KCFLAGS required because sys/conf/kmod.mk:98 resets CFLAGS; first fix-validation attempt hit a stale /usr/obj module picked by find|head -1 plus a Hammer2 rollback after a DDB kill - redone with explicit paths, syncs and hash verification", "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": 2700, "guest_dirty": 0, "build_cmd": "sh /root/df2237/build.sh", "run_cmd": "kldload /boot/kernel/libiconv.ko && /root/df2237/armtbl && kldload /usr/obj/root/df2237/km1/df2237_1.ko", "code_hash": "75fa8d8e60b3b31920aab3015eb48828d31188dbddbe7d112b1b5126362b5891", "notes": "Root-armed local DoS / latent-KPI robustness bug: kern.iconv.add and mounting need root, after which any user walking an msdosfs mount with -C reaches the path per lookup. Real builder only self-triggers on locale/charset divergence (locale tolower targets vs iconv occupancy are independent sources; no _wctype pair is registered at all on locale mismatch, activating the flag path with f_ctp NULL). Escalation closed: READ-only primitive confined to first page; page 0 is user-mappable on this guest so no forced panic and code becomes attacker-chosen, but every sink of code is a bounded <= 3-byte conversion output - no write-what-where, no leak, no uid 0 chain.", "recommended_fix": "guard dp->d_table[c1] == NULL with ret=-1 break immediately before the line 192 load, mirroring the existing line 163 check (see fix.diff)", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 + patched libiconv.ko sha256 30bfdffe7430d3524e832faaa0cdc13622194b0e20022373658982a65f119642", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Single-guard fix.diff applied to guest /usr/src, libiconv.ko rebuilt and hash-verified, disassembly shows test %rdi,%rdi je break before the previously unguarded load. Same armed tables and same harness: control conversions bit-identical (41 42, 63, 12 34), single-byte and double-byte triggers both return ret=-1 with 0 bytes consumed/produced (identical to a normal unconvertible char), zero Fatal traps in the patched boot.", "fix_evidence": "fix_run.log (sha256 line + armed pairs + km0/km1/km2 all load, df2237 dmesg showing SURVIVED ret=-1 for both triggers), fix_build.log (patched module compile+link), fix_boot.log (whole boot, no Fatal trap), fix.diff" } |