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)
PoC verification
Evidence pack
findings/poc/DF-5408 Β· 20 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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
fixedfixed
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.
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.
No comments yet.