diff options
author | Andre Przywara <andre.przywara@linaro.org> | 2013-05-08 18:28:06 -0400 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2013-06-03 03:58:56 -0400 |
commit | e8180dcaa8470ceca21109f143876fdcd9fe050a (patch) | |
tree | e5c4f6dc1e1b0fc3aa34e76a15ccefbdd86ac983 /arch/arm/kvm/arm.c | |
parent | ed829857b36bc0155d85b661ab227df57ac898f3 (diff) |
ARM: KVM: prevent NULL pointer dereferences with KVM VCPU ioctl
Some ARM KVM VCPU ioctls require the vCPU to be properly initialized
with the KVM_ARM_VCPU_INIT ioctl before being used with further
requests. KVM_RUN checks whether this initialization has been
done, but other ioctls do not.
Namely KVM_GET_REG_LIST will dereference an array with index -1
without initialization and thus leads to a kernel oops.
Fix this by adding checks before executing the ioctl handlers.
[ Removed superflous comment from static function - Christoffer ]
Changes from v1:
* moved check into a static function with a meaningful name
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
Diffstat (limited to 'arch/arm/kvm/arm.c')
-rw-r--r-- | arch/arm/kvm/arm.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 37d216d814cd..ef1703b9587b 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c | |||
@@ -492,6 +492,11 @@ static void vcpu_pause(struct kvm_vcpu *vcpu) | |||
492 | wait_event_interruptible(*wq, !vcpu->arch.pause); | 492 | wait_event_interruptible(*wq, !vcpu->arch.pause); |
493 | } | 493 | } |
494 | 494 | ||
495 | static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu) | ||
496 | { | ||
497 | return vcpu->arch.target >= 0; | ||
498 | } | ||
499 | |||
495 | /** | 500 | /** |
496 | * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code | 501 | * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code |
497 | * @vcpu: The VCPU pointer | 502 | * @vcpu: The VCPU pointer |
@@ -508,8 +513,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
508 | int ret; | 513 | int ret; |
509 | sigset_t sigsaved; | 514 | sigset_t sigsaved; |
510 | 515 | ||
511 | /* Make sure they initialize the vcpu with KVM_ARM_VCPU_INIT */ | 516 | if (unlikely(!kvm_vcpu_initialized(vcpu))) |
512 | if (unlikely(vcpu->arch.target < 0)) | ||
513 | return -ENOEXEC; | 517 | return -ENOEXEC; |
514 | 518 | ||
515 | ret = kvm_vcpu_first_run_init(vcpu); | 519 | ret = kvm_vcpu_first_run_init(vcpu); |
@@ -710,6 +714,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
710 | case KVM_SET_ONE_REG: | 714 | case KVM_SET_ONE_REG: |
711 | case KVM_GET_ONE_REG: { | 715 | case KVM_GET_ONE_REG: { |
712 | struct kvm_one_reg reg; | 716 | struct kvm_one_reg reg; |
717 | |||
718 | if (unlikely(!kvm_vcpu_initialized(vcpu))) | ||
719 | return -ENOEXEC; | ||
720 | |||
713 | if (copy_from_user(®, argp, sizeof(reg))) | 721 | if (copy_from_user(®, argp, sizeof(reg))) |
714 | return -EFAULT; | 722 | return -EFAULT; |
715 | if (ioctl == KVM_SET_ONE_REG) | 723 | if (ioctl == KVM_SET_ONE_REG) |
@@ -722,6 +730,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
722 | struct kvm_reg_list reg_list; | 730 | struct kvm_reg_list reg_list; |
723 | unsigned n; | 731 | unsigned n; |
724 | 732 | ||
733 | if (unlikely(!kvm_vcpu_initialized(vcpu))) | ||
734 | return -ENOEXEC; | ||
735 | |||
725 | if (copy_from_user(®_list, user_list, sizeof(reg_list))) | 736 | if (copy_from_user(®_list, user_list, sizeof(reg_list))) |
726 | return -EFAULT; | 737 | return -EFAULT; |
727 | n = reg_list.n; | 738 | n = reg_list.n; |