From adc27a4336f9476bcceb1c83cf56e2fdc3ac4a25 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Tue, 16 Sep 2025 08:02:46 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Check PGD alignment when creating a pVM Martijn reported a hypervisor crash when providing pKVM with an undersized PGD allocation. Indeed, although the size of the PGD allocation at EL2 is not under host control, a smaller host-side allocation can lead to providing pKVM with a misaligned PGD, which will cause the guest stage-2 init to fail in a bad way. Specifically, guest_s2_zalloc_pages_exact() expects a successful allocation from hyp_alloc_pages(), which can only happen if the pool has been pre-filled with a physically aligned high-order page. In order to guarantee allocation success in this path, check the host-provided PGD alignment early on. Bug: 443668075 Change-Id: I170963edc5721cf368a506bcdc4b2d0cdb462f78 Fixes: a1ec5c70d3f6 ("KVM: arm64: Add infrastructure to create and track pKVM instances at EL2") Reported-by: Martijn Bogaard Signed-off-by: Quentin Perret (cherry picked from commit 749cf1743eb22eff1851c68a533147e1af97a9bf) Signed-off-by: Lee Jones --- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 2 +- arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 1016c7935dd0..e5d7081ec545 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -218,7 +218,7 @@ static void *guest_s2_zalloc_pages_exact(size_t size) { void *addr = hyp_alloc_pages(¤t_vm->pool, get_order(size)); - WARN_ON(size != (PAGE_SIZE << get_order(size))); + WARN_ON(!addr || size != (PAGE_SIZE << get_order(size))); hyp_split_page(hyp_virt_to_page(addr)); return addr; diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 89e70cb906a7..f081ac2ec43e 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -857,6 +857,8 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long pgd_hva) ret = -EINVAL; pgd_size = kvm_pgtable_stage2_pgd_size(host_mmu.arch.mmu.vtcr); + if (!IS_ALIGNED(pgd_hva, pgd_size)) + goto err_free_last_ran; pgd = map_donated_memory_noclear(pgd_hva, pgd_size); if (!pgd) goto err_free_last_ran;