• Sean Christopherson's avatar
    KVM: VMX: Set vmcs.PENDING_DBG.BS on #DB in STI/MOVSS blocking shadow · b9bed78e
    Sean Christopherson authored
    Set vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS, a.k.a. the pending single-step
    breakpoint flag, when re-injecting a #DB with RFLAGS.TF=1, and STI or
    MOVSS blocking is active.  Setting the flag is necessary to make VM-Entry
    consistency checks happy, as VMX has an invariant that if RFLAGS.TF is
    set and STI/MOVSS blocking is true, then the previous instruction must
    have been STI or MOV/POP, and therefore a single-step #DB must be pending
    since the RFLAGS.TF cannot have been set by the previous instruction,
    i.e. the one instruction delay after setting RFLAGS.TF must have already
    expired.
    
    Normally, the CPU sets vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS appropriately
    when recording guest state as part of a VM-Exit, but #DB VM-Exits
    intentionally do not treat the #DB as "guest state" as interception of
    the #DB effectively makes the #DB host-owned, thus KVM needs to manually
    set PENDING_DBG.BS when forwarding/re-injecting the #DB to the guest.
    
    Note, although this bug can be triggered by guest userspace, doing so
    requires IOPL=3, and guest userspace running with IOPL=3 has full access
    to all I/O ports (from the guest's perspective) and can crash/reboot the
    guest any number of ways.  IOPL=3 is required because STI blocking kicks
    in if and only if RFLAGS.IF is toggled 0=>1, and if CPL>IOPL, STI either
    takes a #GP or modifies RFLAGS.VIF, not RFLAGS.IF.
    
    MOVSS blocking can be initiated by userspace, but can be coincident with
    a #DB if and only if DR7.GD=1 (General Detect enabled) and a MOV DR is
    executed in the MOVSS shadow.  MOV DR #GPs at CPL>0, thus MOVSS blocking
    is problematic only for CPL0 (and only if the guest is crazy enough to
    access a DR in a MOVSS shadow).  All other sources of #DBs are either
    suppressed by MOVSS blocking (single-step, code fetch, data, and I/O),
    are mutually exclusive with MOVSS blocking (T-bit task switch), or are
    already handled by KVM (ICEBP, a.k.a. INT1).
    
    This bug was originally found by running tests[1] created for XSA-308[2].
    Note that Xen's userspace test emits ICEBP in the MOVSS shadow, which is
    presumably why the Xen bug was deemed to be an exploitable DOS from guest
    userspace.  KVM already handles ICEBP by skipping the ICEBP instruction
    and thus clears MOVSS blocking as a side effect of its "emulation".
    
    [1] http://xenbits.xenproject.org/docs/xtf/xsa-308_2main_8c_source.html
    [2] https://xenbits.xen.org/xsa/advisory-308.htmlReported-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
    Reported-by: default avatarAlexander Graf <graf@amazon.de>
    Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
    Message-Id: <20220120000624.655815-1-seanjc@google.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    b9bed78e
vmx.c 230 KB