From 408fad8bb69ed79fef60b6c2b3c4f8b52fb246b1 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Tue, 29 Nov 2022 14:34:55 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Move pKVM host deprivilege to device_initcall In preparation for early loading of pKVM modules (i.e. before deprivilege), move the pKVM finalization in device_initcall. This is needed as modules are found in the initramfs whom unpack starts in the previous initcall. A deprivilege failure now ends-up in erasing the PVM firmware and simply prevent loading of any protected VM. As an interesting side effect, it also allows us to mark the module loading functions as __init. Those functions will then be erased once the init is complete, reducing the attack surface. Bug: 254835242 Change-Id: Ifab4b9167b8924222bc8b6c2a0af529a3f8540c0 Signed-off-by: Vincent Donnefort --- arch/arm64/kvm/arm.c | 20 -------------------- arch/arm64/kvm/pkvm.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 34a909d9b5ae..ea613a7df676 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2271,20 +2271,6 @@ static int pkvm_drop_host_privileges(void) return ret; } -static int finalize_hyp_mode(void) -{ - if (!is_protected_kvm_enabled()) - return 0; - - /* - * Exclude HYP sections from kmemleak so that they don't get peeked - * at, which would end badly once inaccessible. - */ - kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start); - kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size); - return pkvm_drop_host_privileges(); -} - struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr) { struct kvm_vcpu *vcpu; @@ -2400,12 +2386,6 @@ int kvm_arch_init(void *opaque) goto out_hyp; if (!in_hyp_mode) { - err = finalize_hyp_mode(); - if (err) { - kvm_err("Failed to finalize Hyp protection\n"); - goto out_hyp; - } - err = init_hyp_tracefs(); if (err) kvm_err("Failed to initialize Hyp tracing\n"); diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index cb347c4710a0..1672c50fa1d1 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -433,7 +433,7 @@ static int __init pkvm_firmware_rmem_clear(void) void *addr; phys_addr_t size; - if (likely(!pkvm_firmware_mem) || is_protected_kvm_enabled()) + if (likely(!pkvm_firmware_mem)) return 0; kvm_info("Clearing unused pKVM firmware memory\n"); @@ -447,7 +447,32 @@ static int __init pkvm_firmware_rmem_clear(void) memunmap(addr); return 0; } -device_initcall_sync(pkvm_firmware_rmem_clear); + +static int __init finalize_pkvm(void) +{ + int ret; + + if (!is_protected_kvm_enabled()) { + pkvm_firmware_rmem_clear(); + return 0; + } + + /* + * Exclude HYP sections from kmemleak so that they don't get peeked + * at, which would end badly once inaccessible. + */ + kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start); + kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size); + + ret = pkvm_drop_host_privileges(); + if (ret) { + pr_err("Failed to de-privilege the host kernel: %d\n", ret); + pkvm_firmware_rmem_clear(); + } + + return ret; +} +device_initcall_sync(finalize_pkvm); static int pkvm_vm_ioctl_set_fw_ipa(struct kvm *kvm, u64 ipa) {