aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Jones <drjones@redhat.com>2017-04-18 11:59:58 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-20 08:28:36 -0400
commit7b0d4391d0f4970601b21f56c540fc368bb8be06 (patch)
treebfa3aa35ef3d9f019a4fa63fc04e1cd17f60e618
parentbdf1d5b4c12959f4473e60cde44bfa1a2ebbf44f (diff)
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 c2b131527a64..a08d7a93aebb 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -208,9 +208,10 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
208 208
209static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) 209static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
210{ 210{
211 int ret = 1; 211 struct kvm *kvm = vcpu->kvm;
212 unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); 212 unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
213 unsigned long val; 213 unsigned long val;
214 int ret = 1;
214 215
215 switch (psci_fn) { 216 switch (psci_fn) {
216 case PSCI_0_2_FN_PSCI_VERSION: 217 case PSCI_0_2_FN_PSCI_VERSION:
@@ -230,7 +231,9 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
230 break; 231 break;
231 case PSCI_0_2_FN_CPU_ON: 232 case PSCI_0_2_FN_CPU_ON:
232 case PSCI_0_2_FN64_CPU_ON: 233 case PSCI_0_2_FN64_CPU_ON:
234 mutex_lock(&kvm->lock);
233 val = kvm_psci_vcpu_on(vcpu); 235 val = kvm_psci_vcpu_on(vcpu);
236 mutex_unlock(&kvm->lock);
234 break; 237 break;
235 case PSCI_0_2_FN_AFFINITY_INFO: 238 case PSCI_0_2_FN_AFFINITY_INFO:
236 case PSCI_0_2_FN64_AFFINITY_INFO: 239 case PSCI_0_2_FN64_AFFINITY_INFO:
@@ -279,6 +282,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
279 282
280static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) 283static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
281{ 284{
285 struct kvm *kvm = vcpu->kvm;
282 unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); 286 unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
283 unsigned long val; 287 unsigned long val;
284 288
@@ -288,7 +292,9 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
288 val = PSCI_RET_SUCCESS; 292 val = PSCI_RET_SUCCESS;
289 break; 293 break;
290 case KVM_PSCI_FN_CPU_ON: 294 case KVM_PSCI_FN_CPU_ON:
295 mutex_lock(&kvm->lock);
291 val = kvm_psci_vcpu_on(vcpu); 296 val = kvm_psci_vcpu_on(vcpu);
297 mutex_unlock(&kvm->lock);
292 break; 298 break;
293 default: 299 default:
294 val = PSCI_RET_NOT_SUPPORTED; 300 val = PSCI_RET_NOT_SUPPORTED;