• Paolo Bonzini's avatar
    KVM: SEV: only access GHCB fields once · 7588dbce
    Paolo Bonzini authored
    A KVM guest using SEV-ES or SEV-SNP with multiple vCPUs can trigger
    a double fetch race condition vulnerability and invoke the VMGEXIT
    handler recursively.
    
    sev_handle_vmgexit() maps the GHCB page using kvm_vcpu_map() and then
    fetches the exit code using ghcb_get_sw_exit_code().  Soon after,
    sev_es_validate_vmgexit() fetches the exit code again. Since the GHCB
    page is shared with the guest, the guest is able to quickly swap the
    values with another vCPU and hence bypass the validation. One vmexit code
    that can be rejected by sev_es_validate_vmgexit() is SVM_EXIT_VMGEXIT;
    if sev_handle_vmgexit() observes it in the second fetch, the call
    to svm_invoke_exit_handler() will invoke sev_handle_vmgexit() again
    recursively.
    
    To avoid the race, always fetch the GHCB data from the places where
    sev_es_sync_from_ghcb stores it.
    
    Exploiting recursions on linux kernel has been proven feasible
    in the past, but the impact is mitigated by stack guard pages
    (CONFIG_VMAP_STACK).  Still, if an attacker manages to call the handler
    multiple times, they can theoretically trigger a stack overflow and
    cause a denial-of-service, or potentially guest-to-host escape in kernel
    configurations without stack guard pages.
    
    Note that winning the race reliably in every iteration is very tricky
    due to the very tight window of the fetches; depending on the compiler
    settings, they are often consecutive because of optimization and inlining.
    
    Tested by booting an SEV-ES RHEL9 guest.
    
    Fixes: CVE-2023-4155
    Fixes: 291bd20d ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT")
    Cc: stable@vger.kernel.org
    Reported-by: default avatarAndy Nguyen <theflow@google.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    7588dbce
sev.c 77.1 KB