All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] KVM: syzkaller fixes
@ 2016-06-01 12:09 Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 1/7] kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR Paolo Bonzini
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

These fix most of the bugs reported by Dmitry Vyukov a while back.
I couldn't reproduce one of the bugs (patch 7) but the fix is easy.
Probably, more VM ioctls should take kvm->lock, but I have not looked
at it yet.

I have only marked for stable the two patches that fix an oops.  However,
all of patches 1-6 could go in 4.7-rc, I think.

Thanks,

Paolo

Paolo Bonzini (7):
  kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR
  KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
  KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number
  KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
  KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
  KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS
  KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock

 arch/x86/kvm/cpuid.c |   22 ++++++++++++----------
 arch/x86/kvm/i8254.c |    4 +++-
 arch/x86/kvm/x86.c   |   15 ++++++++++++---
 virt/kvm/irqchip.c   |    2 +-
 virt/kvm/kvm_main.c  |   22 ++++++++++++----------
 5 files changed, 40 insertions(+), 25 deletions(-)

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/7] kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 2/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

Found by syzkaller:

    WARNING: CPU: 3 PID: 15175 at arch/x86/kvm/x86.c:7705 __x86_set_memory_region+0x1dc/0x1f0 [kvm]()
    CPU: 3 PID: 15175 Comm: a.out Tainted: G        W       4.4.6-300.fc23.x86_64 #1
    Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012
     0000000000000286 00000000950899a7 ffff88011ab3fbf0 ffffffff813b542e
     0000000000000000 ffffffffa0966496 ffff88011ab3fc28 ffffffff810a40f2
     00000000000001fd 0000000000003000 ffff88014fc50000 0000000000000000
    Call Trace:
     [<ffffffff813b542e>] dump_stack+0x63/0x85
     [<ffffffff810a40f2>] warn_slowpath_common+0x82/0xc0
     [<ffffffff810a423a>] warn_slowpath_null+0x1a/0x20
     [<ffffffffa09251cc>] __x86_set_memory_region+0x1dc/0x1f0 [kvm]
     [<ffffffffa092521b>] x86_set_memory_region+0x3b/0x60 [kvm]
     [<ffffffffa09bb61c>] vmx_set_tss_addr+0x3c/0x150 [kvm_intel]
     [<ffffffffa092f4d4>] kvm_arch_vm_ioctl+0x654/0xbc0 [kvm]
     [<ffffffffa091d31a>] kvm_vm_ioctl+0x9a/0x6f0 [kvm]
     [<ffffffff81241248>] do_vfs_ioctl+0x298/0x480
     [<ffffffff812414a9>] SyS_ioctl+0x79/0x90
     [<ffffffff817a04ee>] entry_SYSCALL_64_fastpath+0x12/0x71

