summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndrew Jones <drjones@redhat.com>2017-04-18 17:59:58 +0200
committerBen Hutchings <ben@decadent.org.uk>2017-08-26 02:14:36 +0100
commit7c2173a8169111df531cd75cb967ea3a01ded682 (patch)
treef18500193c401368343f1d4765e2fe1464d399db /arch
parent2c30708e811c261a491db247771f2829697aaffa (diff)
downloadlinux-stable-7c2173a8169111df531cd75cb967ea3a01ded682.tar.gz
linux-stable-7c2173a8169111df531cd75cb967ea3a01ded682.tar.bz2
linux-stable-7c2173a8169111df531cd75cb967ea3a01ded682.zip
KVM: arm/arm64: fix races in kvm_psci_vcpu_on
commit 6c7a5dce22b3f3cc44be098e2837fa6797edb8b8 upstream. Fix potential races in kvm_psci_vcpu_on() by taking the kvm->lock mutex. In general, it's a bad idea to allow more than one PSCI_CPU_ON to process the same target VCPU at the same time. One such problem that may arise is that one PSCI_CPU_ON could be resetting the target vcpu, which fills the entire sys_regs array with a temporary value including the MPIDR register, while another looks up the VCPU based on the MPIDR value, resulting in no target VCPU found. Resolves both races found with the kvm-unit-tests/arm/psci unit test. Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Reviewed-by: Christoffer Dall <cdall@linaro.org> Reported-by: Levente Kurusa <lkurusa@redhat.com> Suggested-by: Christoffer Dall <cdall@linaro.org> Signed-off-by: Andrew Jones <drjones@redhat.com> Signed-off-by: Christoffer Dall <cdall@linaro.org> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kvm/psci.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index 09cf37737ee2..5030facb4aaf 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -191,9 +191,10 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
{
- int ret = 1;
+ struct kvm *kvm = vcpu->kvm;
unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
+ int ret = 1;
switch (psci_fn) {
case PSCI_0_2_FN_PSCI_VERSION:
@@ -213,7 +214,9 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
break;
case PSCI_0_2_FN_CPU_ON:
case PSCI_0_2_FN64_CPU_ON:
+ mutex_lock(&kvm->lock);
val = kvm_psci_vcpu_on(vcpu);
+ mutex_unlock(&kvm->lock);
break;
case PSCI_0_2_FN_AFFINITY_INFO:
case PSCI_0_2_FN64_AFFINITY_INFO:
@@ -269,6 +272,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
{
+ struct kvm *kvm = vcpu->kvm;
unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
@@ -278,7 +282,9 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
val = PSCI_RET_SUCCESS;
break;
case KVM_PSCI_FN_CPU_ON:
+ mutex_lock(&kvm->lock);
val = kvm_psci_vcpu_on(vcpu);
+ mutex_unlock(&kvm->lock);
break;
case KVM_PSCI_FN_CPU_SUSPEND:
case KVM_PSCI_FN_MIGRATE: