[PATCH v2 2/2] KVM: arm64: top up pKVM mapping cache for permission faults
From: Bradley Morgan
Date: Tue Jun 23 2026 - 12:40:47 EST
Permission faults normally only relax an existing leaf, so the fault path
does not top up the memcache.
With pKVM, a permission fault can also replace page mappings with a
PMD mapping. That path needs a fresh pkvm_mapping object, and can
dereference a NULL cache->mapping if the cache was not topped up.
Allocate just that object for pKVM permission faults.
The issue was discovered [1] by Sashiko.
Link: https://lore.kernel.org/all/20260623161545.EA08E1F000E9@xxxxxxxxxxxxxxx/ [1]
Fixes: db14091d8f75 ("KVM: arm64: Stage-2 huge mappings for np-guests")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Bradley Morgan <include@xxxxxxxxx>
---
Changes in v2:
- New patch.
arch/arm64/kvm/mmu.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 6c941aaa10c6..3f57f6825a33 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1177,17 +1177,26 @@ void free_hyp_memcache(struct kvm_hyp_memcache *mc)
__free_hyp_memcache(mc, hyp_mc_free_fn, kvm_host_va, mc);
}
+static int topup_hyp_memcache_mapping(struct kvm_hyp_memcache *mc)
+{
+ if (mc->mapping)
+ return 0;
+
+ mc->mapping = kzalloc_obj(struct pkvm_mapping,
+ GFP_KERNEL_ACCOUNT);
+ return mc->mapping ? 0 : -ENOMEM;
+}
+
int topup_hyp_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages)
{
+ int ret;
+
if (!is_protected_kvm_enabled())
return 0;
- if (!mc->mapping) {
- mc->mapping = kzalloc_obj(struct pkvm_mapping,
- GFP_KERNEL_ACCOUNT);
- if (!mc->mapping)
- return -ENOMEM;
- }
+ ret = topup_hyp_memcache_mapping(mc);
+ if (ret)
+ return ret;
return __topup_hyp_memcache(mc, min_pages, hyp_mc_alloc_fn,
kvm_host_pa, mc);
@@ -2113,7 +2122,9 @@ static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd)
* Permission faults just need to update the existing leaf entry,
* and so normally don't require allocations from the memcache. The
* only exception to this is when dirty logging is enabled at runtime
- * and a write fault needs to collapse a block entry into a table.
+ * and a write fault needs to collapse a block entry into a table. With
+ * pKVM, they may still need a fresh mapping object if the fault turns
+ * page entries into a block entry.
*/
memcache = get_mmu_memcache(s2fd->vcpu);
if (!perm_fault || (memslot_is_logging(s2fd->memslot) &&
@@ -2121,6 +2132,10 @@ static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd)
ret = topup_mmu_memcache(s2fd->vcpu, memcache);
if (ret)
return ret;
+ } else if (is_protected_kvm_enabled()) {
+ ret = topup_hyp_memcache_mapping(memcache);
+ if (ret)
+ return ret;
}
/*
--
2.53.0