[linux] 15/18: [x86] KVM: drop error recovery in em_jmp_far and em_ret_far (CVE-2016-9756)

debian-kernel at lists.debian.org debian-kernel at lists.debian.org
Thu Dec 29 03:44:12 UTC 2016


This is an automated email from the git hooks/post-receive script.

benh pushed a commit to branch jessie
in repository linux.

commit de565a48b2cc33137cb4efd0743fb38c8c3bd0dc
Author: Ben Hutchings <ben at decadent.org.uk>
Date:   Wed Dec 28 23:46:52 2016 +0000

    [x86] KVM: drop error recovery in em_jmp_far and em_ret_far (CVE-2016-9756)
---
 debian/changelog                                   |   1 +
 ...p-error-recovery-in-em_jmp_far-and-em_ret.patch | 125 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 127 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 2d8f8e4..53006ac 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -506,6 +506,7 @@ linux (3.16.39-1) UNRELEASED; urgency=medium
   * sctp: validate chunk len before actually using it (CVE-2016-9555)
   * sg_write()/bsg_write() is not fit to be called under KERNEL_DS
     (CVE-2016-9576)
+  * [x86] KVM: drop error recovery in em_jmp_far and em_ret_far (CVE-2016-9756)
 
   [ Julien Cristau ]
   * hwrng: Add chaoskey driver, backported from 4.8 (Closes: #839616)
diff --git a/debian/patches/bugfix/x86/kvm-x86-drop-error-recovery-in-em_jmp_far-and-em_ret.patch b/debian/patches/bugfix/x86/kvm-x86-drop-error-recovery-in-em_jmp_far-and-em_ret.patch
new file mode 100644
index 0000000..fe1a31a
--- /dev/null
+++ b/debian/patches/bugfix/x86/kvm-x86-drop-error-recovery-in-em_jmp_far-and-em_ret.patch
@@ -0,0 +1,125 @@
+From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= <rkrcmar at redhat.com>
+Date: Wed, 23 Nov 2016 21:15:00 +0100
+Subject: KVM: x86: drop error recovery in em_jmp_far and em_ret_far
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Origin: https://git.kernel.org/linus/2117d5398c81554fbf803f5fd1dc55eb78216c0c
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2016-9756
+
+em_jmp_far and em_ret_far assumed that setting IP can only fail in 64
+bit mode, but syzkaller proved otherwise (and SDM agrees).
+Code segment was restored upon failure, but it was left uninitialized
+outside of long mode, which could lead to a leak of host kernel stack.
+We could have fixed that by always saving and restoring the CS, but we
+take a simpler approach and just break any guest that manages to fail
+as the error recovery is error-prone and modern CPUs don't need emulator
+for this.
+
+Found by syzkaller:
+
+  WARNING: CPU: 2 PID: 3668 at arch/x86/kvm/emulate.c:2217 em_ret_far+0x428/0x480
+  Kernel panic - not syncing: panic_on_warn set ...
+
+  CPU: 2 PID: 3668 Comm: syz-executor Not tainted 4.9.0-rc4+ #49
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
+   [...]
+  Call Trace:
+   [...] __dump_stack lib/dump_stack.c:15
+   [...] dump_stack+0xb3/0x118 lib/dump_stack.c:51
+   [...] panic+0x1b7/0x3a3 kernel/panic.c:179
+   [...] __warn+0x1c4/0x1e0 kernel/panic.c:542
+   [...] warn_slowpath_null+0x2c/0x40 kernel/panic.c:585
+   [...] em_ret_far+0x428/0x480 arch/x86/kvm/emulate.c:2217
+   [...] em_ret_far_imm+0x17/0x70 arch/x86/kvm/emulate.c:2227
+   [...] x86_emulate_insn+0x87a/0x3730 arch/x86/kvm/emulate.c:5294
+   [...] x86_emulate_instruction+0x520/0x1ba0 arch/x86/kvm/x86.c:5545
+   [...] emulate_instruction arch/x86/include/asm/kvm_host.h:1116
+   [...] complete_emulated_io arch/x86/kvm/x86.c:6870
+   [...] complete_emulated_mmio+0x4e9/0x710 arch/x86/kvm/x86.c:6934
+   [...] kvm_arch_vcpu_ioctl_run+0x3b7a/0x5a90 arch/x86/kvm/x86.c:6978
+   [...] kvm_vcpu_ioctl+0x61e/0xdd0 arch/x86/kvm/../../../virt/kvm/kvm_main.c:2557
+   [...] vfs_ioctl fs/ioctl.c:43
+   [...] do_vfs_ioctl+0x18c/0x1040 fs/ioctl.c:679
+   [...] SYSC_ioctl fs/ioctl.c:694
+   [...] SyS_ioctl+0x8f/0xc0 fs/ioctl.c:685
+   [...] entry_SYSCALL_64_fastpath+0x1f/0xc2
+
+Reported-by: Dmitry Vyukov <dvyukov at google.com>
+Cc: stable at vger.kernel.org
+Fixes: d1442d85cc30 ("KVM: x86: Handle errors when RIP is set during far jumps")
+Signed-off-by: Radim Krčmář <rkrcmar at redhat.com>
+[bwh: Backported to 3.16: adjust context]
+---
+ arch/x86/kvm/emulate.c | 36 +++++++++++-------------------------
+ 1 file changed, 11 insertions(+), 25 deletions(-)
+
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -1983,16 +1983,10 @@ static int em_iret(struct x86_emulate_ct
+ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
+ {
+ 	int rc;
+-	unsigned short sel, old_sel;
+-	struct desc_struct old_desc, new_desc;
+-	const struct x86_emulate_ops *ops = ctxt->ops;
++	unsigned short sel;
++	struct desc_struct new_desc;
+ 	u8 cpl = ctxt->ops->cpl(ctxt);
+ 
+-	/* Assignment of RIP may only fail in 64-bit mode */
+-	if (ctxt->mode == X86EMUL_MODE_PROT64)
+-		ops->get_segment(ctxt, &old_sel, &old_desc, NULL,
+-				 VCPU_SREG_CS);
+-
+ 	memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2);
+ 
+ 	rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl, false,
+@@ -2001,12 +1995,10 @@ static int em_jmp_far(struct x86_emulate
+ 		return rc;
+ 
+ 	rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
+-	if (rc != X86EMUL_CONTINUE) {
+-		WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
+-		/* assigning eip failed; restore the old cs */
+-		ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
+-		return rc;
+-	}
++	/* Error handling is not implemented. */
++	if (rc != X86EMUL_CONTINUE)
++		return X86EMUL_UNHANDLEABLE;
++
+ 	return rc;
+ }
+ 
+@@ -2072,14 +2064,8 @@ static int em_ret_far(struct x86_emulate
+ {
+ 	int rc;
+ 	unsigned long eip, cs;
+-	u16 old_cs;
+ 	int cpl = ctxt->ops->cpl(ctxt);
+-	struct desc_struct old_desc, new_desc;
+-	const struct x86_emulate_ops *ops = ctxt->ops;
+-
+-	if (ctxt->mode == X86EMUL_MODE_PROT64)
+-		ops->get_segment(ctxt, &old_cs, &old_desc, NULL,
+-				 VCPU_SREG_CS);
++	struct desc_struct new_desc;
+ 
+ 	rc = emulate_pop(ctxt, &eip, ctxt->op_bytes);
+ 	if (rc != X86EMUL_CONTINUE)
+@@ -2095,10 +2081,10 @@ static int em_ret_far(struct x86_emulate
+ 	if (rc != X86EMUL_CONTINUE)
+ 		return rc;
+ 	rc = assign_eip_far(ctxt, eip, new_desc.l);
+-	if (rc != X86EMUL_CONTINUE) {
+-		WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
+-		ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
+-	}
++	/* Error handling is not implemented. */
++	if (rc != X86EMUL_CONTINUE)
++		return X86EMUL_UNHANDLEABLE;
++
+ 	return rc;
+ }
+ 
diff --git a/debian/patches/series b/debian/patches/series
index c2ff3d1..4e08748 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -673,6 +673,7 @@ bugfix/all/packet-fix-race-condition-in-packet_set_ring.patch
 bugfix/x86/fix-potential-infoleak-in-older-kernels.patch
 bugfix/all/sctp-validate-chunk-len-before-actually-using-it.patch
 bugfix/all/sg_write-bsg_write-is-not-fit-to-be-called-under-ker.patch
+bugfix/x86/kvm-x86-drop-error-recovery-in-em_jmp_far-and-em_ret.patch
 
 # Fix ABI changes
 debian/of-fix-abi-changes.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git



More information about the Kernel-svn-changes mailing list