• Sean Christopherson's avatar
    KVM: x86/mmu: Use atomic XCHG to write TDP MMU SPTEs with volatile bits · ba3a6120
    Sean Christopherson authored
    Use an atomic XCHG to write TDP MMU SPTEs that have volatile bits, even
    if mmu_lock is held for write, as volatile SPTEs can be written by other
    tasks/vCPUs outside of mmu_lock.  If a vCPU uses the to-be-modified SPTE
    to write a page, the CPU can cache the translation as WRITABLE in the TLB
    despite it being seen by KVM as !WRITABLE, and/or KVM can clobber the
    Accessed/Dirty bits and not properly tag the backing page.
    
    Exempt non-leaf SPTEs from atomic updates as KVM itself doesn't modify
    non-leaf SPTEs without holding mmu_lock, they do not have Dirty bits, and
    KVM doesn't consume the Accessed bit of non-leaf SPTEs.
    
    Dropping the Dirty and/or Writable bits is most problematic for dirty
    logging, as doing so can result in a missed TLB flush and eventually a
    missed dirty page.  In the unlikely event that the only dirty page(s) is
    a clobbered SPTE, clear_dirty_gfn_range() will see the SPTE as not dirty
    (based on the Dirty or Writable bit depending on the method) and so not
    update the SPTE and ultimately not flush.  If the SPTE is cached in the
    TLB as writable before it is clobbered, the guest can continue writing
    the associated page without ever taking a write-protect fault.
    
    For most (all?) file back memory, dropping the Dirty bit is a non-issue.
    The primary MMU write-protects its PTEs on writeback, i.e. KVM's dirty
    bit is effectively ignored because the primary MMU will mark that page
    dirty when the write-protection is lifted, e.g. when KVM faults the page
    back in for write.
    
    The Accessed bit is a complete non-issue.  Aside from being unused for
    non-leaf SPTEs, KVM doesn't do a TLB flush when aging SPTEs, i.e. the
    Accessed bit may be dropped anyways.
    
    Lastly, the Writable bit is also problematic as an extension of the Dirty
    bit, as KVM (correctly) treats the Dirty bit as volatile iff the SPTE is
    !DIRTY && WRITABLE.  If KVM fixes an MMU-writable, but !WRITABLE, SPTE
    out of mmu_lock, then it can allow the CPU to set the Dirty bit despite
    the SPTE being !WRITABLE when it is checked by KVM.  But that all depends
    on the Dirty bit being problematic in the first place.
    
    Fixes: 2f2fad08 ("kvm: x86/mmu: Add functions to handle changed TDP SPTEs")
    Cc: stable@vger.kernel.org
    Cc: Ben Gardon <bgardon@google.com>
    Cc: David Matlack <dmatlack@google.com>
    Cc: Venkatesh Srinivas <venkateshs@google.com>
    Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
    Message-Id: <20220423034752.1161007-4-seanjc@google.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    ba3a6120
tdp_mmu.c 57.2 KB