ANDROID: KVM: arm64: Fix missing poison for huge-mapping The entire huge stage-2 mapping must be poisonned when reclaiming. Bug: 278749606 Bug: 409228797 Change-Id: Idd103a80be3f6c110b5d6605c213c8393a57535a Signed-off-by: Vincent Donnefort <vdonnefort@google.com> (cherry picked from commit c56c645543cbb2d40f24125da142d26a754b9a19) Signed-off-by: Lee Jones <joneslee@google.com>
diff --git a/arch/arm64/kvm/hyp/include/nvhe/mm.h b/arch/arm64/kvm/hyp/include/nvhe/mm.h index f0d7262..66bc4b1 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mm.h
@@ -19,7 +19,7 @@ void *hyp_fixmap_map(phys_addr_t phys); void hyp_fixmap_unmap(void); void *hyp_fixblock_map(phys_addr_t phys); void hyp_fixblock_unmap(void); -void hyp_poison_page(phys_addr_t phys); +void hyp_poison_page(phys_addr_t phys, size_t page_size); int hyp_create_idmap(u32 hyp_va_bits); int hyp_map_vectors(void);
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 442569c..9c53190 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -401,7 +401,7 @@ static int relinquish_walker(const struct kvm_pgtable_visit_ctx *ctx, phys += ctx->addr - addr; if (state == PKVM_PAGE_OWNED) { - hyp_poison_page(phys); + hyp_poison_page(phys, PAGE_SIZE); psci_mem_protect_dec(1); } @@ -2770,20 +2770,29 @@ int __pkvm_host_donate_guest(struct pkvm_hyp_vcpu *vcpu, u64 pfn, u64 gfn, return ret; } -void hyp_poison_page(phys_addr_t phys) +void hyp_poison_page(phys_addr_t phys, size_t size) { - void *addr = hyp_fixmap_map(phys); + WARN_ON(!PAGE_ALIGNED(size)); - memset(addr, 0, PAGE_SIZE); - /* - * Prefer kvm_flush_dcache_to_poc() over __clean_dcache_guest_page() - * here as the latter may elide the CMO under the assumption that FWB - * will be enabled on CPUs that support it. This is incorrect for the - * host stage-2 and would otherwise lead to a malicious host potentially - * being able to read the contents of newly reclaimed guest pages. - */ - kvm_flush_dcache_to_poc(addr, PAGE_SIZE); - hyp_fixmap_unmap(); + while (size) { + size_t __size = size == PMD_SIZE ? size : PAGE_SIZE; + void *addr = __fixmap_guest_page(__hyp_va(phys), &__size); + + memset(addr, 0, __size); + + /* + * Prefer kvm_flush_dcache_to_poc() over __clean_dcache_guest_page() + * here as the latter may elide the CMO under the assumption that FWB + * will be enabled on CPUs that support it. This is incorrect for the + * host stage-2 and would otherwise lead to a malicious host potentially + * being able to read the contents of newly reclaimed guest pages. + */ + kvm_flush_dcache_to_poc(addr, __size); + __fixunmap_guest_page(__size); + + size -= __size; + phys += __size; + } } void destroy_hyp_vm_pgt(struct pkvm_hyp_vm *vm) @@ -2825,7 +2834,7 @@ int __pkvm_host_reclaim_page(struct pkvm_hyp_vm *vm, u64 pfn, u64 ipa, u8 order) switch((int)guest_get_page_state(pte, ipa)) { case PKVM_PAGE_OWNED: WARN_ON(__host_check_page_state_range(phys, page_size, PKVM_NOPAGE)); - hyp_poison_page(phys); + hyp_poison_page(phys, page_size); psci_mem_protect_dec(order); break; case PKVM_PAGE_SHARED_BORROWED:
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index f7b6548..caf7c5e 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -1086,7 +1086,7 @@ void pkvm_poison_pvmfw_pages(void) phys_addr_t addr = pvmfw_base; while (npages--) { - hyp_poison_page(addr); + hyp_poison_page(addr, PAGE_SIZE); addr += PAGE_SIZE; } }