Commit eb259186 authored by Xiao Guangrong's avatar Xiao Guangrong Committed by Avi Kivity

KVM: MMU: improve spte audit

Both audit_mappings() and audit_sptes_have_rmaps() need to walk vcpu's page
table, so we can do these checking in a spte walking
Signed-off-by: default avatarXiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 49edf878
...@@ -19,23 +19,24 @@ ...@@ -19,23 +19,24 @@
static const char *audit_msg; static const char *audit_msg;
typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level);
static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
inspect_spte_fn fn) inspect_spte_fn fn, int level)
{ {
int i; int i;
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
u64 ent = sp->spt[i]; u64 *ent = sp->spt;
if (is_shadow_present_pte(ent)) { fn(vcpu, ent + i, level);
if (!is_last_spte(ent, sp->role.level)) {
if (is_shadow_present_pte(ent[i]) &&
!is_last_spte(ent[i], level)) {
struct kvm_mmu_page *child; struct kvm_mmu_page *child;
child = page_header(ent & PT64_BASE_ADDR_MASK);
__mmu_spte_walk(kvm, child, fn); child = page_header(ent[i] & PT64_BASE_ADDR_MASK);
} else __mmu_spte_walk(vcpu, child, fn, level - 1);
fn(kvm, &sp->spt[i]);
} }
} }
} }
...@@ -47,21 +48,25 @@ static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) ...@@ -47,21 +48,25 @@ static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return; return;
if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
hpa_t root = vcpu->arch.mmu.root_hpa; hpa_t root = vcpu->arch.mmu.root_hpa;
sp = page_header(root); sp = page_header(root);
__mmu_spte_walk(vcpu->kvm, sp, fn); __mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL);
return; return;
} }
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
hpa_t root = vcpu->arch.mmu.pae_root[i]; hpa_t root = vcpu->arch.mmu.pae_root[i];
if (root && VALID_PAGE(root)) { if (root && VALID_PAGE(root)) {
root &= PT64_BASE_ADDR_MASK; root &= PT64_BASE_ADDR_MASK;
sp = page_header(root); sp = page_header(root);
__mmu_spte_walk(vcpu->kvm, sp, fn); __mmu_spte_walk(vcpu, sp, fn, 2);
} }
} }
return; return;
} }
...@@ -75,15 +80,8 @@ static void walk_all_active_sps(struct kvm *kvm, sp_handler fn) ...@@ -75,15 +80,8 @@ static void walk_all_active_sps(struct kvm *kvm, sp_handler fn)
fn(kvm, sp); fn(kvm, sp);
} }
static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
gva_t va, int level)
{ {
u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
int i;
gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
u64 *sptep = pt + i;
struct kvm_mmu_page *sp; struct kvm_mmu_page *sp;
gfn_t gfn; gfn_t gfn;
pfn_t pfn; pfn_t pfn;
...@@ -111,8 +109,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, ...@@ -111,8 +109,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
return; return;
} }
if (!is_shadow_present_pte(*sptep) || if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level))
!is_last_spte(*sptep, level))
return; return;
gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
...@@ -124,31 +121,14 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, ...@@ -124,31 +121,14 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
} }
hpa = pfn << PAGE_SHIFT; hpa = pfn << PAGE_SHIFT;
if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
printk(KERN_ERR "xx audit error: (%s) levels %d" printk(KERN_ERR "xx audit error: (%s) levels %d"
" gva %lx pfn %llx hpa %llx ent %llxn", "pfn %llx hpa %llx ent %llxn",
audit_msg, vcpu->arch.mmu.root_level, audit_msg, vcpu->arch.mmu.root_level,
va, pfn, hpa, *sptep); pfn, hpa, *sptep);
}
} }
static void audit_mappings(struct kvm_vcpu *vcpu) static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
{
unsigned i;
if (vcpu->arch.mmu.root_level == 4)
audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4);
else
for (i = 0; i < 4; ++i)
if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK)
audit_mappings_page(vcpu,
vcpu->arch.mmu.pae_root[i],
i << 30,
2);
}
void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
{ {
unsigned long *rmapp; unsigned long *rmapp;
struct kvm_mmu_page *rev_sp; struct kvm_mmu_page *rev_sp;
...@@ -180,9 +160,10 @@ void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) ...@@ -180,9 +160,10 @@ void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
} }
} }
void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu) static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level)
{ {
mmu_spte_walk(vcpu, inspect_spte_has_rmap); if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level))
inspect_spte_has_rmap(vcpu->kvm, sptep);
} }
static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) 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,13 +215,22 @@ static void audit_all_active_sps(struct kvm *kvm)
walk_all_active_sps(kvm, audit_sp); walk_all_active_sps(kvm, audit_sp);
} }
static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level)
{
audit_sptes_have_rmaps(vcpu, sptep, level);
audit_mappings(vcpu, sptep, level);
}
static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
{
mmu_spte_walk(vcpu, audit_spte);
}
static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point) static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point)
{ {
audit_msg = audit_point_name[audit_point]; audit_msg = audit_point_name[audit_point];
audit_all_active_sps(vcpu->kvm); audit_all_active_sps(vcpu->kvm);
if (strcmp("pre pte write", audit_msg) != 0) audit_vcpu_spte(vcpu);
audit_mappings(vcpu);
audit_sptes_have_rmaps(vcpu);
} }
static bool mmu_audit; static bool mmu_audit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment