]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
KVM: arm64: Discard PC update state on vcpu reset
authorMarc Zyngier <maz@kernel.org>
Thu, 12 Mar 2026 14:08:50 +0000 (14:08 +0000)
committerMarc Zyngier <maz@kernel.org>
Sun, 15 Mar 2026 15:11:22 +0000 (15:11 +0000)
Our vcpu reset suffers from a particularly interesting flaw, as it
does not correctly deal with state that will have an effect on the
execution flow out of reset.

Take the following completely random example, never seen in the wild
and that never resulted in a couple of sleepless nights: /s

- vcpu-A issues a PSCI_CPU_OFF using the SMC conduit

- SMC being a trapped instruction (as opposed to HVC which is always
  normally executed), we annotate the vcpu as needing to skip the
  next instruction, which is the SMC itself

- vcpu-A is now safely off

- vcpu-B issues a PSCI_CPU_ON for vcpu-A, providing a starting PC

- vcpu-A gets reset, get the new PC, and is sent on its merry way

- right at the point of entering the guest, we notice that a PC
  increment is pending (remember the earlier SMC?)

- vcpu-A skips its first instruction...

What could possibly go wrong?

Well, I'm glad you asked. For pKVM as a NV guest, that first instruction
is extremely significant, as it indicates whether the CPU is booting
or resuming. Having skipped that instruction, nothing makes any sense
anymore, and CPU hotplugging fails.

This is all caused by the decoupling of PC update from the handling
of an exception that triggers such update, making it non-obvious
what affects what when.

Fix this train wreck by discarding all the PC-affecting state on
vcpu reset.

Fixes: f5e30680616ab ("KVM: arm64: Move __adjust_pc out of line")
Cc: stable@vger.kernel.org
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Link: https://patch.msgid.link/20260312140850.822968-1-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/reset.c

index 959532422d3a3062713739bded194a68474d77e1..b963fd975aacaf46737b1b3ec75b57bbebc3db05 100644 (file)
@@ -247,6 +247,20 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
                        kvm_vcpu_set_be(vcpu);
 
                *vcpu_pc(vcpu) = target_pc;
+
+               /*
+                * We may come from a state where either a PC update was
+                * pending (SMC call resulting in PC being increpented to
+                * skip the SMC) or a pending exception. Make sure we get
+                * rid of all that, as this cannot be valid out of reset.
+                *
+                * Note that clearing the exception mask also clears PC
+                * updates, but that's an implementation detail, and we
+                * really want to make it explicit.
+                */
+               vcpu_clear_flag(vcpu, PENDING_EXCEPTION);
+               vcpu_clear_flag(vcpu, EXCEPT_MASK);
+               vcpu_clear_flag(vcpu, INCREMENT_PC);
                vcpu_set_reg(vcpu, 0, reset_state.r0);
        }