• Cfir Cohen's avatar
    KVM: Fix UAF in nested posted interrupt processing · c2dd5146
    Cfir Cohen authored
    nested_get_vmcs12_pages() processes the posted_intr address in vmcs12. It
    caches the kmap()ed page object and pointer, however, it doesn't handle
    errors correctly: it's possible to cache a valid pointer, then release
    the page and later dereference the dangling pointer.
    
    I was able to reproduce with the following steps:
    
    1. Call vmlaunch with valid posted_intr_desc_addr but an invalid
    MSR_EFER. This causes nested_get_vmcs12_pages() to cache the kmap()ed
    pi_desc_page and pi_desc. Later the invalid EFER value fails
    check_vmentry_postreqs() which fails the first vmlaunch.
    
    2. Call vmlanuch with a valid EFER but an invalid posted_intr_desc_addr
    (I set it to 2G - 0x80). The second time we call nested_get_vmcs12_pages
    pi_desc_page is unmapped and released and pi_desc_page is set to NULL
    (the "shouldn't happen" clause). Due to the invalid
    posted_intr_desc_addr, kvm_vcpu_gpa_to_page() fails and
    nested_get_vmcs12_pages() returns. It doesn't return an error value so
    vmlaunch proceeds. Note that at this time we have a dangling pointer in
    vmx->nested.pi_desc and POSTED_INTR_DESC_ADDR in L0's vmcs.
    
    3. Issue an IPI in L2 guest code. This triggers a call to
    vmx_complete_nested_posted_interrupt() and pi_test_and_clear_on() which
    dereferences the dangling pointer.
    
    Vulnerable code requires nested and enable_apicv variables to be set to
    true. The host CPU must also support posted interrupts.
    
    Fixes: 5e2f30b7 "KVM: nVMX: get rid of nested_get_page()"
    Cc: stable@vger.kernel.org
    Reviewed-by: default avatarAndy Honig <ahonig@google.com>
    Signed-off-by: default avatarCfir Cohen <cfir@google.com>
    Reviewed-by: default avatarLiran Alon <liran.alon@oracle.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    c2dd5146
vmx.c 436 KB