• Sean Christopherson's avatar
    KVM: VMX: Add basic handling of VM-Exit from SGX enclave · 3c0c2ad1
    Sean Christopherson authored
    Add support for handling VM-Exits that originate from a guest SGX
    enclave.  In SGX, an "enclave" is a new CPL3-only execution environment,
    wherein the CPU and memory state is protected by hardware to make the
    state inaccesible to code running outside of the enclave.  When exiting
    an enclave due to an asynchronous event (from the perspective of the
    enclave), e.g. exceptions, interrupts, and VM-Exits, the enclave's state
    is automatically saved and scrubbed (the CPU loads synthetic state), and
    then reloaded when re-entering the enclave.  E.g. after an instruction
    based VM-Exit from an enclave, vmcs.GUEST_RIP will not contain the RIP
    of the enclave instruction that trigered VM-Exit, but will instead point
    to a RIP in the enclave's untrusted runtime (the guest userspace code
    that coordinates entry/exit to/from the enclave).
    
    To help a VMM recognize and handle exits from enclaves, SGX adds bits to
    existing VMCS fields, VM_EXIT_REASON.VMX_EXIT_REASON_FROM_ENCLAVE and
    GUEST_INTERRUPTIBILITY_INFO.GUEST_INTR_STATE_ENCLAVE_INTR.  Define the
    new architectural bits, and add a boolean to struct vcpu_vmx to cache
    VMX_EXIT_REASON_FROM_ENCLAVE.  Clear the bit in exit_reason so that
    checks against exit_reason do not need to account for SGX, e.g.
    "if (exit_reason == EXIT_REASON_EXCEPTION_NMI)" continues to work.
    
    KVM is a largely a passive observer of the new bits, e.g. KVM needs to
    account for the bits when propagating information to a nested VMM, but
    otherwise doesn't need to act differently for the majority of VM-Exits
    from enclaves.
    
    The one scenario that is directly impacted is emulation, which is for
    all intents and purposes impossible[1] since KVM does not have access to
    the RIP or instruction stream that triggered the VM-Exit.  The inability
    to emulate is a non-issue for KVM, as most instructions that might
    trigger VM-Exit unconditionally #UD in an enclave (before the VM-Exit
    check.  For the few instruction that conditionally #UD, KVM either never
    sets the exiting control, e.g. PAUSE_EXITING[2], or sets it if and only
    if the feature is not exposed to the guest in order to inject a #UD,
    e.g. RDRAND_EXITING.
    
    But, because it is still possible for a guest to trigger emulation,
    e.g. MMIO, inject a #UD if KVM ever attempts emulation after a VM-Exit
    from an enclave.  This is architecturally accurate for instruction
    VM-Exits, and for MMIO it's the least bad choice, e.g. it's preferable
    to killing the VM.  In practice, only broken or particularly stupid
    guests should ever encounter this behavior.
    
    Add a WARN in skip_emulated_instruction to detect any attempt to
    modify the guest's RIP during an SGX enclave VM-Exit as all such flows
    should either be unreachable or must handle exits from enclaves before
    getting to skip_emulated_instruction.
    
    [1] Impossible for all practical purposes.  Not truly impossible
        since KVM could implement some form of para-virtualization scheme.
    
    [2] PAUSE_LOOP_EXITING only affects CPL0 and enclaves exist only at
        CPL3, so we also don't need to worry about that interaction.
    Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
    Signed-off-by: default avatarKai Huang <kai.huang@intel.com>
    Message-Id: <315f54a8507d09c292463ef29104e1d4c62e9090.1618196135.git.kai.huang@intel.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    3c0c2ad1
nested.c 202 KB