blob: dcca3e7d7b4ef7074638241430ab61beea86b3c9 [file] [log] [blame]
Xiao Guangrong2f4f3372010-08-30 18:24:10 +08001/*
2 * mmu_audit.c:
3 *
4 * Audit code for KVM MMU
5 *
6 * Copyright (C) 2006 Qumranet, Inc.
7 * Copyright 2010 Red Hat, Inc. and/or its affilates.
8 *
9 * Authors:
10 * Yaniv Kamay <yaniv@qumranet.com>
11 * Avi Kivity <avi@qumranet.com>
12 * Marcelo Tosatti <mtosatti@redhat.com>
13 * Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
14 *
15 * This work is licensed under the terms of the GNU GPL, version 2. See
16 * the COPYING file in the top-level directory.
17 *
18 */
19
Xiao Guangrong30644b92010-08-30 18:26:33 +080020#include <linux/ratelimit.h>
21
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080022static const char *audit_msg;
23
Xiao Guangrongeb259182010-08-30 18:25:51 +080024typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080025
Xiao Guangrongeb259182010-08-30 18:25:51 +080026static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
27 inspect_spte_fn fn, int level)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080028{
29 int i;
30
31 for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
Xiao Guangrongeb259182010-08-30 18:25:51 +080032 u64 *ent = sp->spt;
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080033
Xiao Guangrongeb259182010-08-30 18:25:51 +080034 fn(vcpu, ent + i, level);
35
36 if (is_shadow_present_pte(ent[i]) &&
37 !is_last_spte(ent[i], level)) {
38 struct kvm_mmu_page *child;
39
40 child = page_header(ent[i] & PT64_BASE_ADDR_MASK);
41 __mmu_spte_walk(vcpu, child, fn, level - 1);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080042 }
43 }
44}
45
46static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
47{
48 int i;
49 struct kvm_mmu_page *sp;
50
51 if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
52 return;
Xiao Guangrongeb259182010-08-30 18:25:51 +080053
Xiao Guangrong98224bf2010-09-27 18:06:16 +080054 if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080055 hpa_t root = vcpu->arch.mmu.root_hpa;
Xiao Guangrongeb259182010-08-30 18:25:51 +080056
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080057 sp = page_header(root);
Xiao Guangrongeb259182010-08-30 18:25:51 +080058 __mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080059 return;
60 }
Xiao Guangrongeb259182010-08-30 18:25:51 +080061
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080062 for (i = 0; i < 4; ++i) {
63 hpa_t root = vcpu->arch.mmu.pae_root[i];
64
65 if (root && VALID_PAGE(root)) {
66 root &= PT64_BASE_ADDR_MASK;
67 sp = page_header(root);
Xiao Guangrongeb259182010-08-30 18:25:51 +080068 __mmu_spte_walk(vcpu, sp, fn, 2);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080069 }
70 }
Xiao Guangrongeb259182010-08-30 18:25:51 +080071
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080072 return;
73}
74
Xiao Guangrong49edf872010-08-30 18:25:03 +080075typedef void (*sp_handler) (struct kvm *kvm, struct kvm_mmu_page *sp);
76
77static void walk_all_active_sps(struct kvm *kvm, sp_handler fn)
78{
79 struct kvm_mmu_page *sp;
80
81 list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link)
82 fn(kvm, sp);
83}
84
Xiao Guangrongeb259182010-08-30 18:25:51 +080085static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080086{
Xiao Guangrongeb259182010-08-30 18:25:51 +080087 struct kvm_mmu_page *sp;
88 gfn_t gfn;
89 pfn_t pfn;
90 hpa_t hpa;
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080091
Xiao Guangrongeb259182010-08-30 18:25:51 +080092 sp = page_header(__pa(sptep));
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080093
Xiao Guangrongeb259182010-08-30 18:25:51 +080094 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);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +080098 return;
99 }
100
Xiao Guangrongeb259182010-08-30 18:25:51 +0800101 if (*sptep == shadow_notrap_nonpresent_pte) {
102 printk(KERN_ERR "audit: (%s) error: notrap spte in unsync sp: %p\n",
103 audit_msg, sp);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800104 return;
105 }
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800106 }
Xiao Guangrongeb259182010-08-30 18:25:51 +0800107
108 if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) {
109 printk(KERN_ERR "audit: (%s) error: notrap spte in direct sp: %p\n",
110 audit_msg, sp);
111 return;
112 }
113
114 if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level))
115 return;
116
117 gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
118 pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
119
120 if (is_error_pfn(pfn)) {
121 kvm_release_pfn_clean(pfn);
122 return;
123 }
124
125 hpa = pfn << PAGE_SHIFT;
126 if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
127 printk(KERN_ERR "xx audit error: (%s) levels %d"
128 "pfn %llx hpa %llx ent %llxn",
129 audit_msg, vcpu->arch.mmu.root_level,
130 pfn, hpa, *sptep);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800131}
132
Xiao Guangrongeb259182010-08-30 18:25:51 +0800133static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800134{
135 unsigned long *rmapp;
136 struct kvm_mmu_page *rev_sp;
137 gfn_t gfn;
138
139
140 rev_sp = page_header(__pa(sptep));
141 gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
142
143 if (!gfn_to_memslot(kvm, gfn)) {
144 if (!printk_ratelimit())
145 return;
146 printk(KERN_ERR "%s: no memslot for gfn %llx\n",
147 audit_msg, gfn);
148 printk(KERN_ERR "%s: index %ld of sp (gfn=%llx)\n",
149 audit_msg, (long int)(sptep - rev_sp->spt),
150 rev_sp->gfn);
151 dump_stack();
152 return;
153 }
154
155 rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
156 if (!*rmapp) {
157 if (!printk_ratelimit())
158 return;
159 printk(KERN_ERR "%s: no rmap for writable spte %llx\n",
160 audit_msg, *sptep);
161 dump_stack();
162 }
163}
164
Xiao Guangrongeb259182010-08-30 18:25:51 +0800165static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800166{
Xiao Guangrongeb259182010-08-30 18:25:51 +0800167 if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level))
168 inspect_spte_has_rmap(vcpu->kvm, sptep);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800169}
170
Xiao Guangrong49edf872010-08-30 18:25:03 +0800171static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800172{
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800173 int i;
174
Xiao Guangrong49edf872010-08-30 18:25:03 +0800175 if (sp->role.level != PT_PAGE_TABLE_LEVEL)
176 return;
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800177
Xiao Guangrong49edf872010-08-30 18:25:03 +0800178 for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
179 if (!is_rmap_spte(sp->spt[i]))
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800180 continue;
181
Xiao Guangrong49edf872010-08-30 18:25:03 +0800182 inspect_spte_has_rmap(kvm, sp->spt + i);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800183 }
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800184}
185
Xiao Guangrong49edf872010-08-30 18:25:03 +0800186void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800187{
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800188 struct kvm_memory_slot *slot;
189 unsigned long *rmapp;
190 u64 *spte;
191
Xiao Guangrong49edf872010-08-30 18:25:03 +0800192 if (sp->role.direct || sp->unsync || sp->role.invalid)
193 return;
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800194
Xiao Guangrong49edf872010-08-30 18:25:03 +0800195 slot = gfn_to_memslot(kvm, sp->gfn);
196 rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800197
Xiao Guangrong49edf872010-08-30 18:25:03 +0800198 spte = rmap_next(kvm, rmapp, NULL);
199 while (spte) {
200 if (is_writable_pte(*spte))
201 printk(KERN_ERR "%s: (%s) shadow page has "
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800202 "writable mappings: gfn %llx role %x\n",
203 __func__, audit_msg, sp->gfn,
204 sp->role.word);
Xiao Guangrong49edf872010-08-30 18:25:03 +0800205 spte = rmap_next(kvm, rmapp, spte);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800206 }
207}
208
Xiao Guangrong49edf872010-08-30 18:25:03 +0800209static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
210{
211 check_mappings_rmap(kvm, sp);
212 audit_write_protection(kvm, sp);
213}
214
215static void audit_all_active_sps(struct kvm *kvm)
216{
217 walk_all_active_sps(kvm, audit_sp);
218}
219
Xiao Guangrongeb259182010-08-30 18:25:51 +0800220static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level)
221{
222 audit_sptes_have_rmaps(vcpu, sptep, level);
223 audit_mappings(vcpu, sptep, level);
224}
225
226static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
227{
228 mmu_spte_walk(vcpu, audit_spte);
229}
230
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800231static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point)
232{
Xiao Guangrong30644b92010-08-30 18:26:33 +0800233 static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
234
235 if (!__ratelimit(&ratelimit_state))
236 return;
237
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800238 audit_msg = audit_point_name[audit_point];
Xiao Guangrong49edf872010-08-30 18:25:03 +0800239 audit_all_active_sps(vcpu->kvm);
Xiao Guangrongeb259182010-08-30 18:25:51 +0800240 audit_vcpu_spte(vcpu);
Xiao Guangrong2f4f3372010-08-30 18:24:10 +0800241}
242
243static bool mmu_audit;
244
245static void mmu_audit_enable(void)
246{
247 int ret;
248
249 if (mmu_audit)
250 return;
251
252 ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
253 WARN_ON(ret);
254
255 mmu_audit = true;
256}
257
258static void mmu_audit_disable(void)
259{
260 if (!mmu_audit)
261 return;
262
263 unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
264 tracepoint_synchronize_unregister();
265 mmu_audit = false;
266}
267
268static int mmu_audit_set(const char *val, const struct kernel_param *kp)
269{
270 int ret;
271 unsigned long enable;
272
273 ret = strict_strtoul(val, 10, &enable);
274 if (ret < 0)
275 return -EINVAL;
276
277 switch (enable) {
278 case 0:
279 mmu_audit_disable();
280 break;
281 case 1:
282 mmu_audit_enable();
283 break;
284 default:
285 return -EINVAL;
286 }
287
288 return 0;
289}
290
291static struct kernel_param_ops audit_param_ops = {
292 .set = mmu_audit_set,
293 .get = param_get_bool,
294};
295
296module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644);