• Sean Christopherson's avatar
    KVM: x86/mmu: Use dummy root, backed by zero page, for !visible guest roots · 0e3223d8
    Sean Christopherson authored
    When attempting to allocate a shadow root for a !visible guest root gfn,
    e.g. that resides in MMIO space, load a dummy root that is backed by the
    zero page instead of immediately synthesizing a triple fault shutdown
    (using the zero page ensures any attempt to translate memory will generate
    a !PRESENT fault and thus VM-Exit).
    
    Unless the vCPU is racing with memslot activity, KVM will inject a page
    fault due to not finding a visible slot in FNAME(walk_addr_generic), i.e.
    the end result is mostly same, but critically KVM will inject a fault only
    *after* KVM runs the vCPU with the bogus root.
    
    Waiting to inject a fault until after running the vCPU fixes a bug where
    KVM would bail from nested VM-Enter if L1 tried to run L2 with TDP enabled
    and a !visible root.  Even though a bad root will *probably* lead to
    shutdown, (a) it's not guaranteed and (b) the CPU won't read the
    underlying memory until after VM-Enter succeeds.  E.g. if L1 runs L2 with
    a VMX preemption timer value of '0', then architecturally the preemption
    timer VM-Exit is guaranteed to occur before the CPU executes any
    instruction, i.e. before the CPU needs to translate a GPA to a HPA (so
    long as there are no injected events with higher priority than the
    preemption timer).
    
    If KVM manages to get to FNAME(fetch) with a dummy root, e.g. because
    userspace created a memslot between installing the dummy root and handling
    the page fault, simply unload the MMU to allocate a new root and retry the
    instruction.  Use KVM_REQ_MMU_FREE_OBSOLETE_ROOTS to drop the root, as
    invoking kvm_mmu_free_roots() while holding mmu_lock would deadlock, and
    conceptually the dummy root has indeeed become obsolete.  The only
    difference versus existing usage of KVM_REQ_MMU_FREE_OBSOLETE_ROOTS is
    that the root has become obsolete due to memslot *creation*, not memslot
    deletion or movement.
    Reported-by: default avatarReima Ishii <ishiir@g.ecc.u-tokyo.ac.jp>
    Cc: Yu Zhang <yu.c.zhang@linux.intel.com>
    Link: https://lore.kernel.org/r/20230729005200.1057358-6-seanjc@google.comSigned-off-by: default avatarSean Christopherson <seanjc@google.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    0e3223d8
mmu.c 198 KB