Testcase:

    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <string.h>
    #include <linux/kvm.h>

    long r[8];

    int main()
    {
        memset(r, -1, sizeof(r));
	r[2] = open("/dev/kvm", O_RDONLY|O_TRUNC);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0x0ul);
        r[5] = ioctl(r[3], KVM_SET_TSS_ADDR, 0x20000000ul);
        r[7] = ioctl(r[3], KVM_SET_TSS_ADDR, 0x20000000ul);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/x86.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 199a87c20a98..6c9793c64522 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7828,7 +7828,7 @@ int __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size)
 
 	slot = id_to_memslot(slots, id);
 	if (size) {
-		if (WARN_ON(slot->npages))
+		if (slot->npages)
 			return -EEXIST;
 
 		/*
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 1/7] kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 3/7] KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number Paolo Bonzini
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

This causes an ugly dmesg splat.  Beautified syzkaller testcase:

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <linux/kvm.h>

    long r[8];

    int main()
    {
        struct kvm_cpuid2 c = { 0 };
        r[2] = open("/dev/kvm", O_RDWR);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
        r[4] = ioctl(r[3], KVM_CREATE_VCPU, 0x8);
        r[7] = ioctl(r[4], KVM_SET_CPUID, &c);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/cpuid.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 769af907f824..7597b42a8a88 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -181,19 +181,22 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
 			     struct kvm_cpuid_entry __user *entries)
 {
 	int r, i;
-	struct kvm_cpuid_entry *cpuid_entries;
+	struct kvm_cpuid_entry *cpuid_entries = NULL;
 
 	r = -E2BIG;
 	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
 		goto out;
 	r = -ENOMEM;
-	cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * cpuid->nent);
-	if (!cpuid_entries)
-		goto out;
-	r = -EFAULT;
-	if (copy_from_user(cpuid_entries, entries,
-			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
-		goto out_free;
+	if (cpuid->nent) {
+		cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) *
+					cpuid->nent);
+		if (!cpuid_entries)
+			goto out;
+		r = -EFAULT;
+		if (copy_from_user(cpuid_entries, entries,
+				   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
+			goto out;
+	}
 	for (i = 0; i < cpuid->nent; i++) {
 		vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function;
 		vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax;
@@ -212,9 +215,8 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
 	kvm_x86_ops->cpuid_update(vcpu);
 	r = kvm_update_cpuid(vcpu);
 
-out_free:
-	vfree(cpuid_entries);
 out:
+	vfree(cpuid_entries);
 	return r;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/7] KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 1/7] kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 2/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi Paolo Bonzini
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

This cannot be returned by KVM_GET_VCPU_EVENTS, so it is okay to return
EINVAL.  It causes a WARN from exception_type:

    WARNING: CPU: 3 PID: 16732 at arch/x86/kvm/x86.c:345 exception_type+0x49/0x50 [kvm]()
    CPU: 3 PID: 16732 Comm: a.out Tainted: G        W       4.4.6-300.fc23.x86_64 #1
    Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012
     0000000000000286 000000006308a48b ffff8800bec7fcf8 ffffffff813b542e
     0000000000000000 ffffffffa0966496 ffff8800bec7fd30 ffffffff810a40f2
     ffff8800552a8000 0000000000000000 00000000002c267c 0000000000000001
    Call Trace:
     [<ffffffff813b542e>] dump_stack+0x63/0x85
     [<ffffffff810a40f2>] warn_slowpath_common+0x82/0xc0
     [<ffffffff810a423a>] warn_slowpath_null+0x1a/0x20
     [<ffffffffa0924809>] exception_type+0x49/0x50 [kvm]
     [<ffffffffa0934622>] kvm_arch_vcpu_ioctl_run+0x10a2/0x14e0 [kvm]
     [<ffffffffa091c04d>] kvm_vcpu_ioctl+0x33d/0x620 [kvm]
     [<ffffffff81241248>] do_vfs_ioctl+0x298/0x480
     [<ffffffff812414a9>] SyS_ioctl+0x79/0x90
     [<ffffffff817a04ee>] entry_SYSCALL_64_fastpath+0x12/0x71
    ---[ end trace b1a0391266848f50 ]---

Testcase (beautified/reduced from syzkaller output):

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <string.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/kvm.h>

    long r[31];

    int main()
    {
        memset(r, -1, sizeof(r));
        r[2] = open("/dev/kvm", O_RDONLY);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
        r[7] = ioctl(r[3], KVM_CREATE_VCPU, 0);

        struct kvm_vcpu_events ve = {
                .exception.injected = 1,
                .exception.nr = 0xd4
        };
        r[27] = ioctl(r[7], KVM_SET_VCPU_EVENTS, &ve);
        r[30] = ioctl(r[7], KVM_RUN, 0);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/x86.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6c9793c64522..71284533f0b7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2973,6 +2973,10 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 			      | KVM_VCPUEVENT_VALID_SMM))
 		return -EINVAL;
 
+	if (events->exception.injected &&
+	    (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR))
+		return -EINVAL;
+
 	process_nmi(vcpu);
 	vcpu->arch.exception.pending = events->exception.injected;
 	vcpu->arch.exception.nr = events->exception.nr;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
                   ` (2 preceding siblings ...)
  2016-06-01 12:09 ` [PATCH 3/7] KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2017-01-09 22:39   ` Steve Rutherford
  2016-06-01 12:09 ` [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar, stable

Found by syzkaller:

    BUG: unable to handle kernel NULL pointer dereference at 0000000000000120
    IP: [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
    PGD 6f80b067 PUD b6535067 PMD 0
    Oops: 0000 [#1] SMP
    CPU: 3 PID: 4988 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1
    [...]
    Call Trace:
     [<ffffffffa0795f62>] irqfd_update+0x32/0xc0 [kvm]
     [<ffffffffa0796c7c>] kvm_irqfd+0x3dc/0x5b0 [kvm]
     [<ffffffffa07943f4>] kvm_vm_ioctl+0x164/0x6f0 [kvm]
     [<ffffffff81241648>] do_vfs_ioctl+0x298/0x480
     [<ffffffff812418a9>] SyS_ioctl+0x79/0x90
     [<ffffffff817a1062>] tracesys_phase2+0x84/0x89
    Code: b5 71 a7 e0 5b 41 5c 41 5d 5d f3 c3 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 8b 8f 10 2e 00 00 31 c0 48 89 e5 <39> 91 20 01 00 00 76 6a 48 63 d2 48 8b 94 d1 28 01 00 00 48 85
    RIP  [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
     RSP <ffff8800926cbca8>
    CR2: 0000000000000120

Testcase:

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <string.h>
    #include <stdint.h>
    #include <linux/kvm.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>

    long r[26];

    int main()
    {
        memset(r, -1, sizeof(r));
        r[2] = open("/dev/kvm", 0);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);

        struct kvm_irqfd ifd;
        ifd.fd = syscall(SYS_eventfd2, 5, 0);
        ifd.gsi = 3;
        ifd.flags = 2;
        ifd.resamplefd = ifd.fd;
        r[25] = ioctl(r[3], KVM_IRQFD, &ifd);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 virt/kvm/irqchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index fe84e1a95dd5..8db197bb6c7a 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -40,7 +40,7 @@ int kvm_irq_map_gsi(struct kvm *kvm,
 
 	irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
 					lockdep_is_held(&kvm->irq_lock));
-	if (gsi < irq_rt->nr_rt_entries) {
+	if (irq_rt && gsi < irq_rt->nr_rt_entries) {
 		hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
 			entries[n] = *e;
 			++n;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
                   ` (3 preceding siblings ...)
  2016-06-01 12:09 ` [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-04 23:55   ` Wanpeng Li
  2016-06-01 12:09 ` [PATCH 6/7] KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS Paolo Bonzini
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

This causes an ugly dmesg splat.  Beautified syzkaller testcase:

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <linux/kvm.h>

    long r[8];

    int main()
    {
        struct kvm_irq_routing ir = { 0 };
        r[2] = open("/dev/kvm", O_RDWR);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
        r[4] = ioctl(r[3], KVM_SET_GSI_ROUTING, &ir);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 virt/kvm/kvm_main.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 37af23052470..02e98f3131bd 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2935,7 +2935,7 @@ static long kvm_vm_ioctl(struct file *filp,
 	case KVM_SET_GSI_ROUTING: {
 		struct kvm_irq_routing routing;
 		struct kvm_irq_routing __user *urouting;
-		struct kvm_irq_routing_entry *entries;
+		struct kvm_irq_routing_entry *entries = NULL;
 
 		r = -EFAULT;
 		if (copy_from_user(&routing, argp, sizeof(routing)))
@@ -2945,15 +2945,17 @@ static long kvm_vm_ioctl(struct file *filp,
 			goto out;
 		if (routing.flags)
 			goto out;
-		r = -ENOMEM;
-		entries = vmalloc(routing.nr * sizeof(*entries));
-		if (!entries)
-			goto out;
-		r = -EFAULT;
-		urouting = argp;
-		if (copy_from_user(entries, urouting->entries,
-				   routing.nr * sizeof(*entries)))
-			goto out_free_irq_routing;
+		if (routing.nr) {
+			r = -ENOMEM;
+			entries = vmalloc(routing.nr * sizeof(*entries));
+			if (!entries)
+				goto out;
+			r = -EFAULT;
+			urouting = argp;
+			if (copy_from_user(entries, urouting->entries,
+					   routing.nr * sizeof(*entries)))
+				goto out_free_irq_routing;
+		}
 		r = kvm_set_irq_routing(kvm, entries, routing.nr,
 					routing.flags);
 out_free_irq_routing:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/7] KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
                   ` (4 preceding siblings ...)
  2016-06-01 12:09 ` [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-01 12:09 ` [PATCH 7/7] KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock Paolo Bonzini
  2016-06-01 16:07 ` [PATCH 0/7] KVM: syzkaller fixes Radim Krčmář
  7 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar, stable

MOV to DR6 or DR7 causes a #GP if an attempt is made to write a 1 to
any of bits 63:32.  However, this is not detected at KVM_SET_DEBUGREGS
time, and the next KVM_RUN oopses:

   general protection fault: 0000 [#1] SMP
   CPU: 2 PID: 14987 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1
   Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012
   [...]
   Call Trace:
    [<ffffffffa072c93d>] kvm_arch_vcpu_ioctl_run+0x141d/0x14e0 [kvm]
    [<ffffffffa071405d>] kvm_vcpu_ioctl+0x33d/0x620 [kvm]
    [<ffffffff81241648>] do_vfs_ioctl+0x298/0x480
    [<ffffffff812418a9>] SyS_ioctl+0x79/0x90
    [<ffffffff817a0f2e>] entry_SYSCALL_64_fastpath+0x12/0x71
   Code: 55 83 ff 07 48 89 e5 77 27 89 ff ff 24 fd 90 87 80 81 0f 23 fe 5d c3 0f 23 c6 5d c3 0f 23 ce 5d c3 0f 23 d6 5d c3 0f 23 de 5d c3 <0f> 23 f6 5d c3 0f 0b 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
   RIP  [<ffffffff810639eb>] native_set_debugreg+0x2b/0x40
    RSP <ffff88005836bd50>

Testcase (beautified/reduced from syzkaller output):

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <string.h>
    #include <stdint.h>
    #include <linux/kvm.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>

    long r[8];

    int main()
    {
        struct kvm_debugregs dr = { 0 };

        r[2] = open("/dev/kvm", O_RDONLY);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
        r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7);

        memcpy(&dr,
               "\x5d\x6a\x6b\xe8\x57\x3b\x4b\x7e\xcf\x0d\xa1\x72"
               "\xa3\x4a\x29\x0c\xfc\x6d\x44\x00\xa7\x52\xc7\xd8"
               "\x00\xdb\x89\x9d\x78\xb5\x54\x6b\x6b\x13\x1c\xe9"
               "\x5e\xd3\x0e\x40\x6f\xb4\x66\xf7\x5b\xe3\x36\xcb",
               48);
        r[7] = ioctl(r[4], KVM_SET_DEBUGREGS, &dr);
        r[6] = ioctl(r[4], KVM_RUN, 0);
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/x86.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 71284533f0b7..3fbf88f85a2d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3041,6 +3041,11 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
 	if (dbgregs->flags)
 		return -EINVAL;
 
+	if (dbgregs->dr6 & ~0xffffffffull)
+		return -EINVAL;
+	if (dbgregs->dr7 & ~0xffffffffull)
+		return -EINVAL;
+
 	memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
 	kvm_update_dr0123(vcpu);
 	vcpu->arch.dr6 = dbgregs->dr6;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/7] KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
                   ` (5 preceding siblings ...)
  2016-06-01 12:09 ` [PATCH 6/7] KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS Paolo Bonzini
@ 2016-06-01 12:09 ` Paolo Bonzini
  2016-06-01 16:07 ` [PATCH 0/7] KVM: syzkaller fixes Radim Krčmář
  7 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2016-06-01 12:09 UTC (permalink / raw)
  To: linux-kernel, kvm; +Cc: rkrcmar

The syzkaller folks reported a NULL pointer dereference that seems
to be cause by a race between KVM_CREATE_IRQCHIP and KVM_CREATE_PIT2.
The former takes kvm->lock (except when registering the devices,
which needs kvm->slots_lock); the latter takes kvm->slots_lock only.
Change KVM_CREATE_PIT2 to follow the same model as KVM_CREATE_IRQCHIP.

Testcase:

    #include <pthread.h>
    #include <linux/kvm.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/syscall.h>
    #include <unistd.h>

    long r[23];

    void* thr1(void* arg)
    {
        struct kvm_pit_config pitcfg = { .flags = 4 };
        switch ((long)arg) {
        case 0: r[2]  = open("/dev/kvm", O_RDONLY|O_ASYNC);    break;
        case 1: r[3]  = ioctl(r[2], KVM_CREATE_VM, 0);         break;
        case 2: r[4]  = ioctl(r[3], KVM_CREATE_IRQCHIP, 0);    break;
        case 3: r[22] = ioctl(r[3], KVM_CREATE_PIT2, &pitcfg); break;
        }
        return 0;
    }

    int main(int argc, char **argv)
    {
        long i;
        pthread_t th[4];

        memset(r, -1, sizeof(r));
        for (i = 0; i < 4; i++) {
            pthread_create(&th[i], 0, thr, (void*)i);
            if (argc > 1 && rand()%2) usleep(rand()%1000);
        }
        usleep(20000);
        return 0;
    }

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/i8254.c | 4 +++-
 arch/x86/kvm/x86.c   | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index a4bf5b45d65a..5fb6c620180e 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -645,7 +645,6 @@ static const struct kvm_io_device_ops speaker_dev_ops = {
 	.write    = speaker_ioport_write,
 };
 
-/* Caller must hold slots_lock */
 struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
 	struct kvm_pit *pit;
@@ -690,6 +689,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 
 	kvm_pit_set_reinject(pit, true);
 
+	mutex_lock(&kvm->slots_lock);
 	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
 	ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
 				      KVM_PIT_MEM_LENGTH, &pit->dev);
