Skip to content

Commit 8234409

Browse files
Fuad TabbaMarc Zyngier
authored andcommitted
KVM: arm64: Pre-check vcpu memcache for host->guest share
__pkvm_host_share_guest() ends with kvm_pgtable_stage2_map() to install the guest stage-2 mapping, after a forward pass that mutates the host vmemmap (sets PKVM_PAGE_SHARED_OWNED and increments host_share_guest_count) for every page in the range. The map's return value is wrapped in WARN_ON() and otherwise discarded, asserting that the call cannot fail. WARN_ON() at nVHE EL2 panics, so this assertion is only correct if the call genuinely cannot fail. kvm_pgtable_stage2_map() can fail with -ENOMEM when the stage-2 walker exhausts the caller's memcache, and the host controls the vcpu memcache via the topup interface, so an under-provisioned share request would otherwise turn a recoverable -ENOMEM into a fatal hyp panic. Bound the worst-case walker allocation in the existing pre-check pass so that kvm_pgtable_stage2_map() cannot fail at the call site, using kvm_mmu_cache_min_pages() -- the same bound host EL1 uses for its own stage-2 maps. If the vcpu memcache holds fewer pages, return -ENOMEM before any state mutation. Fixes: d0bd3e6 ("KVM: arm64: Introduce __pkvm_host_share_guest()") Assisted-by: Gemini:gemini-3.1-pro review-prompts Signed-off-by: Fuad Tabba <tabba@google.com> Link: https://patch.msgid.link/20260501112149.2824881-6-tabba@google.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 5130d45 commit 8234409

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

arch/arm64/kvm/hyp/nvhe/mem_protect.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,22 @@ int __pkvm_host_reclaim_page_guest(u64 gfn, struct pkvm_hyp_vm *vm)
13901390
return ret && ret != -EHWPOISON ? ret : 0;
13911391
}
13921392

1393+
/*
1394+
* share/donate install at most one stage-2 leaf (PAGE_SIZE, or one
1395+
* KVM_PGTABLE_LAST_LEVEL - 1 block for share). kvm_mmu_cache_min_pages()
1396+
* bounds the worst-case allocation: exact for the PAGE_SIZE leaf,
1397+
* conservative by one for the block.
1398+
*/
1399+
static int __guest_check_pgtable_memcache(struct pkvm_hyp_vcpu *vcpu)
1400+
{
1401+
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
1402+
1403+
if (vcpu->vcpu.arch.pkvm_memcache.nr_pages < kvm_mmu_cache_min_pages(vm->pgt.mmu))
1404+
return -ENOMEM;
1405+
1406+
return 0;
1407+
}
1408+
13931409
int __pkvm_host_donate_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu)
13941410
{
13951411
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
@@ -1474,6 +1490,10 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu
14741490
}
14751491
}
14761492

1493+
ret = __guest_check_pgtable_memcache(vcpu);
1494+
if (ret)
1495+
goto unlock;
1496+
14771497
for_each_hyp_page(page, phys, size) {
14781498
set_host_state(page, PKVM_PAGE_SHARED_OWNED);
14791499
page->host_share_guest_count++;

0 commit comments

Comments
 (0)