a0f7ab8a6a
cherry-pick from upstream 4.14
125 lines
4.3 KiB
Diff
125 lines
4.3 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Paolo Bonzini <pbonzini@redhat.com>
|
|
Date: Thu, 21 Dec 2017 00:49:14 +0100
|
|
Subject: [PATCH] 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 <lersek@redhat.com>
|
|
Tested-by: Laszlo Ersek <lersek@redhat.com>
|
|
Fixes: 660a5d517aaab9187f93854425c4c63f4a09195c
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
(cherry picked from commit fae1a3e775cca8c3a9e0eb34443b310871a15a92)
|
|
Signed-off-by: Andy Whitcroft <apw@canonical.com>
|
|
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
|
|
(cherry picked from commit dba4ceb9a91ed2d11a47722436b3c0be15e791d4)
|
|
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
---
|
|
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
|
|
|