# DF-5409 — `cpu_sanitize_frame` whitelists `PSL_VM_UNSUPP`: the DF-5335 gate is incomplete for EFLAGS.VM

## What (the bug)

The vkernel's frame sanitizer, `sys/platform/vkernel64/x86_64/cpu_regs.c:311-320`:

```c
316:	frame->tf_rflags &= (PSL_RF | PSL_USERCHANGE | PSL_VM_UNSUPP);
```

The mask deliberately KEEPS `PSL_VM_UNSUPP` (0x20000, the EFLAGS.VM bit,
with a "XXX VM (8086) mode not supported?" comment).  The pc64 host mirror
(`sys/platform/pc64/x86_64/machdep.c:916`) is identical — confirmed by
disassembly of the **running** guest kernel (`disasm_host.txt`:
`and $0x274dd5,%eax`; 0x20000 ∈ mask).

`cpu_sanitize_frame` is the gate the trap.c pass-2 audits cited as blocking
the DF-5335 (espfix / bad-frame-at-iretq) route for the vkernel: every
`go_user` → `vmspace_ctl(VMSPACE_CTL_RUN)` re-entry into (guest-)user mode
passes through it (`sys/vm/vm_vmspace.c:298`), and it correctly forces
CS/SS and masks IOPL/NT/… — but not VM.

## Consequence

A VM-set rflags survives BOTH sanitizers (the vkernel's and the host's)
and is loaded by the host kernel's return-to-user:

* reached structurally by ANY frame source — `sigreturn` (see DF-5408),
  `set_regs` is blocked (EFL_SECURE), but `vmspace_ctl(RUN)` frames pass
  straight through the whitelisting mask (verified: 20,000 consecutive
  `vmspace_ctl` RUNs with rflags=0x20246 accepted, `run_suite.log` mode 2),
* on hardware/VMMs that enforce the SDM rule (iretq attempting VM in long
  mode → #GP(0)), that is a guest-user-triggerable kernel-mode #GP at the
  host `doreti` iretq — the `IDTVEC(prot)` / `doreti_iret_fault` special
  case, i.e. exactly the code path whose robustness DF-5335 questions;
* on the rig's CPU (Intel Skylake under KVM) the bit is silently masked at
  iretq/SYSRET (proved with `iretvm.c` — see DF-5408's pack), so no fault
  manifests here.

There is no legitimate way for VM to be set in a 64-bit user rflags: the
kernel's own `sys_sigreturn` calls it "VM (8086) mode not supported" and
tries (DF-5408: ineffectively) to strip it.  The sanitize mask keeping it
is a completeness gap in the gate.

## Precondition

* `sigreturn` vector: none (any guest user).
* direct `vmspace_ctl` vector: `vm.vkernel_enable=1` inside the vkernel
  (guest-root sysctl — the standard state for running any nested vkernel);
  then any guest process can `vmspace_create` + `vmspace_ctl` (no priv
  check — sys/vm/vm_vmspace.c:150-192).

## Verified

Same rig and run as DF-5408 (shared evidence):

* baseline vkernel binary: mask `0x274dd5` (`disasm_vk_baseline.txt`);
* running HOST kernel (pc64): mask `0x274dd5` (`disasm_host.txt`);
* runtime: mode 2 loop — 20k VM-frames through both sanitizers, all
  accepted, nested contexts executed at the poisoned rip (frame loaded,
  not rejected);
* fixed vkernel: mask `0x254dd5` (VM removed — `disasm_vk_fixed.txt`).

## Recommended fix

Drop `PSL_VM_UNSUPP` from the mask in BOTH copies (vkernel64 cpu_regs.c:316
and pc64 machdep.c:916) — `fix.diff` in DF-5408's pack contains both hunks
plus the sigreturn-side fix.
