β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5408

sys_sigreturn installs raw mc_rflags β€” the PSL_VM_UNSUPP strip defangs EFL_SECURE (validate-vs-install mismatch; pc64 mirror)

Summary

The VM bit is stripped from the LOCAL rflags used for EFL_SECURE validation but the RAW mcontext is bcopy'd into the trapframe: the check never sees the bit and the install re-adds it - a guest user installs a VM-set rflags the check exists to reject (set_regs blocks the identical value). In-vkernel-proven: VM-poisoned sigreturn accepted and the process survives; fixed kernel rejects with its own 'sigreturn: rflags' EINVAL. The poisoned rflags survives both sanitizers and is loaded by the HOST's return-to-user - silently masked on Skylake/KVM (iretvm probe) but a guest-triggered host-kernel-mode #GP(0) at doreti iretq on SDM-enforcing hardware (the DF-5335 special case). Same shape in pc64 machdep.c:1013-1040 (disassembly-verified). Validate-what-you-install fix (both copies).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5408 Β· 20 files
FileTypeDescriptionSize
vmflag.c β€” 8.6 KB view raw
iretvm.c β€” 2.4 KB view raw
build_kernel.sh β€” 447 B view raw
build_image.sh β€” 1.2 KB view raw
run_suite.sh β€” 2.0 KB view raw
run.sh β€” 199 B view raw
run_suite.log β€” 3.8 KB view raw
run_fixed.log β€” 3.6 KB view raw
run_baseline.log β€” 1.8 KB view raw
vkconsole_fixed.log β€” 3.8 KB view raw
build.log β€” 934.7 KB ↓ download
fixbuild.log β€” 935.2 KB ↓ download
img.log β€” 601 B view raw
disasm_vk_baseline.txt β€” 592 B view raw
disasm_host.txt β€” 740 B view raw
disasm_vk_fixed.txt β€” 672 B view raw
disasm_vk_sigreturn_fixed.txt β€” 3.8 KB view raw
env.txt β€” 349 B view raw
fix.diff β€” 1.5 KB view raw
verdict.json β€” 4.1 KB view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

fixed

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.
↓ fix.diffper-fix-DF-5408

Confirmed kernel references

Detail

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 (decisive lines)

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

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.

Verified 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_frame's mask (vkernel64 + pc64).

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 vkernel's and the host's cpu_sanitize_frame into the host return-to-user path. On this rig's 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.