Commit 47ab8751 authored by Xiao Guangrong's avatar Xiao Guangrong Committed by Paolo Bonzini

KVM: MMU: fully check zero bits for sptes

The #PF with PFEC.RSV = 1 is designed to speed MMIO emulation, however,
it is possible that the RSV #PF is caused by real BUG by mis-configure
shadow page table entries

This patch enables full check for the zero bits on shadow page table
entries (which includes not only bits reserved by the hardware, but also
bits that will never be set in the SPTE), then dump the shadow page table
hierarchy.
Signed-off-by: default avatarXiao Guangrong <guangrong.xiao@linux.intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent d625b155
...@@ -3295,31 +3295,62 @@ static bool quickly_check_mmio_pf(struct kvm_vcpu *vcpu, u64 addr, bool direct) ...@@ -3295,31 +3295,62 @@ static bool quickly_check_mmio_pf(struct kvm_vcpu *vcpu, u64 addr, bool direct)
return vcpu_match_mmio_gva(vcpu, addr); return vcpu_match_mmio_gva(vcpu, addr);
} }
static u64 walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr) /* return true if reserved bit is detected on spte. */
static bool
walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
{ {
struct kvm_shadow_walk_iterator iterator; struct kvm_shadow_walk_iterator iterator;
u64 spte = 0ull; u64 sptes[PT64_ROOT_LEVEL], spte = 0ull;
int root, leaf;
bool reserved = false;
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return spte; goto exit;
walk_shadow_page_lockless_begin(vcpu); walk_shadow_page_lockless_begin(vcpu);
for_each_shadow_entry_lockless(vcpu, addr, iterator, spte)
for (shadow_walk_init(&iterator, vcpu, addr), root = iterator.level;
shadow_walk_okay(&iterator);
__shadow_walk_next(&iterator, spte)) {
leaf = iterator.level;
spte = mmu_spte_get_lockless(iterator.sptep);
sptes[leaf - 1] = spte;
if (!is_shadow_present_pte(spte)) if (!is_shadow_present_pte(spte))
break; break;
reserved |= is_shadow_zero_bits_set(&vcpu->arch.mmu, spte,
leaf);
}
walk_shadow_page_lockless_end(vcpu); walk_shadow_page_lockless_end(vcpu);
return spte; if (reserved) {
pr_err("%s: detect reserved bits on spte, addr 0x%llx, dump hierarchy:\n",
__func__, addr);
while (root >= leaf) {
pr_err("------ spte 0x%llx level %d.\n",
sptes[root - 1], root);
root--;
}
}
exit:
*sptep = spte;
return reserved;
} }
int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct) int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
{ {
u64 spte; u64 spte;
bool reserved;
if (quickly_check_mmio_pf(vcpu, addr, direct)) if (quickly_check_mmio_pf(vcpu, addr, direct))
return RET_MMIO_PF_EMULATE; return RET_MMIO_PF_EMULATE;
spte = walk_shadow_page_get_mmio_spte(vcpu, addr); reserved = walk_shadow_page_get_mmio_spte(vcpu, addr, &spte);
if (unlikely(reserved))
return RET_MMIO_PF_BUG;
if (is_mmio_spte(spte)) { if (is_mmio_spte(spte)) {
gfn_t gfn = get_mmio_spte_gfn(spte); gfn_t gfn = get_mmio_spte_gfn(spte);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment