diff options
author | Andrew Jones <drjones@redhat.com> | 2017-04-18 11:59:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-20 08:28:36 -0400 |
commit | 7b0d4391d0f4970601b21f56c540fc368bb8be06 (patch) | |
tree | bfa3aa35ef3d9f019a4fa63fc04e1cd17f60e618 | |
parent | bdf1d5b4c12959f4473e60cde44bfa1a2ebbf44f (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.c | 8 |
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 | ||
209 | static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | 209 | static 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 | ||
280 | static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | 283 | static 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; |