{
  "finding_id": "DF-2234",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "The stack overflow is real: iconv_register_cspair stores names of unbounded length (no ICONV_CSNMAXLEN check anywhere in the kernel registration path) and iconv_sysctl_cslist strcpy-copies them into the char[31] cs_to/cs_from fields of an on-stack struct iconv_cspair_info at iconv.c:368-369. After a KLD registered 200-byte names through the exported iconv_add(), an unprivileged user (uid 1001) reading kern.iconv.cslist panicked the kernel: Fatal trap 9 with frame pointer 0x4242424242424242 stopped at iconv_sysctl_cslist+0xf7 ret, i.e. the name bytes smashed saved RBP and the return path (kernel modules are built -fno-stack-protector). The trigger is fully unprivileged and even fires during the oldptr==NULL sizing pass of any sysctl read. However the ARMING side is gated: kern.iconv.add writes require root (kern_sysctl.c:1447) and its strlen checks reject names >= 31, and every in-tree composer (iconv_ucs_init constants, mount helpers, 31-byte mount-arg fields) is bounded. So on this tree no unprivileged path registers an over-long name; the bug is a latent kernel stack-overflow primitive that any kernel-side caller of iconv_add arms and any user then triggers. privesc_candidate false: impact is privileged-arm / unprivileged-trigger DoS, severity Low as filed. Fix validated A/B on a rebuilt patched module: longcs registration now fails with EINVAL, the 30/31 boundary is unchanged, and the unprivileged read returns the bit-identical control listing with no panic.",
  "exploit_chain": "",
  "evidence": "panic.txt: serial capture showing Fatal trap 9, frame pointer 0x10:0x4242424242424242, Stopped at iconv_sysctl_cslist+0xf7 ret, immediately after user maxx ran csread. run.log: boundary proofs (30 chars register as csid 3, 31 chars EINVAL, unprivileged write EPERM), the clean 240-byte control listing, the longcs load message (registered 200-byte charset names) and the full fix A/B outputs.",
  "kernel_refs": [
    "sys/libiconv/iconv.c:368",
    "sys/libiconv/iconv.c:369",
    "sys/libiconv/iconv.c:179",
    "sys/libiconv/iconv.c:382",
    "sys/sys/iconv.h:64",
    "sys/kern/kern_sysctl.c:1321",
    "sys/kern/kern_sysctl.c:1447"
  ],
  "poc_changes": "No seed pack existed; built from scratch. longcs.ko registers the long pair via the exported iconv_add (converter UTF-16BE so stock libiconv.ko suffices); csread.c performs the unprivileged read (works even as a sizing probe since sysctl_old_user returns 0 with oldptr NULL); addtest.c proves the 30/31 boundary and the privilege gate.",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 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": 600,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh (guest root): cd /root/rig2234 && make; cc -O -o csread csread.c; cc -O -o addtest addtest.c",
  "run_cmd": "sh run.sh (guest root): kldload libiconv; addtest 30; addtest 31; su maxx csread (control); kldload /root/rig2234/longcs.ko; su maxx csread (trigger)",
  "code_hash": "31d61d4ae9b80eb0b31699334b663fd9b96c713490fe42e09c0951939813b404",
  "notes": "Team directive answered: DF-2234 is a kernel stack overflow with attacker-chosen bytes, but the registration of an over-long name cannot be performed by an unprivileged user on this tree (sysctl-write privilege gate plus strlen checks; all in-tree composers bounded), so it is NOT an unpriv-to-root candidate; impact ceiling is privileged-arm / unpriv-trigger panic. privesc_candidate false.",
  "fix_status": "fixed",
  "fix_notes": "fix.diff: iconv_register_cspair rejects strlen(to) or strlen(from) >= ICONV_CSNMAXLEN with EINVAL (single choke point for every registration path including KLD callers); iconv_sysctl_cslist uses strlcpy bounded to sizeof(csi.cs_to)/sizeof(csi.cs_from). Validated: longcs now fails to load (iconv_add error 22), 30-char registration still succeeds, 31 still EINVAL, unprivileged cslist read returns the bit-identical control listing, no panic.",
  "recommended_fix": "Bound charset names at registration (reject >= ICONV_CSNMAXLEN in iconv_register_cspair) and copy them out with strlcpy in iconv_sysctl_cslist."
}
