aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/mmu_audit.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kvm/mmu_audit.c')
-rw-r--r--arch/x86/kvm/mmu_audit.c148
1 files changed, 69 insertions, 79 deletions
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index 8becb86cd348..3bde186409bf 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -19,23 +19,24 @@
19 19
20static const char *audit_msg; 20static const char *audit_msg;
21 21
22typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); 22typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level);
23 23
24static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, 24static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
25 inspect_spte_fn fn) 25 inspect_spte_fn fn, int level)
26{ 26{
27 int i; 27 int i;
28 28
29 for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { 29 for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
30 u64 ent = sp->spt[i]; 30 u64 *ent = sp->spt;
31 31
32 if (is_shadow_present_pte(ent)) { 32 fn(vcpu, ent + i, level);
33 if (!is_last_spte(ent, sp->role.level)) { 33
34 struct kvm_mmu_page *child; 34 if (is_shadow_present_pte(ent[i]) &&
35 child = page_header(ent & PT64_BASE_ADDR_MASK); 35 !is_last_spte(ent[i], level)) {
36 __mmu_spte_walk(kvm, child, fn); 36 struct kvm_mmu_page *child;
37 } else 37
38 fn(kvm, &sp->spt[i]); 38 child = page_header(ent[i] & PT64_BASE_ADDR_MASK);
39 __mmu_spte_walk(vcpu, child, fn, level - 1);
39 } 40 }
40 } 41 }
41} 42}
@@ -47,21 +48,25 @@ static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
47 48
48 if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) 49 if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
49 return; 50 return;
51
50 if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { 52 if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
51 hpa_t root = vcpu->arch.mmu.root_hpa; 53 hpa_t root = vcpu->arch.mmu.root_hpa;
54
52 sp = page_header(root); 55 sp = page_header(root);
53 __mmu_spte_walk(vcpu->kvm, sp, fn); 56 __mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL);
54 return; 57 return;
55 } 58 }
59
56 for (i = 0; i < 4; ++i) { 60 for (i = 0; i < 4; ++i) {
57 hpa_t root = vcpu->arch.mmu.pae_root[i]; 61 hpa_t root = vcpu->arch.mmu.pae_root[i];
58 62
59 if (root && VALID_PAGE(root)) { 63 if (root && VALID_PAGE(root)) {
60 root &= PT64_BASE_ADDR_MASK; 64 root &= PT64_BASE_ADDR_MASK;
61 sp = page_header(root); 65 sp = page_header(root);
62 __mmu_spte_walk(vcpu->kvm, sp, fn); 66 __mmu_spte_walk(vcpu, sp, fn, 2);
63 } 67 }
64 } 68 }
69
65 return; 70 return;
66} 71}
67 72
@@ -75,80 +80,55 @@ static void walk_all_active_sps(struct kvm *kvm, sp_handler fn)
75 fn(kvm, sp); 80 fn(kvm, sp);
76} 81}
77 82
78static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, 83static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
79 gva_t va, int level)
80{ 84{
81 u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK); 85 struct kvm_mmu_page *sp;
82 int i; 86 gfn_t gfn;
83 gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); 87 pfn_t pfn;
84 88 hpa_t hpa;
85 for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
86 u64 *sptep = pt + i;
87 struct kvm_mmu_page *sp;
88 gfn_t gfn;
89 pfn_t pfn;
90 hpa_t hpa;
91
92 sp = page_header(__pa(sptep));
93
94 if (sp->unsync) {
95 if (level != PT_PAGE_TABLE_LEVEL) {
96 printk(KERN_ERR "audit: (%s) error: unsync sp: %p level = %d\n",
97 audit_msg, sp, level);
98 return;
99 }
100
101 if (*sptep == shadow_notrap_nonpresent_pte) {
102 printk(KERN_ERR "audit: (%s) error: notrap spte in unsync sp: %p\n",
103 audit_msg, sp);
104 return;
105 }
106 }
107 89
108 if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { 90 sp = page_header(__pa(sptep));
109 printk(KERN_ERR "audit: (%s) error: notrap spte in direct sp: %p\n", 91
110 audit_msg, sp); 92 if (sp->unsync) {
93 if (level != PT_PAGE_TABLE_LEVEL) {
94 printk(KERN_ERR "audit: (%s) error: unsync sp: %p level = %d\n",
95 audit_msg, sp, level);
111 return; 96 return;
112 } 97 }
113 98
114 if (!is_shadow_present_pte(*sptep) || 99 if (*sptep == shadow_notrap_nonpresent_pte) {
115 !is_last_spte(*sptep, level)) 100 printk(KERN_ERR "audit: (%s) error: notrap spte in unsync sp: %p\n",
101 audit_msg, sp);
116 return; 102 return;
103 }
104 }
117 105
118 gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); 106 if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) {
119 pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn); 107 printk(KERN_ERR "audit: (%s) error: notrap spte in direct sp: %p\n",
108 audit_msg, sp);
109 return;
110 }
120 111
121 if (is_error_pfn(pfn)) { 112 if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level))
122 kvm_release_pfn_clean(pfn); 113 return;
123 return;
124 }
125 114
126 hpa = pfn << PAGE_SHIFT; 115 gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
116 pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
127 117
128 if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) 118 if (is_error_pfn(pfn)) {
129 printk(KERN_ERR "xx audit error: (%s) levels %d" 119 kvm_release_pfn_clean(pfn);
130 " gva %lx pfn %llx hpa %llx ent %llxn", 120 return;
131 audit_msg, vcpu->arch.mmu.root_level,
132 va, pfn, hpa, *sptep);
133 } 121 }
134}
135 122
136static void audit_mappings(struct kvm_vcpu *vcpu) 123 hpa = pfn << PAGE_SHIFT;
137{ 124 if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
138 unsigned i; 125 printk(KERN_ERR "xx audit error: (%s) levels %d"
139 126 "pfn %llx hpa %llx ent %llxn",
140 if (vcpu->arch.mmu.root_level == 4) 127 audit_msg, vcpu->arch.mmu.root_level,
141 audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4); 128 pfn, hpa, *sptep);
142 else
143 for (i = 0; i < 4; ++i)
144 if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK)
145 audit_mappings_page(vcpu,
146 vcpu->arch.mmu.pae_root[i],
147 i << 30,
148 2);
149} 129}
150 130
151void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) 131static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
152{ 132{
153 unsigned long *rmapp; 133 unsigned long *rmapp;
154 struct kvm_mmu_page *rev_sp; 134 struct kvm_mmu_page *rev_sp;
@@ -180,9 +160,10 @@ void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
180 } 160 }
181} 161}
182 162
183void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu) 163static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level)
184{ 164{
185 mmu_spte_walk(vcpu, inspect_spte_has_rmap); 165 if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level))
166 inspect_spte_has_rmap(vcpu->kvm, sptep);
186} 167}
187 168
188static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) 169static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
@@ -234,13 +215,22 @@ static void audit_all_active_sps(struct kvm *kvm)
234 walk_all_active_sps(kvm, audit_sp); 215 walk_all_active_sps(kvm, audit_sp);
235} 216}
236 217
218static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level)
219{
220 audit_sptes_have_rmaps(vcpu, sptep, level);
221 audit_mappings(vcpu, sptep, level);
222}
223
224static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
225{
226 mmu_spte_walk(vcpu, audit_spte);
227}
228
237static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point) 229static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point)
238{ 230{
239 audit_msg = audit_point_name[audit_point]; 231 audit_msg = audit_point_name[audit_point];
240 audit_all_active_sps(vcpu->kvm); 232 audit_all_active_sps(vcpu->kvm);
241 if (strcmp("pre pte write", audit_msg) != 0) 233 audit_vcpu_spte(vcpu);
242 audit_mappings(vcpu);
243 audit_sptes_have_rmaps(vcpu);
244} 234}
245 235
246static bool mmu_audit; 236static bool mmu_audit;