@@ -704,12 +704,14 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 		if (ret < 0)
 			goto fail_register_speaker;
 	}
+	mutex_unlock(&kvm->slots_lock);
 
 	return pit;
 
 fail_register_speaker:
 	kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->dev);
 fail_register_pit:
+	mutex_unlock(&kvm->slots_lock);
 	kvm_pit_set_reinject(pit, false);
 	kthread_stop(pit->worker_task);
 fail_kthread:
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3fbf88f85a2d..99bb0cf93747 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3878,7 +3878,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 				   sizeof(struct kvm_pit_config)))
 			goto out;
 	create_pit:
-		mutex_lock(&kvm->slots_lock);
+		mutex_lock(&kvm->lock);
 		r = -EEXIST;
 		if (kvm->arch.vpit)
 			goto create_pit_unlock;
@@ -3887,7 +3887,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		if (kvm->arch.vpit)
 			r = 0;
 	create_pit_unlock:
-		mutex_unlock(&kvm->slots_lock);
+		mutex_unlock(&kvm->lock);
 		break;
 	case KVM_GET_IRQCHIP: {
 		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/7] KVM: syzkaller fixes
  2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
                   ` (6 preceding siblings ...)
  2016-06-01 12:09 ` [PATCH 7/7] KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock Paolo Bonzini
