⬢ DragonFlyBSD Kernel Audit
DF-5639 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5639",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED (panic): sys_set_tls_area(2) performs no canonicality validation of the user-supplied 64-bit tls_info.base (sys/platform/pc64/x86_64/tls.c:100-108) and set_user_TLS() programs it directly into MSR_FSBASE/MSR_KGSBASE via wrmsr (tls.c:163-171). WRMSR with a non-canonical FS.base/GS.base raises #GP(0) in kernel mode (Intel SDM Vol.3 17.17), a fatal trap: any unprivileged user calling set_tls_area(0, {base=0x0000800000000000, size=-1}, 16) panics the kernel instantly (Fatal trap 9 ... Stopped at set_user_TLS+0x68: wrmsr; RIP 0xffffffff80bd4c48 = the MSR_FSBASE wrmsr, identified by objdump of the guest kernel). Deterministic single-syscall repro as uid 65534 on a fresh vm.sh reset boot; guest halted in DDB. The same unvalidated value is also installable through vmspace_ctl(VMSPACE_CTL_RUN) because pc64 cpu_sanitize_tls() (machdep.c:924-928) is a no-op. Ceiling is a reliable unprivileged local kernel panic (DoS): #GP is a fixed fault with no write primitive and no resumable path, so no uid=0 route exists. fix.diff (canonicality check in sys_set_tls_area + real validation in cpu_sanitize_tls) was built in-guest (make nativekernel), installed, rebooted: PoC now returns -1/EINVAL with the guest healthy, the full boundary matrix passes, and normal TLS (rtld of every freshly execd binary, round-trip, fork inheritance, exec reset) is unchanged.",
  "exploit_chain": "unprivileged user -> syscall(472, 0, {base=0x0000800000000000, size=-1}, 16) -> sys_set_tls_area stores td_tls.info[0] (tls.c:106) -> set_user_TLS writes pcb_fsbase (tls.c:163) -> wrmsr(MSR_FSBASE, non-canonical) (tls.c:167) -> #GP(0) in kernel mode inside crit section -> trap_fatal -> Fatal trap 9 -> kernel halts in DDB. Stop at panic: no memory-corruption primitive exists (#GP is a fault, not a controlled write), impact ceiling = permanent unprivileged local DoS of the whole system.",
  "evidence": "panic.txt (Fatal trap 9 console capture, current process = PoC pid, Stopped at set_user_TLS+0x68: wrmsr); run.log (baseline PoC run: output stops at the syscall, ssh dead); run.2.log (patched kernel: same PoC returns -1/EINVAL, guest up, gs-variant also EINVAL); run.3.log (patched full tls_edge.c matrix, completes end-to-end with noncanon->EINVAL and all legitimate TLS behavior intact); fix.diff (two hunks: tls.c + machdep.c cpu_sanitize_tls); build.log (patch applied in-guest, nativekernel build, install, reboot); env.txt (uname, QEMU/KVM on Intel host).",
  "kernel_refs": [
    "sys/platform/pc64/x86_64/tls.c:100-108",
    "sys/platform/pc64/x86_64/tls.c:163-171",
    "sys/platform/pc64/x86_64/machdep.c:924-928",
    "sys/vm/vm_vmspace.c:293-307",
    "sys/platform/pc64/x86_64/swtch.s:515-535"
  ],
  "poc_changes": "No seed PoC existed (pass-2 discovery). tls_noncanon.c written from scratch as a minimal single-syscall trigger; syscall number taken from sys/sys/syscall.h (SYS_set_tls_area=472); output uses raw write(2) because libc errno is %fs-relative and dies once a wild base is installed (that quirk itself is what produced the first, user-mode SIGSEGV harness iteration).",
  "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 (baseline); patched fix-kernel #1: Fri Oct  9 03:00:09 UTC 2026",
  "runtime_sec": 2,
  "guest_dirty": 0,
  "build_cmd": "cc -O1 -o /tmp/tls_noncanon /tmp/tls_noncanon.c   (fix kernel: cd /usr/src && patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel)",
  "run_cmd": "su -m nobody -c /tmp/tls_noncanon   # baseline: Fatal trap 9 at set_user_TLS+0x68 (wrmsr); patched: -1/EINVAL, no panic",
  "code_hash": "979af9bf98d2897ed282169cdcb186ec3d2d50bd2c228439305412f8f67c411c",
  "notes": "Discovered during pass-2 boundary-matrix testing of the syscall-gate checklist item (b) (can a user craft a descriptor that escapes the intended %fs/%gs semantics). GSBASE variant (which=1) equally affected and equally fixed. vmspace_ctl variant requires vm.vkernel_enable=1; syscall-472 route is unconditional. QEMU/TCG note: on emulation without the WRMSR canonical check the install may succeed and only user-mode %fs/%gs accesses fault; on real Intel (and this KVM guest) the kernel-mode #GP fires inside the syscall. Host was GenuineIntel + KVM, so the panic is the native-CPU behavior.",
  "recommended_fix": "Validate canonicality of info.base in sys_set_tls_area (return EINVAL) and implement the same check for both savetls bases in pc64 cpu_sanitize_tls so the vmspace_ctl route is covered (see fix.diff).",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Fri Oct  9 03:00:09 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fixed: baseline kernel panics at set_user_TLS+0x68 (wrmsr) on the PoC; patched kernel returns -1/EINVAL for both fs and gs non-canonical bases, guest stays up, full boundary matrix passes, and all legitimate TLS semantics (round-trip, fork inheritance, exec reset, rtld TLS bootstrap of fresh binaries) are preserved.",
  "fix_evidence": "run.2.log and run.3.log (patched runs, no panic; set fs noncanon rc=-1 errno=22); build.log (patch application, nativekernel build completion NATIVEKERNEL_DONE/INSTALL_DONE, rebooted kernel uname #1: Oct 9 03:00:09); contrast run.log/panic.txt (baseline Fatal trap 9)."
}