diff options
author | Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | 2010-08-28 07:24:13 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:51:48 -0400 |
commit | 365fb3fdf6769d3553999d8eb6cc2a8c56c747c1 (patch) | |
tree | e8ac38a587a4cf2cac88df4580e7112c15b13e14 /arch | |
parent | bc32ce2152406431acf4daf4a81dc1664bb7b91b (diff) |
KVM: MMU: rewrite audit_mappings_page() function
There is a bugs in this function, we call gfn_to_pfn() and kvm_mmu_gva_to_gpa_read() in
atomic context(kvm_mmu_audit() is called under the spinlock(mmu_lock)'s protection).
This patch fix it by:
- introduce gfn_to_pfn_atomic instead of gfn_to_pfn
- get the mapping gfn from kvm_mmu_page_get_gfn()
And it adds 'notrap' ptes check in unsync/direct sps
Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/mmu.c | 75 |
1 files changed, 40 insertions, 35 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 68575dc32ec7..0d91f60af1a8 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -3487,15 +3487,6 @@ EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); | |||
3487 | 3487 | ||
3488 | static const char *audit_msg; | 3488 | static const char *audit_msg; |
3489 | 3489 | ||
3490 | static gva_t canonicalize(gva_t gva) | ||
3491 | { | ||
3492 | #ifdef CONFIG_X86_64 | ||
3493 | gva = (long long)(gva << 16) >> 16; | ||
3494 | #endif | ||
3495 | return gva; | ||
3496 | } | ||
3497 | |||
3498 | |||
3499 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); | 3490 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); |
3500 | 3491 | ||
3501 | static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, | 3492 | static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, |
@@ -3550,39 +3541,53 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, | |||
3550 | gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); | 3541 | gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); |
3551 | 3542 | ||
3552 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { | 3543 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { |
3553 | u64 ent = pt[i]; | 3544 | u64 *sptep = pt + i; |
3545 | struct kvm_mmu_page *sp; | ||
3546 | gfn_t gfn; | ||
3547 | pfn_t pfn; | ||
3548 | hpa_t hpa; | ||
3554 | 3549 | ||
3555 | if (ent == shadow_trap_nonpresent_pte) | 3550 | sp = page_header(__pa(sptep)); |
3556 | continue; | ||
3557 | 3551 | ||
3558 | va = canonicalize(va); | 3552 | if (sp->unsync) { |
3559 | if (is_shadow_present_pte(ent) && !is_last_spte(ent, level)) | 3553 | if (level != PT_PAGE_TABLE_LEVEL) { |
3560 | audit_mappings_page(vcpu, ent, va, level - 1); | 3554 | printk(KERN_ERR "audit: (%s) error: unsync sp: %p level = %d\n", |
3561 | else { | 3555 | audit_msg, sp, level); |
3562 | gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL); | 3556 | return; |
3563 | gfn_t gfn = gpa >> PAGE_SHIFT; | 3557 | } |
3564 | pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn); | ||
3565 | hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT; | ||
3566 | 3558 | ||
3567 | if (is_error_pfn(pfn)) { | 3559 | if (*sptep == shadow_notrap_nonpresent_pte) { |
3568 | kvm_release_pfn_clean(pfn); | 3560 | printk(KERN_ERR "audit: (%s) error: notrap spte in unsync sp: %p\n", |
3569 | continue; | 3561 | audit_msg, sp); |
3562 | return; | ||
3570 | } | 3563 | } |
3564 | } | ||
3571 | 3565 | ||
3572 | if (is_shadow_present_pte(ent) | 3566 | if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { |
3573 | && (ent & PT64_BASE_ADDR_MASK) != hpa) | 3567 | printk(KERN_ERR "audit: (%s) error: notrap spte in direct sp: %p\n", |
3574 | printk(KERN_ERR "xx audit error: (%s) levels %d" | 3568 | audit_msg, sp); |
3575 | " gva %lx gpa %llx hpa %llx ent %llx %d\n", | 3569 | return; |
3576 | audit_msg, vcpu->arch.mmu.root_level, | 3570 | } |
3577 | va, gpa, hpa, ent, | 3571 | |
3578 | is_shadow_present_pte(ent)); | 3572 | if (!is_shadow_present_pte(*sptep) || |
3579 | else if (ent == shadow_notrap_nonpresent_pte | 3573 | !is_last_spte(*sptep, level)) |
3580 | && !is_error_hpa(hpa)) | 3574 | return; |
3581 | printk(KERN_ERR "audit: (%s) notrap shadow," | 3575 | |
3582 | " valid guest gva %lx\n", audit_msg, va); | 3576 | gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); |
3583 | kvm_release_pfn_clean(pfn); | 3577 | pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn); |
3584 | 3578 | ||
3579 | if (is_error_pfn(pfn)) { | ||
3580 | kvm_release_pfn_clean(pfn); | ||
3581 | return; | ||
3585 | } | 3582 | } |
3583 | |||
3584 | hpa = pfn << PAGE_SHIFT; | ||
3585 | |||
3586 | if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) | ||
3587 | printk(KERN_ERR "xx audit error: (%s) levels %d" | ||
3588 | " gva %lx pfn %llx hpa %llx ent %llxn", | ||
3589 | audit_msg, vcpu->arch.mmu.root_level, | ||
3590 | va, pfn, hpa, *sptep); | ||
3586 | } | 3591 | } |
3587 | } | 3592 | } |
3588 | 3593 | ||