The initial KVM_ARM_VCPU_INIT path holds config_lock while resetting the
vCPU, but repeated initialization of an existing vCPU does not. As a
result, reset_mdcr() can race with VM-wide PMU configuration and
overwrite MDCR_EL2 with a stale counter count.

Take config_lock around the repeated-init checks and reset. The vCPU
ioctl already holds vcpu->mutex, matching the established lock ordering.

Fixes: c8823e51b534 ("KVM: arm64: Fix MDCR_EL2.HPMN reset value")
Closes: 
https://sashiko.dev/#/patchset/[email protected]?part=1
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Akihiko Odaki <[email protected]>
---
 arch/arm64/kvm/arm.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50adfff75be8..a06ea39f57b1 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1652,29 +1652,26 @@ static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
 {
        unsigned long features = init->features[0];
        struct kvm *kvm = vcpu->kvm;
-       int ret = -EINVAL;
+       int ret;
 
-       mutex_lock(&kvm->arch.config_lock);
+       lockdep_assert_held(&kvm->arch.config_lock);
 
        if (test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags) 
&&
            kvm_vcpu_init_changed(vcpu, init))
-               goto out_unlock;
+               return -EINVAL;
 
        bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES);
 
        ret = kvm_setup_vcpu(vcpu);
        if (ret)
-               goto out_unlock;
+               return ret;
 
        /* Now we know what it is, we can reset it. */
        kvm_reset_vcpu(vcpu);
 
        set_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags);
        vcpu_set_flag(vcpu, VCPU_INITIALIZED);
-       ret = 0;
-out_unlock:
-       mutex_unlock(&kvm->arch.config_lock);
-       return ret;
+       return 0;
 }
 
 static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
@@ -1690,6 +1687,8 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
        if (ret)
                return ret;
 
+       guard(mutex)(&vcpu->kvm->arch.config_lock);
+
        if (!kvm_vcpu_initialized(vcpu))
                return __kvm_vcpu_set_target(vcpu, init);
 

-- 
2.55.0


Reply via email to