diff options
Diffstat (limited to 'arch/x86/kvm/mmu_audit.c')
-rw-r--r-- | arch/x86/kvm/mmu_audit.c | 148 |
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 | ||
20 | static const char *audit_msg; | 20 | static const char *audit_msg; |
21 | 21 | ||
22 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); | 22 | typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level); |
23 | 23 | ||
24 | static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, | 24 | static 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 | ||
78 | static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, | 83 | static 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 | ||
136 | static 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 | ||
151 | void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) | 131 | static 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 | ||
183 | void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu) | 163 | static 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 | ||
188 | static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) | 169 | static 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 | ||
218 | static 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 | |||
224 | static void audit_vcpu_spte(struct kvm_vcpu *vcpu) | ||
225 | { | ||
226 | mmu_spte_walk(vcpu, audit_spte); | ||
227 | } | ||
228 | |||
237 | static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point) | 229 | static 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 | ||
246 | static bool mmu_audit; | 236 | static bool mmu_audit; |