diff options
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 4 | ||||
| -rw-r--r-- | arch/x86/kvm/mmu.c | 26 | ||||
| -rw-r--r-- | arch/x86/kvm/mmu_audit.c | 39 |
3 files changed, 39 insertions, 30 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 95f026be8b5e..aa75f21a9fba 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -461,6 +461,10 @@ struct kvm_arch { | |||
| 461 | /* fields used by HYPER-V emulation */ | 461 | /* fields used by HYPER-V emulation */ |
| 462 | u64 hv_guest_os_id; | 462 | u64 hv_guest_os_id; |
| 463 | u64 hv_hypercall; | 463 | u64 hv_hypercall; |
| 464 | |||
| 465 | #ifdef CONFIG_KVM_MMU_AUDIT | ||
| 466 | int audit_point; | ||
| 467 | #endif | ||
| 464 | }; | 468 | }; |
| 465 | 469 | ||
| 466 | struct kvm_vm_stat { | 470 | struct kvm_vm_stat { |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index e558795fccd5..892ffc603ff9 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
| @@ -3534,13 +3534,6 @@ static void mmu_destroy_caches(void) | |||
| 3534 | kmem_cache_destroy(mmu_page_header_cache); | 3534 | kmem_cache_destroy(mmu_page_header_cache); |
| 3535 | } | 3535 | } |
| 3536 | 3536 | ||
| 3537 | void kvm_mmu_module_exit(void) | ||
| 3538 | { | ||
| 3539 | mmu_destroy_caches(); | ||
| 3540 | percpu_counter_destroy(&kvm_total_used_mmu_pages); | ||
| 3541 | unregister_shrinker(&mmu_shrinker); | ||
| 3542 | } | ||
| 3543 | |||
| 3544 | int kvm_mmu_module_init(void) | 3537 | int kvm_mmu_module_init(void) |
| 3545 | { | 3538 | { |
| 3546 | pte_chain_cache = kmem_cache_create("kvm_pte_chain", | 3539 | pte_chain_cache = kmem_cache_create("kvm_pte_chain", |
| @@ -3733,12 +3726,6 @@ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]) | |||
| 3733 | } | 3726 | } |
| 3734 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); | 3727 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); |
| 3735 | 3728 | ||
| 3736 | #ifdef CONFIG_KVM_MMU_AUDIT | ||
| 3737 | #include "mmu_audit.c" | ||
| 3738 | #else | ||
| 3739 | static void mmu_audit_disable(void) { } | ||
| 3740 | #endif | ||
| 3741 | |||
| 3742 | void kvm_mmu_destroy(struct kvm_vcpu *vcpu) | 3729 | void kvm_mmu_destroy(struct kvm_vcpu *vcpu) |
| 3743 | { | 3730 | { |
| 3744 | ASSERT(vcpu); | 3731 | ASSERT(vcpu); |
| @@ -3746,5 +3733,18 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu) | |||
| 3746 | destroy_kvm_mmu(vcpu); | 3733 | destroy_kvm_mmu(vcpu); |
| 3747 | free_mmu_pages(vcpu); | 3734 | free_mmu_pages(vcpu); |
| 3748 | mmu_free_memory_caches(vcpu); | 3735 | mmu_free_memory_caches(vcpu); |
| 3736 | } | ||
| 3737 | |||
| 3738 | #ifdef CONFIG_KVM_MMU_AUDIT | ||
| 3739 | #include "mmu_audit.c" | ||
| 3740 | #else | ||
| 3741 | static void mmu_audit_disable(void) { } | ||
| 3742 | #endif | ||
| 3743 | |||
| 3744 | void kvm_mmu_module_exit(void) | ||
| 3745 | { | ||
| 3746 | mmu_destroy_caches(); | ||
| 3747 | percpu_counter_destroy(&kvm_total_used_mmu_pages); | ||
| 3748 | unregister_shrinker(&mmu_shrinker); | ||
| 3749 | mmu_audit_disable(); | 3749 | mmu_audit_disable(); |
| 3750 | } | 3750 | } |
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index ba2bcdde6221..5f6223b8bcf7 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c | |||
| @@ -19,11 +19,9 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/ratelimit.h> | 20 | #include <linux/ratelimit.h> |
| 21 | 21 | ||
| 22 | static int audit_point; | 22 | #define audit_printk(kvm, fmt, args...) \ |
| 23 | |||
| 24 | #define audit_printk(fmt, args...) \ | ||
| 25 | printk(KERN_ERR "audit: (%s) error: " \ | 23 | printk(KERN_ERR "audit: (%s) error: " \ |
| 26 | fmt, audit_point_name[audit_point], ##args) | 24 | fmt, audit_point_name[kvm->arch.audit_point], ##args) |
| 27 | 25 | ||
| 28 | typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level); | 26 | typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level); |
| 29 | 27 | ||
| @@ -97,18 +95,21 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) | |||
| 97 | 95 | ||
| 98 | if (sp->unsync) { | 96 | if (sp->unsync) { |
| 99 | if (level != PT_PAGE_TABLE_LEVEL) { | 97 | if (level != PT_PAGE_TABLE_LEVEL) { |
| 100 | audit_printk("unsync sp: %p level = %d\n", sp, level); | 98 | audit_printk(vcpu->kvm, "unsync sp: %p " |
| 99 | "level = %d\n", sp, level); | ||
| 101 | return; | 100 | return; |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | if (*sptep == shadow_notrap_nonpresent_pte) { | 103 | if (*sptep == shadow_notrap_nonpresent_pte) { |
| 105 | audit_printk("notrap spte in unsync sp: %p\n", sp); | 104 | audit_printk(vcpu->kvm, "notrap spte in unsync " |
| 105 | "sp: %p\n", sp); | ||
| 106 | return; | 106 | return; |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { | 110 | if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { |
| 111 | audit_printk("notrap spte in direct sp: %p\n", sp); | 111 | audit_printk(vcpu->kvm, "notrap spte in direct sp: %p\n", |
| 112 | sp); | ||
| 112 | return; | 113 | return; |
| 113 | } | 114 | } |
| 114 | 115 | ||
| @@ -125,8 +126,9 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) | |||
| 125 | 126 | ||
| 126 | hpa = pfn << PAGE_SHIFT; | 127 | hpa = pfn << PAGE_SHIFT; |
| 127 | if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) | 128 | if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) |
| 128 | audit_printk("levels %d pfn %llx hpa %llx ent %llxn", | 129 | audit_printk(vcpu->kvm, "levels %d pfn %llx hpa %llx " |
| 129 | vcpu->arch.mmu.root_level, pfn, hpa, *sptep); | 130 | "ent %llxn", vcpu->arch.mmu.root_level, pfn, |
| 131 | hpa, *sptep); | ||
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) | 134 | static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) |
| @@ -142,8 +144,8 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) | |||
| 142 | if (!gfn_to_memslot(kvm, gfn)) { | 144 | if (!gfn_to_memslot(kvm, gfn)) { |
| 143 | if (!printk_ratelimit()) | 145 | if (!printk_ratelimit()) |
| 144 | return; | 146 | return; |
| 145 | audit_printk("no memslot for gfn %llx\n", gfn); | 147 | audit_printk(kvm, "no memslot for gfn %llx\n", gfn); |
| 146 | audit_printk("index %ld of sp (gfn=%llx)\n", | 148 | audit_printk(kvm, "index %ld of sp (gfn=%llx)\n", |
| 147 | (long int)(sptep - rev_sp->spt), rev_sp->gfn); | 149 | (long int)(sptep - rev_sp->spt), rev_sp->gfn); |
| 148 | dump_stack(); | 150 | dump_stack(); |
| 149 | return; | 151 | return; |
| @@ -153,7 +155,8 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) | |||
| 153 | if (!*rmapp) { | 155 | if (!*rmapp) { |
| 154 | if (!printk_ratelimit()) | 156 | if (!printk_ratelimit()) |
| 155 | return; | 157 | return; |
| 156 | audit_printk("no rmap for writable spte %llx\n", *sptep); | 158 | audit_printk(kvm, "no rmap for writable spte %llx\n", |
| 159 | *sptep); | ||
| 157 | dump_stack(); | 160 | dump_stack(); |
| 158 | } | 161 | } |
| 159 | } | 162 | } |
| @@ -168,8 +171,9 @@ static void audit_spte_after_sync(struct kvm_vcpu *vcpu, u64 *sptep, int level) | |||
| 168 | { | 171 | { |
| 169 | struct kvm_mmu_page *sp = page_header(__pa(sptep)); | 172 | struct kvm_mmu_page *sp = page_header(__pa(sptep)); |
| 170 | 173 | ||
| 171 | if (audit_point == AUDIT_POST_SYNC && sp->unsync) | 174 | if (vcpu->kvm->arch.audit_point == AUDIT_POST_SYNC && sp->unsync) |
| 172 | audit_printk("meet unsync sp(%p) after sync root.\n", sp); | 175 | audit_printk(vcpu->kvm, "meet unsync sp(%p) after sync " |
| 176 | "root.\n", sp); | ||
| 173 | } | 177 | } |
| 174 | 178 | ||
| 175 | static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) | 179 | static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) |
| @@ -202,8 +206,9 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) | |||
| 202 | spte = rmap_next(kvm, rmapp, NULL); | 206 | spte = rmap_next(kvm, rmapp, NULL); |
| 203 | while (spte) { | 207 | while (spte) { |
| 204 | if (is_writable_pte(*spte)) | 208 | if (is_writable_pte(*spte)) |
| 205 | audit_printk("shadow page has writable mappings: gfn " | 209 | audit_printk(kvm, "shadow page has writable " |
| 206 | "%llx role %x\n", sp->gfn, sp->role.word); | 210 | "mappings: gfn %llx role %x\n", |
| 211 | sp->gfn, sp->role.word); | ||
| 207 | spte = rmap_next(kvm, rmapp, spte); | 212 | spte = rmap_next(kvm, rmapp, spte); |
| 208 | } | 213 | } |
| 209 | } | 214 | } |
| @@ -238,7 +243,7 @@ static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int point) | |||
| 238 | if (!__ratelimit(&ratelimit_state)) | 243 | if (!__ratelimit(&ratelimit_state)) |
| 239 | return; | 244 | return; |
| 240 | 245 | ||
| 241 | audit_point = point; | 246 | vcpu->kvm->arch.audit_point = point; |
| 242 | audit_all_active_sps(vcpu->kvm); | 247 | audit_all_active_sps(vcpu->kvm); |
| 243 | audit_vcpu_spte(vcpu); | 248 | audit_vcpu_spte(vcpu); |
| 244 | } | 249 | } |