@ 2016-06-01 16:07 ` Radim Krčmář
  7 siblings, 0 replies; 12+ messages in thread
From: Radim Krčmář @ 2016-06-01 16:07 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: linux-kernel, kvm

2016-06-01 14:09+0200, Paolo Bonzini:
> These fix most of the bugs reported by Dmitry Vyukov a while back.
> I couldn't reproduce one of the bugs (patch 7) but the fix is easy.
> Probably, more VM ioctls should take kvm->lock, but I have not looked
> at it yet.

Applied, thanks.

> I have only marked for stable the two patches that fix an oops.  However,
> all of patches 1-6 could go in 4.7-rc, I think.

Normal userspaces don't exercise modified paths, so I'll prepare [1-6/7]
for -rc1, as thorough testing wouldn't make a difference ...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
  2016-06-01 12:09 ` [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
@ 2016-06-04 23:55   ` Wanpeng Li
  0 siblings, 0 replies; 12+ messages in thread
From: Wanpeng Li @ 2016-06-04 23:55 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: linux-kernel, kvm, Radim Krcmar

2016-06-01 20:09 GMT+08:00 Paolo Bonzini <pbonzini@redhat.com>:
> This causes an ugly dmesg splat.  Beautified syzkaller testcase:
>
>     #include <unistd.h>
>     #include <sys/syscall.h>
>     #include <sys/ioctl.h>
>     #include <fcntl.h>
>     #include <linux/kvm.h>
>
>     long r[8];
>
>     int main()
>     {
>         struct kvm_irq_routing ir = { 0 };
>         r[2] = open("/dev/kvm", O_RDWR);
>         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
>         r[4] = ioctl(r[3], KVM_SET_GSI_ROUTING, &ir);
>         return 0;
>     }
>

The patch subject is not correct.

Regards,
Wanpeng Li

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
  2016-06-01 12:09 ` [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi Paolo Bonzini
@ 2017-01-09 22:39   ` Steve Rutherford
  2017-01-10  9:32     ` Paolo Bonzini
  0 siblings, 1 reply; 12+ messages in thread
From: Steve Rutherford @ 2017-01-09 22:39 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: KVM list, Radim Krčmář

Doesn't this same bug also affect kvm_irq_map_chip_pin?

(Note: I haven't chased down whether anything can even reach here if
irq_rt is NULL.)

int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
{
        struct kvm_irq_routing_table *irq_rt;

        irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
+
+      if (!irq_rt)
+              return -1;
+
        return irq_rt->chip[irqchip][pin];
}

Steve

On Wed, Jun 1, 2016 at 5:09 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Found by syzkaller:
>
>     BUG: unable to handle kernel NULL pointer dereference at 0000000000000120
>     IP: [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
>     PGD 6f80b067 PUD b6535067 PMD 0
>     Oops: 0000 [#1] SMP
>     CPU: 3 PID: 4988 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1
>     [...]
>     Call Trace:
>      [<ffffffffa0795f62>] irqfd_update+0x32/0xc0 [kvm]
>      [<ffffffffa0796c7c>] kvm_irqfd+0x3dc/0x5b0 [kvm]
>      [<ffffffffa07943f4>] kvm_vm_ioctl+0x164/0x6f0 [kvm]
>      [<ffffffff81241648>] do_vfs_ioctl+0x298/0x480
>      [<ffffffff812418a9>] SyS_ioctl+0x79/0x90
>      [<ffffffff817a1062>] tracesys_phase2+0x84/0x89
>     Code: b5 71 a7 e0 5b 41 5c 41 5d 5d f3 c3 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 8b 8f 10 2e 00 00 31 c0 48 89 e5 <39> 91 20 01 00 00 76 6a 48 63 d2 48 8b 94 d1 28 01 00 00 48 85
>     RIP  [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
>      RSP <ffff8800926cbca8>
>     CR2: 0000000000000120
>
> Testcase:
>
>     #include <unistd.h>
>     #include <sys/syscall.h>
>     #include <string.h>
>     #include <stdint.h>
>     #include <linux/kvm.h>
>     #include <fcntl.h>
>     #include <sys/ioctl.h>
>
>     long r[26];
>
>     int main()
>     {
>         memset(r, -1, sizeof(r));
>         r[2] = open("/dev/kvm", 0);
>         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
>
>         struct kvm_irqfd ifd;
>         ifd.fd = syscall(SYS_eventfd2, 5, 0);
>         ifd.gsi = 3;
>         ifd.flags = 2;
>         ifd.resamplefd = ifd.fd;
>         r[25] = ioctl(r[3], KVM_IRQFD, &ifd);
>         return 0;
>     }
>
> Reported-by: Dmitry Vyukov <dvyukov@google.com>
> Cc: stable@vger.kernel.org
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  virt/kvm/irqchip.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
> index fe84e1a95dd5..8db197bb6c7a 100644
> --- a/virt/kvm/irqchip.c
> +++ b/virt/kvm/irqchip.c
> @@ -40,7 +40,7 @@ int kvm_irq_map_gsi(struct kvm *kvm,
>
>         irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
>                                         lockdep_is_held(&kvm->irq_lock));
> -       if (gsi < irq_rt->nr_rt_entries) {
> +       if (irq_rt && gsi < irq_rt->nr_rt_entries) {
>                 hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
>                         entries[n] = *e;
>                         ++n;
> --
> 1.8.3.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi
  2017-01-09 22:39   ` Steve Rutherford
@ 2017-01-10  9:32     ` Paolo Bonzini
  0 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2017-01-10  9:32 UTC (permalink / raw)
  To: Steve Rutherford; +Cc: KVM list, Radim Krčmář


> Doesn't this same bug also affect kvm_irq_map_chip_pin?
> 
> (Note: I haven't chased down whether anything can even reach here if
> irq_rt is NULL.)

No, it is safe because kvm_irq_map_chip_pin requires having created an
irqchip, and:

- host code (kvm_set_irq) in virt/kvm/irqchip.c goes through kvm_irq_map_gsi,
and until you have a successful kvm_irq_map_gsi you cannot get to
kvm_notify_acked_irq

- guest code (such as ioapic_write_indirect) can call kvm_irq_map_chip_pin,
but it cannot run until KVM_CREATE_IRQCHIP returns.  KVM_CREATE_IRQCHIP
requires that there are no VCPUs, and kvm->lock protects both KVM_CREATE_IRQCHIP
and (the first part of) KVM_CREATE_VCPU.

Maybe it was possible, but very unlikely, before commit 557abc40d121
("KVM: remove kvm_vcpu_compatible", 2016-06-16).

Paolo

> int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
> {
>         struct kvm_irq_routing_table *irq_rt;
> 
>         irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
> +
> +      if (!irq_rt)
> +              return -1;
> +
>         return irq_rt->chip[irqchip][pin];
> }
> 
> Steve
> 
> On Wed, Jun 1, 2016 at 5:09 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> > Found by syzkaller:
> >
> >     BUG: unable to handle kernel NULL pointer dereference at
> >     0000000000000120
> >     IP: [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
> >     PGD 6f80b067 PUD b6535067 PMD 0
> >     Oops: 0000 [#1] SMP
> >     CPU: 3 PID: 4988 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1
> >     [...]
> >     Call Trace:
> >      [<ffffffffa0795f62>] irqfd_update+0x32/0xc0 [kvm]
> >      [<ffffffffa0796c7c>] kvm_irqfd+0x3dc/0x5b0 [kvm]
> >      [<ffffffffa07943f4>] kvm_vm_ioctl+0x164/0x6f0 [kvm]
> >      [<ffffffff81241648>] do_vfs_ioctl+0x298/0x480
> >      [<ffffffff812418a9>] SyS_ioctl+0x79/0x90
> >      [<ffffffff817a1062>] tracesys_phase2+0x84/0x89
> >     Code: b5 71 a7 e0 5b 41 5c 41 5d 5d f3 c3 66 66 66 66 2e 0f 1f 84 00 00
> >     00 00 00 0f 1f 44 00 00 55 48 8b 8f 10 2e 00 00 31 c0 48 89 e5 <39> 91
> >     20 01 00 00 76 6a 48 63 d2 48 8b 94 d1 28 01 00 00 48 85
> >     RIP  [<ffffffffa0797202>] kvm_irq_map_gsi+0x12/0x90 [kvm]
> >      RSP <ffff8800926cbca8>
> >     CR2: 0000000000000120
> >
> > Testcase:
> >
> >     #include <unistd.h>
> >     #include <sys/syscall.h>
> >     #include <string.h>
> >     #include <stdint.h>
> >     #include <linux/kvm.h>
> >     #include <fcntl.h>
> >     #include <sys/ioctl.h>
> >
> >     long r[26];
> >
> >     int main()
> >     {
> >         memset(r, -1, sizeof(r));
> >         r[2] = open("/dev/kvm", 0);
> >         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
> >
> >         struct kvm_irqfd ifd;
> >         ifd.fd = syscall(SYS_eventfd2, 5, 0);
> >         ifd.gsi = 3;
> >         ifd.flags = 2;
> >         ifd.resamplefd = ifd.fd;
> >         r[25] = ioctl(r[3], KVM_IRQFD, &ifd);
> >         return 0;
> >     }
> >
> > Reported-by: Dmitry Vyukov <dvyukov@google.com>
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> > ---
> >  virt/kvm/irqchip.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
> > index fe84e1a95dd5..8db197bb6c7a 100644
> > --- a/virt/kvm/irqchip.c
> > +++ b/virt/kvm/irqchip.c
> > @@ -40,7 +40,7 @@ int kvm_irq_map_gsi(struct kvm *kvm,
> >
> >         irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
> >                                         lockdep_is_held(&kvm->irq_lock));
> > -       if (gsi < irq_rt->nr_rt_entries) {
> > +       if (irq_rt && gsi < irq_rt->nr_rt_entries) {
> >                 hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
> >                         entries[n] = *e;
> >                         ++n;
> > --
> > 1.8.3.1
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-01-10  9:32 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-01 12:09 [PATCH 0/7] KVM: syzkaller fixes Paolo Bonzini
2016-06-01 12:09 ` [PATCH 1/7] kvm: x86: avoid warning on repeated KVM_SET_TSS_ADDR Paolo Bonzini
2016-06-01 12:09 ` [PATCH 2/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
2016-06-01 12:09 ` [PATCH 3/7] KVM: fail KVM_SET_VCPU_EVENTS with invalid exception number Paolo Bonzini
2016-06-01 12:09 ` [PATCH 4/7] KVM: irqfd: fix NULL pointer dereference in kvm_irq_map_gsi Paolo Bonzini
2017-01-09 22:39   ` Steve Rutherford
2017-01-10  9:32     ` Paolo Bonzini
2016-06-01 12:09 ` [PATCH 5/7] KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID Paolo Bonzini
2016-06-04 23:55   ` Wanpeng Li
2016-06-01 12:09 ` [PATCH 6/7] KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS Paolo Bonzini
2016-06-01 12:09 ` [PATCH 7/7] KVM: x86: protect KVM_CREATE_PIT/KVM_CREATE_PIT2 with kvm->lock Paolo Bonzini
2016-06-01 16:07 ` [PATCH 0/7] KVM: syzkaller fixes Radim Krčmář

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.