DF-5408 / verdict.json
{ "finding_id": "DF-5408", "status": "reproduced", "verdict": "Reproduced as a validation bypass: sys_sigreturn strips PSL_VM_UNSUPP from the copy it validates (cpu_regs.c:366-369) but bcopy()s the raw mc_rflags into the trapframe (cpu_regs.c:441), so a guest user installs a VM-set rflags that EFL_SECURE exists to reject (proven: baseline accepts the poisoned frame and survives; fixed kernel prints sigreturn: rflags = 0x20206 and EINVALs the identical input). The bit provably survives both the vkernels and the hosts cpu_sanitize_frame into the host return-to-user path. On this rigs CPU (Skylake/KVM) VM at iretq/sysret is silently masked, so no fault manifests; per SDM other implementations #GP at the doreti iretq (DF-5335 special case), reachable from an unprivileged in-vkernel user. Impact recorded as none because no fault, leak, or escalation is realizable on the tested hardware.", "reproduced": true, "impact": "none", "confidence": "certain", "exploit_chain": "guest user -> signal handler poisons uc_mcontext.mc_rflags |= 0x20000 -> sigcode trampoline SYS_sigreturn -> EFL_SECURE sees stripped copy, raw mcontext installed into go_user trapframe -> host vmspace_ctl(RUN) -> host cpu_sanitize_frame whitelists 0x20000 (mask 0x274dd5) -> host return-to-user loads rflags with VM -> hardware masks it here (SDM: #GP(0) at iretq elsewhere). Ceiling on this rig: silent masking; on enforcing hardware: guest-triggered kernel-mode #GP on the doreti/espfix path.", "evidence": "run_suite.log (baseline: mode1 SURVIVED sigreturn = bypass), run_fixed.log (fixed: sigreturn: rflags = 0x20206 + process terminated, mode0 unchanged), disasm_vk_baseline.txt (and ~0x20000 check-strip + 0xc8 raw bcopy), disasm_host.txt (host mask 0x274dd5), disasm_vk_fixed.txt (mask 0x254dd5), iretvm.c (hardware probe with working control), vmflag.c modes 0/1/2/5/6", "kernel_refs": [ "sys/platform/vkernel64/x86_64/cpu_regs.c:366", "sys/platform/vkernel64/x86_64/cpu_regs.c:369", "sys/platform/vkernel64/x86_64/cpu_regs.c:425", "sys/platform/vkernel64/x86_64/cpu_regs.c:441", "sys/platform/pc64/x86_64/machdep.c:916", "sys/platform/pc64/x86_64/machdep.c:1040" ], "poc_changes": "Seed was a source-analysis only; wrote vmflag.c (modes 0/1/2/5/6: control, sigreturn-poison, vmspace_ctl RUN frames, signal storms), iretvm.c CPL3 iretq hardware probe (two earlier revisions were defective: 4-slot frame and stack skew; final uses the correct 5-slot long-mode iretq frame), the vkernel build/image/run rig adapted from DF-5337, and fix.diff generated with diff -u against the pristine tree.", "attempts": 6, "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": 3900, "guest_dirty": 1, "build_cmd": "sh build_kernel.sh; sh build_image.sh (vmflag: cc -static -O2 -pthread)", "run_cmd": "sh run_suite.sh baseline # then: cd /usr/src && patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=VKERNEL64 && sh run_suite.sh fixed", "code_hash": "ca21e7001a7df69bdf6f37d3e91230e33bd5f3a4560886334b8d2ca3aee1fae0", "notes": "Same code shape exists in pc64 sys_sigreturn (host side) \u2014 verified by disassembly of the running guest kernel; the fix.diff covers both. Mode 5 (poisoned sigreturn + SIGUSR2 storm) survives on both baseline and fixed: DragonFlys sigreturn-exit does not re-check pending signals (mask restore without signotify) and the quickret SYSRETQ masks VM, so the doreti/iretq variant could not be forced deterministically here.", "recommended_fix": "Remove the PSL_VM_UNSUPP pre-strip in sys_sigreturn so EFL_SECURE validates the rflags actually installed; drop PSL_VM_UNSUPP from cpu_sanitize_frames mask (vkernel64 + pc64).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fixed", "fix_evidence": "run_fixed.log: mode 1 rejected with kernel kprintf sigreturn: rflags = 0x20206 and process terminated (baseline accepted + survived); mode 0 control unchanged; disasm_vk_fixed.txt shows sanitize mask 0x254dd5 (VM removed) and disasm_vk_sigreturn_fixed.txt shows the check-strip gone." } |