]> git.proxmox.com Git - pve-kernel-jessie.git/blob - CVE-2017-2583-KVM-x86-fix-emulation-of-MOV-SS-null-selector.patch
3a984eddaf647f5390be5f13e6f64e2e9df6dd3e
[pve-kernel-jessie.git] / CVE-2017-2583-KVM-x86-fix-emulation-of-MOV-SS-null-selector.patch
1 From 33ab91103b3415e12457e3104f0e4517ce12d0f3 Mon Sep 17 00:00:00 2001
2 From: Paolo Bonzini <pbonzini@redhat.com>
3 Date: Thu, 12 Jan 2017 15:02:32 +0100
4 Subject: KVM: x86: fix emulation of "MOV SS, null selector"
5
6 This is CVE-2017-2583. On Intel this causes a failed vmentry because
7 SS's type is neither 3 nor 7 (even though the manual says this check is
8 only done for usable SS, and the dmesg splat says that SS is unusable!).
9 On AMD it's worse: svm.c is confused and sets CPL to 0 in the vmcb.
10
11 The fix fabricates a data segment descriptor when SS is set to a null
12 selector, so that CPL and SS.DPL are set correctly in the VMCS/vmcb.
13 Furthermore, only allow setting SS to a NULL selector if SS.RPL < 3;
14 this in turn ensures CPL < 3 because RPL must be equal to CPL.
15
16 Thanks to Andy Lutomirski and Willy Tarreau for help in analyzing
17 the bug and deciphering the manuals.
18
19 Reported-by: Xiaohan Zhang <zhangxiaohan1@huawei.com>
20 Fixes: 79d5b4c3cd809c770d4bf9812635647016c56011
21 Cc: stable@nongnu.org
22 Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
23 ---
24 arch/x86/kvm/emulate.c | 48 ++++++++++++++++++++++++++++++++++++++----------
25 1 file changed, 38 insertions(+), 10 deletions(-)
26
27 diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
28 index f36d0fa..cedbba0 100644
29 --- a/arch/x86/kvm/emulate.c
30 +++ b/arch/x86/kvm/emulate.c
31 @@ -1585,7 +1585,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
32 &ctxt->exception);
33 }
34
35 -/* Does not support long mode */
36 static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
37 u16 selector, int seg, u8 cpl,
38 enum x86_transfer_type transfer,
39 @@ -1622,20 +1621,34 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
40
41 rpl = selector & 3;
42
43 - /* NULL selector is not valid for TR, CS and SS (except for long mode) */
44 - if ((seg == VCPU_SREG_CS
45 - || (seg == VCPU_SREG_SS
46 - && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
47 - || seg == VCPU_SREG_TR)
48 - && null_selector)
49 - goto exception;
50 -
51 /* TR should be in GDT only */
52 if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
53 goto exception;
54
55 - if (null_selector) /* for NULL selector skip all following checks */
56 + /* NULL selector is not valid for TR, CS and (except for long mode) SS */
57 + if (null_selector) {
58 + if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
59 + goto exception;
60 +
61 + if (seg == VCPU_SREG_SS) {
62 + if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
63 + goto exception;
64 +
65 + /*
66 + * ctxt->ops->set_segment expects the CPL to be in
67 + * SS.DPL, so fake an expand-up 32-bit data segment.
68 + */
69 + seg_desc.type = 3;
70 + seg_desc.p = 1;
71 + seg_desc.s = 1;
72 + seg_desc.dpl = cpl;
73 + seg_desc.d = 1;
74 + seg_desc.g = 1;
75 + }
76 +
77 + /* Skip all following checks */
78 goto load;
79 + }
80
81 ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
82 if (ret != X86EMUL_CONTINUE)
83 @@ -1751,6 +1764,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
84 u16 selector, int seg)
85 {
86 u8 cpl = ctxt->ops->cpl(ctxt);
87 +
88 + /*
89 + * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
90 + * they can load it at CPL<3 (Intel's manual says only LSS can,
91 + * but it's wrong).
92 + *
93 + * However, the Intel manual says that putting IST=1/DPL=3 in
94 + * an interrupt gate will result in SS=3 (the AMD manual instead
95 + * says it doesn't), so allow SS=3 in __load_segment_descriptor
96 + * and only forbid it here.
97 + */
98 + if (seg == VCPU_SREG_SS && selector == 3 &&
99 + ctxt->mode == X86EMUL_MODE_PROT64)
100 + return emulate_exception(ctxt, GP_VECTOR, 0, true);
101 +
102 return __load_segment_descriptor(ctxt, selector, seg, cpl,
103 X86_TRANSFER_NONE, NULL);
104 }
105 --
106 cgit v0.12
107