| From d14bdb553f9196169f003058ae1cdabe514470e6 Mon Sep 17 00:00:00 2001 |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| Date: Wed, 1 Jun 2016 14:09:23 +0200 |
| Subject: KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| |
| commit d14bdb553f9196169f003058ae1cdabe514470e6 upstream. |
| |
| 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> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/x86.c | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -3014,6 +3014,11 @@ static int kvm_vcpu_ioctl_x86_set_debugr |
| 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; |