| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- From 59b914593681a98524e4f3ba239544f77f03d14a Mon Sep 17 00:00:00 2001
- From: Paolo Bonzini <[email protected]>
- Date: Thu, 21 Dec 2017 00:49:14 +0100
- Subject: [PATCH 224/242] kvm: x86: fix RSM when PCID is non-zero
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- rsm_load_state_64() and rsm_enter_protected_mode() load CR3, then
- CR4 & ~PCIDE, then CR0, then CR4.
- However, setting CR4.PCIDE fails if CR3[11:0] != 0. It's probably easier
- in the long run to replace rsm_enter_protected_mode() with an emulator
- callback that sets all the special registers (like KVM_SET_SREGS would
- do). For now, set the PCID field of CR3 only after CR4.PCIDE is 1.
- Reported-by: Laszlo Ersek <[email protected]>
- Tested-by: Laszlo Ersek <[email protected]>
- Fixes: 660a5d517aaab9187f93854425c4c63f4a09195c
- Cc: [email protected]
- Signed-off-by: Paolo Bonzini <[email protected]>
- (cherry picked from commit fae1a3e775cca8c3a9e0eb34443b310871a15a92)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit dba4ceb9a91ed2d11a47722436b3c0be15e791d4)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/kvm/emulate.c | 32 +++++++++++++++++++++++++-------
- 1 file changed, 25 insertions(+), 7 deletions(-)
- diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
- index fb0055953fbc..155f2af2cb39 100644
- --- a/arch/x86/kvm/emulate.c
- +++ b/arch/x86/kvm/emulate.c
- @@ -2399,9 +2399,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n)
- }
-
- static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
- - u64 cr0, u64 cr4)
- + u64 cr0, u64 cr3, u64 cr4)
- {
- int bad;
- + u64 pcid;
- +
- + /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */
- + pcid = 0;
- + if (cr4 & X86_CR4_PCIDE) {
- + pcid = cr3 & 0xfff;
- + cr3 &= ~0xfff;
- + }
- +
- + bad = ctxt->ops->set_cr(ctxt, 3, cr3);
- + if (bad)
- + return X86EMUL_UNHANDLEABLE;
-
- /*
- * First enable PAE, long mode needs it before CR0.PG = 1 is set.
- @@ -2420,6 +2432,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
- bad = ctxt->ops->set_cr(ctxt, 4, cr4);
- if (bad)
- return X86EMUL_UNHANDLEABLE;
- + if (pcid) {
- + bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid);
- + if (bad)
- + return X86EMUL_UNHANDLEABLE;
- + }
- +
- }
-
- return X86EMUL_CONTINUE;
- @@ -2430,11 +2448,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
- struct desc_struct desc;
- struct desc_ptr dt;
- u16 selector;
- - u32 val, cr0, cr4;
- + u32 val, cr0, cr3, cr4;
- int i;
-
- cr0 = GET_SMSTATE(u32, smbase, 0x7ffc);
- - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8));
- + cr3 = GET_SMSTATE(u32, smbase, 0x7ff8);
- ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED;
- ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0);
-
- @@ -2476,14 +2494,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
-
- ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8));
-
- - return rsm_enter_protected_mode(ctxt, cr0, cr4);
- + return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
- }
-
- static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
- {
- struct desc_struct desc;
- struct desc_ptr dt;
- - u64 val, cr0, cr4;
- + u64 val, cr0, cr3, cr4;
- u32 base3;
- u16 selector;
- int i, r;
- @@ -2500,7 +2518,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
- ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
-
- cr0 = GET_SMSTATE(u64, smbase, 0x7f58);
- - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50));
- + cr3 = GET_SMSTATE(u64, smbase, 0x7f50);
- cr4 = GET_SMSTATE(u64, smbase, 0x7f48);
- ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00));
- val = GET_SMSTATE(u64, smbase, 0x7ed0);
- @@ -2528,7 +2546,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
- dt.address = GET_SMSTATE(u64, smbase, 0x7e68);
- ctxt->ops->set_gdt(ctxt, &dt);
-
- - r = rsm_enter_protected_mode(ctxt, cr0, cr4);
- + r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
- if (r != X86EMUL_CONTINUE)
- return r;
-
- --
- 2.14.2
|