mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
KVM: arm64: Don't free hyp pages with pKVM on GICv2
Marc reported that enabling protected mode on a device with GICv2
doesn't fail gracefully as one would expect, and leads to a host
kernel crash.
As it turns out, the first half of pKVM init happens before the vgic
probe, and so by the time we find out we have a GICv2 we're already
committed to keeping the pKVM vectors installed at EL2 -- pKVM rejects
stub HVCs for obvious security reasons. However, the error path on KVM
init leads to teardown_hyp_mode() which unconditionally frees hypervisor
allocations (including the EL2 stacks and per-cpu pages) under the
assumption that a previous cpu_hyp_uninit() execution has reset the
vectors back to the stubs, which is false with pKVM.
Interestingly, host stage-2 protection is not enabled yet at this point,
so this use-after-free may go unnoticed for a while. The issue becomes
more obvious after the finalize_pkvm() call.
Fix this by keeping track of the CPUs on which pKVM is initialized in
the kvm_hyp_initialized per-cpu variable, and use it from
teardown_hyp_mode() to skip freeing pages that are in fact used.
Fixes: a770ee80e6 ("KVM: arm64: pkvm: Disable GICv2 support")
Reported-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Quentin Perret <qperret@google.com>
Link: https://lore.kernel.org/r/20250626101014.1519345-1-qperret@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
9a2b9416fd
commit
0e02219f9c
|
|
@ -2129,7 +2129,7 @@ static void cpu_hyp_init(void *discard)
|
|||
|
||||
static void cpu_hyp_uninit(void *discard)
|
||||
{
|
||||
if (__this_cpu_read(kvm_hyp_initialized)) {
|
||||
if (!is_protected_kvm_enabled() && __this_cpu_read(kvm_hyp_initialized)) {
|
||||
cpu_hyp_reset();
|
||||
__this_cpu_write(kvm_hyp_initialized, 0);
|
||||
}
|
||||
|
|
@ -2345,6 +2345,9 @@ static void __init teardown_hyp_mode(void)
|
|||
|
||||
free_hyp_pgds();
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (per_cpu(kvm_hyp_initialized, cpu))
|
||||
continue;
|
||||
|
||||
free_pages(per_cpu(kvm_arm_hyp_stack_base, cpu), NVHE_STACK_SHIFT - PAGE_SHIFT);
|
||||
|
||||
if (!kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu])
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user