KVM: x86: fix escape of guest dr6 to the host

"Linux Kernel Mailing List" <[email protected]>
Newsgroups gmane.linux.kernel.commits.head
Message-ID <[email protected]>
Web:        https://git.kernel.org/torvalds/c/efdab992813fb2ed825745625b83c05032e9cda2
Commit:     efdab992813fb2ed825745625b83c05032e9cda2
Parent:     f38a7b75267f1fb240a8178cbcb16d66dd37aac8
Refname:    refs/heads/master
Author:     Wanpeng Li <[email protected]>
AuthorDate: Wed Dec 13 10:46:40 2017 +0100
Committer:  Radim Krčmář <[email protected]>
CommitDate: Tue Jan 16 16:34:13 2018 +0100

    KVM: x86: fix escape of guest dr6 to the host
    
    syzkaller reported:
    
       WARNING: CPU: 0 PID: 12927 at arch/x86/kernel/traps.c:780 do_debug+0x222/0x250
       CPU: 0 PID: 12927 Comm: syz-executor Tainted: G           OE    4.15.0-rc2+ #16
       RIP: 0010:do_debug+0x222/0x250
       Call Trace:
        <#DB>
        debug+0x3e/0x70
       RIP: 0010:copy_user_enhanced_fast_string+0x10/0x20
        </#DB>
        _copy_from_user+0x5b/0x90
        SyS_timer_create+0x33/0x80
        entry_SYSCALL_64_fastpath+0x23/0x9a
    
    The testcase sets a watchpoint (with perf_event_open) on a buffer that is
    passed to timer_create() as the struct sigevent argument.  In timer_create(),
    copy_from_user()'s rep movsb triggers the BP.  The testcase also sets
    the debug registers for the guest.
    
    However, KVM only restores host debug registers when the host has active
    watchpoints, which triggers a race condition when running the testcase with
    multiple threads.  The guest's DR6.BS bit can escape to the host before
    another thread invokes timer_create(), and do_debug() complains.
    
    The fix is to respect do_debug()'s dr6 invariant when leaving KVM.
    
    Reported-by: Dmitry Vyukov <[email protected]>
    Cc: Paolo Bonzini <[email protected]>
    Cc: Radim Krčmář <[email protected]>
    Cc: David Hildenbrand <[email protected]>
    Cc: Dmitry Vyukov <[email protected]>
    Reviewed-by: David Hildenbrand <[email protected]>
    Signed-off-by: Wanpeng Li <[email protected]>
    Signed-off-by: Paolo Bonzini <[email protected]>
    Signed-off-by: Radim Krčmář <[email protected]>
---
 arch/x86/kvm/x86.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 35d0b3de697b..a3dd44bb6f1e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2961,6 +2961,12 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 	pagefault_enable();
 	kvm_x86_ops->vcpu_put(vcpu);
 	vcpu->arch.last_host_tsc = rdtsc();
+	/*
+	 * If userspace has set any breakpoints or watchpoints, dr6 is restored
+	 * on every vmexit, but if not, we might have a stale dr6 from the
+	 * guest. do_debug expects dr6 to be cleared after it runs, do the same.
+	 */
+	set_debugreg(0, 6);
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.