18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mmu_audit.c: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Audit code for KVM MMU 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 Qumranet, Inc. 88c2ecf20Sopenharmony_ci * Copyright 2010 Red Hat, Inc. and/or its affiliates. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Authors: 118c2ecf20Sopenharmony_ci * Yaniv Kamay <yaniv@qumranet.com> 128c2ecf20Sopenharmony_ci * Avi Kivity <avi@qumranet.com> 138c2ecf20Sopenharmony_ci * Marcelo Tosatti <mtosatti@redhat.com> 148c2ecf20Sopenharmony_ci * Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic char const *audit_point_name[] = { 208c2ecf20Sopenharmony_ci "pre page fault", 218c2ecf20Sopenharmony_ci "post page fault", 228c2ecf20Sopenharmony_ci "pre pte write", 238c2ecf20Sopenharmony_ci "post pte write", 248c2ecf20Sopenharmony_ci "pre sync", 258c2ecf20Sopenharmony_ci "post sync" 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define audit_printk(kvm, fmt, args...) \ 298c2ecf20Sopenharmony_ci printk(KERN_ERR "audit: (%s) error: " \ 308c2ecf20Sopenharmony_ci fmt, audit_point_name[kvm->arch.audit_point], ##args) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_citypedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, 358c2ecf20Sopenharmony_ci inspect_spte_fn fn, int level) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int i; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { 408c2ecf20Sopenharmony_ci u64 *ent = sp->spt; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci fn(vcpu, ent + i, level); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (is_shadow_present_pte(ent[i]) && 458c2ecf20Sopenharmony_ci !is_last_spte(ent[i], level)) { 468c2ecf20Sopenharmony_ci struct kvm_mmu_page *child; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci child = to_shadow_page(ent[i] & PT64_BASE_ADDR_MASK); 498c2ecf20Sopenharmony_ci __mmu_spte_walk(vcpu, child, fn, level - 1); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int i; 578c2ecf20Sopenharmony_ci struct kvm_mmu_page *sp; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (vcpu->arch.mmu->root_level >= PT64_ROOT_4LEVEL) { 638c2ecf20Sopenharmony_ci hpa_t root = vcpu->arch.mmu->root_hpa; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci sp = to_shadow_page(root); 668c2ecf20Sopenharmony_ci __mmu_spte_walk(vcpu, sp, fn, vcpu->arch.mmu->root_level); 678c2ecf20Sopenharmony_ci return; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 718c2ecf20Sopenharmony_ci hpa_t root = vcpu->arch.mmu->pae_root[i]; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (root && VALID_PAGE(root)) { 748c2ecf20Sopenharmony_ci root &= PT64_BASE_ADDR_MASK; 758c2ecf20Sopenharmony_ci sp = to_shadow_page(root); 768c2ecf20Sopenharmony_ci __mmu_spte_walk(vcpu, sp, fn, 2); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_citypedef void (*sp_handler) (struct kvm *kvm, struct kvm_mmu_page *sp); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void walk_all_active_sps(struct kvm *kvm, sp_handler fn) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct kvm_mmu_page *sp; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) 908c2ecf20Sopenharmony_ci fn(kvm, sp); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct kvm_mmu_page *sp; 968c2ecf20Sopenharmony_ci gfn_t gfn; 978c2ecf20Sopenharmony_ci kvm_pfn_t pfn; 988c2ecf20Sopenharmony_ci hpa_t hpa; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci sp = sptep_to_sp(sptep); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (sp->unsync) { 1038c2ecf20Sopenharmony_ci if (level != PG_LEVEL_4K) { 1048c2ecf20Sopenharmony_ci audit_printk(vcpu->kvm, "unsync sp: %p " 1058c2ecf20Sopenharmony_ci "level = %d\n", sp, level); 1068c2ecf20Sopenharmony_ci return; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level)) 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); 1148c2ecf20Sopenharmony_ci pfn = kvm_vcpu_gfn_to_pfn_atomic(vcpu, gfn); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (is_error_pfn(pfn)) 1178c2ecf20Sopenharmony_ci return; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci hpa = pfn << PAGE_SHIFT; 1208c2ecf20Sopenharmony_ci if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) 1218c2ecf20Sopenharmony_ci audit_printk(vcpu->kvm, "levels %d pfn %llx hpa %llx " 1228c2ecf20Sopenharmony_ci "ent %llxn", vcpu->arch.mmu->root_level, pfn, 1238c2ecf20Sopenharmony_ci hpa, *sptep); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); 1298c2ecf20Sopenharmony_ci struct kvm_rmap_head *rmap_head; 1308c2ecf20Sopenharmony_ci struct kvm_mmu_page *rev_sp; 1318c2ecf20Sopenharmony_ci struct kvm_memslots *slots; 1328c2ecf20Sopenharmony_ci struct kvm_memory_slot *slot; 1338c2ecf20Sopenharmony_ci gfn_t gfn; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci rev_sp = sptep_to_sp(sptep); 1368c2ecf20Sopenharmony_ci gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci slots = kvm_memslots_for_spte_role(kvm, rev_sp->role); 1398c2ecf20Sopenharmony_ci slot = __gfn_to_memslot(slots, gfn); 1408c2ecf20Sopenharmony_ci if (!slot) { 1418c2ecf20Sopenharmony_ci if (!__ratelimit(&ratelimit_state)) 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci audit_printk(kvm, "no memslot for gfn %llx\n", gfn); 1448c2ecf20Sopenharmony_ci audit_printk(kvm, "index %ld of sp (gfn=%llx)\n", 1458c2ecf20Sopenharmony_ci (long int)(sptep - rev_sp->spt), rev_sp->gfn); 1468c2ecf20Sopenharmony_ci dump_stack(); 1478c2ecf20Sopenharmony_ci return; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci rmap_head = __gfn_to_rmap(gfn, rev_sp->role.level, slot); 1518c2ecf20Sopenharmony_ci if (!rmap_head->val) { 1528c2ecf20Sopenharmony_ci if (!__ratelimit(&ratelimit_state)) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci audit_printk(kvm, "no rmap for writable spte %llx\n", 1558c2ecf20Sopenharmony_ci *sptep); 1568c2ecf20Sopenharmony_ci dump_stack(); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level)) 1638c2ecf20Sopenharmony_ci inspect_spte_has_rmap(vcpu->kvm, sptep); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void audit_spte_after_sync(struct kvm_vcpu *vcpu, u64 *sptep, int level) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct kvm_mmu_page *sp = sptep_to_sp(sptep); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.audit_point == AUDIT_POST_SYNC && sp->unsync) 1718c2ecf20Sopenharmony_ci audit_printk(vcpu->kvm, "meet unsync sp(%p) after sync " 1728c2ecf20Sopenharmony_ci "root.\n", sp); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci int i; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (sp->role.level != PG_LEVEL_4K) 1808c2ecf20Sopenharmony_ci return; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { 1838c2ecf20Sopenharmony_ci if (!is_shadow_present_pte(sp->spt[i])) 1848c2ecf20Sopenharmony_ci continue; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci inspect_spte_has_rmap(kvm, sp->spt + i); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct kvm_rmap_head *rmap_head; 1938c2ecf20Sopenharmony_ci u64 *sptep; 1948c2ecf20Sopenharmony_ci struct rmap_iterator iter; 1958c2ecf20Sopenharmony_ci struct kvm_memslots *slots; 1968c2ecf20Sopenharmony_ci struct kvm_memory_slot *slot; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (sp->role.direct || sp->unsync || sp->role.invalid) 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci slots = kvm_memslots_for_spte_role(kvm, sp->role); 2028c2ecf20Sopenharmony_ci slot = __gfn_to_memslot(slots, sp->gfn); 2038c2ecf20Sopenharmony_ci rmap_head = __gfn_to_rmap(sp->gfn, PG_LEVEL_4K, slot); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for_each_rmap_spte(rmap_head, &iter, sptep) { 2068c2ecf20Sopenharmony_ci if (is_writable_pte(*sptep)) 2078c2ecf20Sopenharmony_ci audit_printk(kvm, "shadow page has writable " 2088c2ecf20Sopenharmony_ci "mappings: gfn %llx role %x\n", 2098c2ecf20Sopenharmony_ci sp->gfn, sp->role.word); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci check_mappings_rmap(kvm, sp); 2168c2ecf20Sopenharmony_ci audit_write_protection(kvm, sp); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void audit_all_active_sps(struct kvm *kvm) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci walk_all_active_sps(kvm, audit_sp); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci audit_sptes_have_rmaps(vcpu, sptep, level); 2278c2ecf20Sopenharmony_ci audit_mappings(vcpu, sptep, level); 2288c2ecf20Sopenharmony_ci audit_spte_after_sync(vcpu, sptep, level); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void audit_vcpu_spte(struct kvm_vcpu *vcpu) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci mmu_spte_walk(vcpu, audit_spte); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic bool mmu_audit; 2378c2ecf20Sopenharmony_cistatic struct static_key mmu_audit_key; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!__ratelimit(&ratelimit_state)) 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci vcpu->kvm->arch.audit_point = point; 2478c2ecf20Sopenharmony_ci audit_all_active_sps(vcpu->kvm); 2488c2ecf20Sopenharmony_ci audit_vcpu_spte(vcpu); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic inline void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci if (static_key_false((&mmu_audit_key))) 2548c2ecf20Sopenharmony_ci __kvm_mmu_audit(vcpu, point); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void mmu_audit_enable(void) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (mmu_audit) 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci static_key_slow_inc(&mmu_audit_key); 2638c2ecf20Sopenharmony_ci mmu_audit = true; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void mmu_audit_disable(void) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci if (!mmu_audit) 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci static_key_slow_dec(&mmu_audit_key); 2728c2ecf20Sopenharmony_ci mmu_audit = false; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int mmu_audit_set(const char *val, const struct kernel_param *kp) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci unsigned long enable; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = kstrtoul(val, 10, &enable); 2818c2ecf20Sopenharmony_ci if (ret < 0) 2828c2ecf20Sopenharmony_ci return -EINVAL; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci switch (enable) { 2858c2ecf20Sopenharmony_ci case 0: 2868c2ecf20Sopenharmony_ci mmu_audit_disable(); 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case 1: 2898c2ecf20Sopenharmony_ci mmu_audit_enable(); 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic const struct kernel_param_ops audit_param_ops = { 2998c2ecf20Sopenharmony_ci .set = mmu_audit_set, 3008c2ecf20Sopenharmony_ci .get = param_get_bool, 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciarch_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644); 304