]>
Commit | Line | Data |
---|---|---|
fcf4a090 GKH |
1 | From d14bdb553f9196169f003058ae1cdabe514470e6 Mon Sep 17 00:00:00 2001 |
2 | From: Paolo Bonzini <pbonzini@redhat.com> | |
3 | Date: Wed, 1 Jun 2016 14:09:23 +0200 | |
4 | Subject: KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Paolo Bonzini <pbonzini@redhat.com> | |
10 | ||
11 | commit d14bdb553f9196169f003058ae1cdabe514470e6 upstream. | |
12 | ||
13 | MOV to DR6 or DR7 causes a #GP if an attempt is made to write a 1 to | |
14 | any of bits 63:32. However, this is not detected at KVM_SET_DEBUGREGS | |
15 | time, and the next KVM_RUN oopses: | |
16 | ||
17 | general protection fault: 0000 [#1] SMP | |
18 | CPU: 2 PID: 14987 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1 | |
19 | Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012 | |
20 | [...] | |
21 | Call Trace: | |
22 | [<ffffffffa072c93d>] kvm_arch_vcpu_ioctl_run+0x141d/0x14e0 [kvm] | |
23 | [<ffffffffa071405d>] kvm_vcpu_ioctl+0x33d/0x620 [kvm] | |
24 | [<ffffffff81241648>] do_vfs_ioctl+0x298/0x480 | |
25 | [<ffffffff812418a9>] SyS_ioctl+0x79/0x90 | |
26 | [<ffffffff817a0f2e>] entry_SYSCALL_64_fastpath+0x12/0x71 | |
27 | 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 | |
28 | RIP [<ffffffff810639eb>] native_set_debugreg+0x2b/0x40 | |
29 | RSP <ffff88005836bd50> | |
30 | ||
31 | Testcase (beautified/reduced from syzkaller output): | |
32 | ||
33 | #include <unistd.h> | |
34 | #include <sys/syscall.h> | |
35 | #include <string.h> | |
36 | #include <stdint.h> | |
37 | #include <linux/kvm.h> | |
38 | #include <fcntl.h> | |
39 | #include <sys/ioctl.h> | |
40 | ||
41 | long r[8]; | |
42 | ||
43 | int main() | |
44 | { | |
45 | struct kvm_debugregs dr = { 0 }; | |
46 | ||
47 | r[2] = open("/dev/kvm", O_RDONLY); | |
48 | r[3] = ioctl(r[2], KVM_CREATE_VM, 0); | |
49 | r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7); | |
50 | ||
51 | memcpy(&dr, | |
52 | "\x5d\x6a\x6b\xe8\x57\x3b\x4b\x7e\xcf\x0d\xa1\x72" | |
53 | "\xa3\x4a\x29\x0c\xfc\x6d\x44\x00\xa7\x52\xc7\xd8" | |
54 | "\x00\xdb\x89\x9d\x78\xb5\x54\x6b\x6b\x13\x1c\xe9" | |
55 | "\x5e\xd3\x0e\x40\x6f\xb4\x66\xf7\x5b\xe3\x36\xcb", | |
56 | 48); | |
57 | r[7] = ioctl(r[4], KVM_SET_DEBUGREGS, &dr); | |
58 | r[6] = ioctl(r[4], KVM_RUN, 0); | |
59 | } | |
60 | ||
61 | Reported-by: Dmitry Vyukov <dvyukov@google.com> | |
62 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
63 | Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> | |
64 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
65 | ||
66 | --- | |
67 | arch/x86/kvm/x86.c | 5 +++++ | |
68 | 1 file changed, 5 insertions(+) | |
69 | ||
70 | --- a/arch/x86/kvm/x86.c | |
71 | +++ b/arch/x86/kvm/x86.c | |
72 | @@ -3014,6 +3014,11 @@ static int kvm_vcpu_ioctl_x86_set_debugr | |
73 | if (dbgregs->flags) | |
74 | return -EINVAL; | |
75 | ||
76 | + if (dbgregs->dr6 & ~0xffffffffull) | |
77 | + return -EINVAL; | |
78 | + if (dbgregs->dr7 & ~0xffffffffull) | |
79 | + return -EINVAL; | |
80 | + | |
81 | memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); | |
82 | kvm_update_dr0123(vcpu); | |
83 | vcpu->arch.dr6 = dbgregs->dr6; |