From 5b2287bddcae9078d9f82ac4bc5c7c8e56ef45a6 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Tue, 25 Oct 2022 16:06:39 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Add a permission fault handler In preparation for allowing to restrict host permissions at stage-2 for certain pages, introduce some infrastructure allowing a pKVM module to register a permission fault handler. Bug: 244543039 Bug: 244373730 Change-Id: I8035c64969cc0ebb01c8936b1974b3bc103ba84f Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pkvm_module.h | 1 + arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 1 + arch/arm64/kvm/hyp/nvhe/mem_protect.c | 18 ++++++++++++++++++ arch/arm64/kvm/hyp/nvhe/modules.c | 1 + 4 files changed, 21 insertions(+) diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h index 49f3b0ff2549..9967b3c2eac7 100644 --- a/arch/arm64/include/asm/kvm_pkvm_module.h +++ b/arch/arm64/include/asm/kvm_pkvm_module.h @@ -16,6 +16,7 @@ struct pkvm_module_ops { void *(*fixmap_map)(phys_addr_t phys); void (*fixmap_unmap)(void); void (*flush_dcache_to_poc)(void *addr, size_t size); + int (*register_host_perm_fault_handler)(int (*cb)(struct kvm_cpu_context *ctxt, u64 esr, u64 addr)); }; struct pkvm_module_section { diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index e9a3c0740cf6..d532d4a53b3f 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -92,6 +92,7 @@ int kvm_host_prepare_stage2(void *pgt_pool_base); int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd); void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt); +int hyp_register_host_perm_fault_handler(int (*cb)(struct kvm_cpu_context *ctxt, u64 esr, u64 addr)); int hyp_pin_shared_mem(void *from, void *to); void hyp_unpin_shared_mem(void *from, void *to); void reclaim_guest_pages(struct pkvm_hyp_vm *vm, struct kvm_hyp_memcache *mc); diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index fbebff2e088c..f46f5af4f840 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -717,6 +717,21 @@ static bool is_dabt(u64 esr) return ESR_ELx_EC(esr) == ESR_ELx_EC_DABT_LOW; } +static int (*perm_fault_handler)(struct kvm_cpu_context *host_ctxt, u64 esr, u64 addr); + +int hyp_register_host_perm_fault_handler(int (*cb)(struct kvm_cpu_context *ctxt, u64 esr, u64 addr)) +{ + return cmpxchg(&perm_fault_handler, NULL, cb) ? -EBUSY : 0; +} + +static int handle_host_perm_fault(struct kvm_cpu_context *host_ctxt, u64 esr, u64 addr) +{ + int (*cb)(struct kvm_cpu_context *host_ctxt, u64 esr, u64 addr); + + cb = READ_ONCE(perm_fault_handler); + return cb ? cb(host_ctxt, esr, addr) : -EPERM; +} + void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) { struct kvm_vcpu_fault_info fault; @@ -742,6 +757,9 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) host_unlock_component(); + if ((esr & ESR_ELx_FSC_TYPE) == FSC_PERM) + ret = handle_host_perm_fault(host_ctxt, esr, addr); + if (ret == -EPERM) host_inject_abort(host_ctxt); else diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c index c91488716557..e4bbfc60c6c4 100644 --- a/arch/arm64/kvm/hyp/nvhe/modules.c +++ b/arch/arm64/kvm/hyp/nvhe/modules.c @@ -22,6 +22,7 @@ const struct pkvm_module_ops module_ops = { .fixmap_map = hyp_fixmap_map, .fixmap_unmap = hyp_fixmap_unmap, .flush_dcache_to_poc = __kvm_flush_dcache_to_poc, + .register_host_perm_fault_handler = hyp_register_host_perm_fault_handler, }; int __pkvm_init_module(void *module_init)