[x86] KVM: fix emulation of "MOV SS, null selector" (CVE-2017-2583)
This commit is contained in:
parent
5745d97d88
commit
f18792b8fa
|
@ -245,6 +245,7 @@ linux (4.9.4-1) UNRELEASED; urgency=medium
|
|||
(CVE-2016-9191)
|
||||
* tmpfs: clear S_ISGID when setting posix ACLs
|
||||
* [x86] KVM: Introduce segmented_write_std (CVE-2017-2584)
|
||||
* [x86] KVM: fix emulation of "MOV SS, null selector" (CVE-2017-2583)
|
||||
|
||||
-- Salvatore Bonaccorso <carnil@debian.org> Mon, 16 Jan 2017 09:26:13 +0100
|
||||
|
||||
|
|
107
debian/patches/bugfix/x86/KVM-x86-fix-emulation-of-MOV-SS-null-selector.patch
vendored
Normal file
107
debian/patches/bugfix/x86/KVM-x86-fix-emulation-of-MOV-SS-null-selector.patch
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 12 Jan 2017 15:02:32 +0100
|
||||
Subject: KVM: x86: fix emulation of "MOV SS, null selector"
|
||||
Origin: https://git.kernel.org/linus/33ab91103b3415e12457e3104f0e4517ce12d0f3
|
||||
|
||||
This is CVE-2017-2583. On Intel this causes a failed vmentry because
|
||||
SS's type is neither 3 nor 7 (even though the manual says this check is
|
||||
only done for usable SS, and the dmesg splat says that SS is unusable!).
|
||||
On AMD it's worse: svm.c is confused and sets CPL to 0 in the vmcb.
|
||||
|
||||
The fix fabricates a data segment descriptor when SS is set to a null
|
||||
selector, so that CPL and SS.DPL are set correctly in the VMCS/vmcb.
|
||||
Furthermore, only allow setting SS to a NULL selector if SS.RPL < 3;
|
||||
this in turn ensures CPL < 3 because RPL must be equal to CPL.
|
||||
|
||||
Thanks to Andy Lutomirski and Willy Tarreau for help in analyzing
|
||||
the bug and deciphering the manuals.
|
||||
|
||||
Reported-by: Xiaohan Zhang <zhangxiaohan1@huawei.com>
|
||||
Fixes: 79d5b4c3cd809c770d4bf9812635647016c56011
|
||||
Cc: stable@nongnu.org
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
arch/x86/kvm/emulate.c | 48 ++++++++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 38 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
|
||||
index f36d0fa..cedbba0 100644
|
||||
--- a/arch/x86/kvm/emulate.c
|
||||
+++ b/arch/x86/kvm/emulate.c
|
||||
@@ -1585,7 +1585,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||
&ctxt->exception);
|
||||
}
|
||||
|
||||
-/* Does not support long mode */
|
||||
static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||
u16 selector, int seg, u8 cpl,
|
||||
enum x86_transfer_type transfer,
|
||||
@@ -1622,20 +1621,34 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||
|
||||
rpl = selector & 3;
|
||||
|
||||
- /* NULL selector is not valid for TR, CS and SS (except for long mode) */
|
||||
- if ((seg == VCPU_SREG_CS
|
||||
- || (seg == VCPU_SREG_SS
|
||||
- && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
|
||||
- || seg == VCPU_SREG_TR)
|
||||
- && null_selector)
|
||||
- goto exception;
|
||||
-
|
||||
/* TR should be in GDT only */
|
||||
if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
|
||||
goto exception;
|
||||
|
||||
- if (null_selector) /* for NULL selector skip all following checks */
|
||||
+ /* NULL selector is not valid for TR, CS and (except for long mode) SS */
|
||||
+ if (null_selector) {
|
||||
+ if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
|
||||
+ goto exception;
|
||||
+
|
||||
+ if (seg == VCPU_SREG_SS) {
|
||||
+ if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
|
||||
+ goto exception;
|
||||
+
|
||||
+ /*
|
||||
+ * ctxt->ops->set_segment expects the CPL to be in
|
||||
+ * SS.DPL, so fake an expand-up 32-bit data segment.
|
||||
+ */
|
||||
+ seg_desc.type = 3;
|
||||
+ seg_desc.p = 1;
|
||||
+ seg_desc.s = 1;
|
||||
+ seg_desc.dpl = cpl;
|
||||
+ seg_desc.d = 1;
|
||||
+ seg_desc.g = 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Skip all following checks */
|
||||
goto load;
|
||||
+ }
|
||||
|
||||
ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
|
||||
if (ret != X86EMUL_CONTINUE)
|
||||
@@ -1751,6 +1764,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||
u16 selector, int seg)
|
||||
{
|
||||
u8 cpl = ctxt->ops->cpl(ctxt);
|
||||
+
|
||||
+ /*
|
||||
+ * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
|
||||
+ * they can load it at CPL<3 (Intel's manual says only LSS can,
|
||||
+ * but it's wrong).
|
||||
+ *
|
||||
+ * However, the Intel manual says that putting IST=1/DPL=3 in
|
||||
+ * an interrupt gate will result in SS=3 (the AMD manual instead
|
||||
+ * says it doesn't), so allow SS=3 in __load_segment_descriptor
|
||||
+ * and only forbid it here.
|
||||
+ */
|
||||
+ if (seg == VCPU_SREG_SS && selector == 3 &&
|
||||
+ ctxt->mode == X86EMUL_MODE_PROT64)
|
||||
+ return emulate_exception(ctxt, GP_VECTOR, 0, true);
|
||||
+
|
||||
return __load_segment_descriptor(ctxt, selector, seg, cpl,
|
||||
X86_TRANSFER_NONE, NULL);
|
||||
}
|
||||
--
|
||||
2.1.4
|
||||
|
|
@ -98,6 +98,7 @@ debian/i386-686-pae-pci-set-pci-nobios-by-default.patch
|
|||
bugfix/all/sysctl-Drop-reference-added-by-grab_header-in-proc_s.patch
|
||||
bugfix/all/tmpfs-clear-S_ISGID-when-setting-posix-ACLs.patch
|
||||
bugfix/x86/KVM-x86-Introduce-segmented_write_std.patch
|
||||
bugfix/x86/KVM-x86-fix-emulation-of-MOV-SS-null-selector.patch
|
||||
|
||||
# Fix exported symbol versions
|
||||
bugfix/ia64/revert-ia64-move-exports-to-definitions.patch
|
||||
|
|
Loading…
Reference in New Issue