]>
Commit | Line | Data |
---|---|---|
59d5af67 | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
321d628a FG |
2 | From: Paolo Bonzini <pbonzini@redhat.com> |
3 | Date: Thu, 21 Dec 2017 00:49:14 +0100 | |
59d5af67 | 4 | Subject: [PATCH] kvm: x86: fix RSM when PCID is non-zero |
321d628a FG |
5 | MIME-Version: 1.0 |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | CVE-2017-5754 | |
10 | ||
11 | rsm_load_state_64() and rsm_enter_protected_mode() load CR3, then | |
12 | CR4 & ~PCIDE, then CR0, then CR4. | |
13 | ||
14 | However, setting CR4.PCIDE fails if CR3[11:0] != 0. It's probably easier | |
15 | in the long run to replace rsm_enter_protected_mode() with an emulator | |
16 | callback that sets all the special registers (like KVM_SET_SREGS would | |
17 | do). For now, set the PCID field of CR3 only after CR4.PCIDE is 1. | |
18 | ||
19 | Reported-by: Laszlo Ersek <lersek@redhat.com> | |
20 | Tested-by: Laszlo Ersek <lersek@redhat.com> | |
21 | Fixes: 660a5d517aaab9187f93854425c4c63f4a09195c | |
22 | Cc: stable@vger.kernel.org | |
23 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
24 | (cherry picked from commit fae1a3e775cca8c3a9e0eb34443b310871a15a92) | |
25 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
26 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
27 | (cherry picked from commit dba4ceb9a91ed2d11a47722436b3c0be15e791d4) | |
28 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
29 | --- | |
30 | arch/x86/kvm/emulate.c | 32 +++++++++++++++++++++++++------- | |
31 | 1 file changed, 25 insertions(+), 7 deletions(-) | |
32 | ||
33 | diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c | |
34 | index fb0055953fbc..155f2af2cb39 100644 | |
35 | --- a/arch/x86/kvm/emulate.c | |
36 | +++ b/arch/x86/kvm/emulate.c | |
37 | @@ -2399,9 +2399,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n) | |
38 | } | |
39 | ||
40 | static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, | |
41 | - u64 cr0, u64 cr4) | |
42 | + u64 cr0, u64 cr3, u64 cr4) | |
43 | { | |
44 | int bad; | |
45 | + u64 pcid; | |
46 | + | |
47 | + /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */ | |
48 | + pcid = 0; | |
49 | + if (cr4 & X86_CR4_PCIDE) { | |
50 | + pcid = cr3 & 0xfff; | |
51 | + cr3 &= ~0xfff; | |
52 | + } | |
53 | + | |
54 | + bad = ctxt->ops->set_cr(ctxt, 3, cr3); | |
55 | + if (bad) | |
56 | + return X86EMUL_UNHANDLEABLE; | |
57 | ||
58 | /* | |
59 | * First enable PAE, long mode needs it before CR0.PG = 1 is set. | |
60 | @@ -2420,6 +2432,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, | |
61 | bad = ctxt->ops->set_cr(ctxt, 4, cr4); | |
62 | if (bad) | |
63 | return X86EMUL_UNHANDLEABLE; | |
64 | + if (pcid) { | |
65 | + bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid); | |
66 | + if (bad) | |
67 | + return X86EMUL_UNHANDLEABLE; | |
68 | + } | |
69 | + | |
70 | } | |
71 | ||
72 | return X86EMUL_CONTINUE; | |
73 | @@ -2430,11 +2448,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) | |
74 | struct desc_struct desc; | |
75 | struct desc_ptr dt; | |
76 | u16 selector; | |
77 | - u32 val, cr0, cr4; | |
78 | + u32 val, cr0, cr3, cr4; | |
79 | int i; | |
80 | ||
81 | cr0 = GET_SMSTATE(u32, smbase, 0x7ffc); | |
82 | - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8)); | |
83 | + cr3 = GET_SMSTATE(u32, smbase, 0x7ff8); | |
84 | ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED; | |
85 | ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0); | |
86 | ||
87 | @@ -2476,14 +2494,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) | |
88 | ||
89 | ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8)); | |
90 | ||
91 | - return rsm_enter_protected_mode(ctxt, cr0, cr4); | |
92 | + return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); | |
93 | } | |
94 | ||
95 | static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) | |
96 | { | |
97 | struct desc_struct desc; | |
98 | struct desc_ptr dt; | |
99 | - u64 val, cr0, cr4; | |
100 | + u64 val, cr0, cr3, cr4; | |
101 | u32 base3; | |
102 | u16 selector; | |
103 | int i, r; | |
104 | @@ -2500,7 +2518,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) | |
105 | ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1); | |
106 | ||
107 | cr0 = GET_SMSTATE(u64, smbase, 0x7f58); | |
108 | - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50)); | |
109 | + cr3 = GET_SMSTATE(u64, smbase, 0x7f50); | |
110 | cr4 = GET_SMSTATE(u64, smbase, 0x7f48); | |
111 | ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00)); | |
112 | val = GET_SMSTATE(u64, smbase, 0x7ed0); | |
113 | @@ -2528,7 +2546,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) | |
114 | dt.address = GET_SMSTATE(u64, smbase, 0x7e68); | |
115 | ctxt->ops->set_gdt(ctxt, &dt); | |
116 | ||
117 | - r = rsm_enter_protected_mode(ctxt, cr0, cr4); | |
118 | + r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); | |
119 | if (r != X86EMUL_CONTINUE) | |
120 | return r; | |
121 | ||
122 | -- | |
123 | 2.14.2 | |
124 |