-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
backport "SMM emulation and interrupt shadow fixes"
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
- Loading branch information
1 parent
aa04318
commit f6df304
Showing
10 changed files
with
1,387 additions
and
0 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
patches/kernel/0015-KVM-x86-emulator-em_sysexit-should-update-ctxt-mode.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Maxim Levitsky <mlevitsk@redhat.com> | ||
Date: Tue, 21 Jun 2022 18:08:52 +0300 | ||
Subject: [PATCH] KVM: x86: emulator: em_sysexit should update ctxt->mode | ||
|
||
This is one of the instructions that can change the | ||
processor mode. | ||
|
||
Note that this is likely a benign bug, because the only problematic | ||
mode change is from 32 bit to 64 bit which can lead to truncation of RIP, | ||
and it is not possible to do with sysexit, | ||
since sysexit running in 32 bit mode will be limited to 32 bit version. | ||
|
||
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||
--- | ||
arch/x86/kvm/emulate.c | 1 + | ||
1 file changed, 1 insertion(+) | ||
|
||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c | ||
index 318a78379ca6..35b12692739c 100644 | ||
--- a/arch/x86/kvm/emulate.c | ||
+++ b/arch/x86/kvm/emulate.c | ||
@@ -2862,6 +2862,7 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) | ||
ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); | ||
|
||
ctxt->_eip = rdx; | ||
+ ctxt->mode = usermode; | ||
*reg_write(ctxt, VCPU_REGS_RSP) = rcx; | ||
|
||
return X86EMUL_CONTINUE; |
158 changes: 158 additions & 0 deletions
158
patches/kernel/0016-KVM-x86-emulator-introduce-update_emulation_mode.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Maxim Levitsky <mlevitsk@redhat.com> | ||
Date: Tue, 21 Jun 2022 18:08:53 +0300 | ||
Subject: [PATCH] KVM: x86: emulator: introduce update_emulation_mode | ||
|
||
Some instructions update the cpu execution mode, which needs | ||
to update the emulation mode. | ||
|
||
Extract this code, and make assign_eip_far use it. | ||
|
||
assign_eip_far now reads CS, instead of getting it via a parameter, | ||
which is ok, because callers always assign CS to the | ||
same value before calling it. | ||
|
||
No functional change is intended. | ||
|
||
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||
--- | ||
arch/x86/kvm/emulate.c | 85 ++++++++++++++++++++++++++++-------------- | ||
1 file changed, 57 insertions(+), 28 deletions(-) | ||
|
||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c | ||
index 35b12692739c..1b5123a882a1 100644 | ||
--- a/arch/x86/kvm/emulate.c | ||
+++ b/arch/x86/kvm/emulate.c | ||
@@ -795,8 +795,7 @@ static int linearize(struct x86_emulate_ctxt *ctxt, | ||
ctxt->mode, linear); | ||
} | ||
|
||
-static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst, | ||
- enum x86emul_mode mode) | ||
+static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst) | ||
{ | ||
ulong linear; | ||
int rc; | ||
@@ -806,41 +805,71 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst, | ||
|
||
if (ctxt->op_bytes != sizeof(unsigned long)) | ||
addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1); | ||
- rc = __linearize(ctxt, addr, &max_size, 1, false, true, mode, &linear); | ||
+ rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear); | ||
if (rc == X86EMUL_CONTINUE) | ||
ctxt->_eip = addr.ea; | ||
return rc; | ||
} | ||
|
||
+static inline int update_emulation_mode(struct x86_emulate_ctxt *ctxt) | ||
+{ | ||
+ u64 efer; | ||
+ struct desc_struct cs; | ||
+ u16 selector; | ||
+ u32 base3; | ||
+ | ||
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); | ||
+ | ||
+ if (!ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE) { | ||
+ /* Real mode. cpu must not have long mode active */ | ||
+ if (efer & EFER_LMA) | ||
+ return X86EMUL_UNHANDLEABLE; | ||
+ ctxt->mode = X86EMUL_MODE_REAL; | ||
+ return X86EMUL_CONTINUE; | ||
+ } | ||
+ | ||
+ if (ctxt->eflags & X86_EFLAGS_VM) { | ||
+ /* Protected/VM86 mode. cpu must not have long mode active */ | ||
+ if (efer & EFER_LMA) | ||
+ return X86EMUL_UNHANDLEABLE; | ||
+ ctxt->mode = X86EMUL_MODE_VM86; | ||
+ return X86EMUL_CONTINUE; | ||
+ } | ||
+ | ||
+ if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS)) | ||
+ return X86EMUL_UNHANDLEABLE; | ||
+ | ||
+ if (efer & EFER_LMA) { | ||
+ if (cs.l) { | ||
+ /* Proper long mode */ | ||
+ ctxt->mode = X86EMUL_MODE_PROT64; | ||
+ } else if (cs.d) { | ||
+ /* 32 bit compatibility mode*/ | ||
+ ctxt->mode = X86EMUL_MODE_PROT32; | ||
+ } else { | ||
+ ctxt->mode = X86EMUL_MODE_PROT16; | ||
+ } | ||
+ } else { | ||
+ /* Legacy 32 bit / 16 bit mode */ | ||
+ ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | ||
+ } | ||
+ | ||
+ return X86EMUL_CONTINUE; | ||
+} | ||
+ | ||
static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) | ||
{ | ||
- return assign_eip(ctxt, dst, ctxt->mode); | ||
+ return assign_eip(ctxt, dst); | ||
} | ||
|
||
-static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, | ||
- const struct desc_struct *cs_desc) | ||
+static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst) | ||
{ | ||
- enum x86emul_mode mode = ctxt->mode; | ||
- int rc; | ||
+ int rc = update_emulation_mode(ctxt); | ||
|
||
-#ifdef CONFIG_X86_64 | ||
- if (ctxt->mode >= X86EMUL_MODE_PROT16) { | ||
- if (cs_desc->l) { | ||
- u64 efer = 0; | ||
+ if (rc != X86EMUL_CONTINUE) | ||
+ return rc; | ||
|
||
- ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); | ||
- if (efer & EFER_LMA) | ||
- mode = X86EMUL_MODE_PROT64; | ||
- } else | ||
- mode = X86EMUL_MODE_PROT32; /* temporary value */ | ||
- } | ||
-#endif | ||
- if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32) | ||
- mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | ||
- rc = assign_eip(ctxt, dst, mode); | ||
- if (rc == X86EMUL_CONTINUE) | ||
- ctxt->mode = mode; | ||
- return rc; | ||
+ return assign_eip(ctxt, dst); | ||
} | ||
|
||
static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) | ||
@@ -2154,7 +2183,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt) | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
|
||
- rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc); | ||
+ rc = assign_eip_far(ctxt, ctxt->src.val); | ||
/* Error handling is not implemented. */ | ||
if (rc != X86EMUL_CONTINUE) | ||
return X86EMUL_UNHANDLEABLE; | ||
@@ -2235,7 +2264,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt) | ||
&new_desc); | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
- rc = assign_eip_far(ctxt, eip, &new_desc); | ||
+ rc = assign_eip_far(ctxt, eip); | ||
/* Error handling is not implemented. */ | ||
if (rc != X86EMUL_CONTINUE) | ||
return X86EMUL_UNHANDLEABLE; | ||
@@ -3459,7 +3488,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt) | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
|
||
- rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc); | ||
+ rc = assign_eip_far(ctxt, ctxt->src.val); | ||
if (rc != X86EMUL_CONTINUE) | ||
goto fail; | ||
|
127 changes: 127 additions & 0 deletions
127
patches/kernel/0017-KVM-x86-emulator-remove-assign_eip_near-far.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Maxim Levitsky <mlevitsk@redhat.com> | ||
Date: Tue, 21 Jun 2022 18:08:54 +0300 | ||
Subject: [PATCH] KVM: x86: emulator: remove assign_eip_near/far | ||
|
||
Now the assign_eip_far just updates the emulation mode in addition to | ||
updating the rip, it doesn't make sense to keep that function. | ||
|
||
Move mode update to the callers and remove these functions. | ||
|
||
No functional change is intended. | ||
|
||
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||
--- | ||
arch/x86/kvm/emulate.c | 47 +++++++++++++++++++++--------------------- | ||
1 file changed, 24 insertions(+), 23 deletions(-) | ||
|
||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c | ||
index 1b5123a882a1..9e305e0cd815 100644 | ||
--- a/arch/x86/kvm/emulate.c | ||
+++ b/arch/x86/kvm/emulate.c | ||
@@ -857,24 +857,9 @@ static inline int update_emulation_mode(struct x86_emulate_ctxt *ctxt) | ||
return X86EMUL_CONTINUE; | ||
} | ||
|
||
-static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) | ||
-{ | ||
- return assign_eip(ctxt, dst); | ||
-} | ||
- | ||
-static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst) | ||
-{ | ||
- int rc = update_emulation_mode(ctxt); | ||
- | ||
- if (rc != X86EMUL_CONTINUE) | ||
- return rc; | ||
- | ||
- return assign_eip(ctxt, dst); | ||
-} | ||
- | ||
static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) | ||
{ | ||
- return assign_eip_near(ctxt, ctxt->_eip + rel); | ||
+ return assign_eip(ctxt, ctxt->_eip + rel); | ||
} | ||
|
||
static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, | ||
@@ -2183,7 +2168,12 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt) | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
|
||
- rc = assign_eip_far(ctxt, ctxt->src.val); | ||
+ rc = update_emulation_mode(ctxt); | ||
+ if (rc != X86EMUL_CONTINUE) | ||
+ return rc; | ||
+ | ||
+ rc = assign_eip(ctxt, ctxt->src.val); | ||
+ | ||
/* Error handling is not implemented. */ | ||
if (rc != X86EMUL_CONTINUE) | ||
return X86EMUL_UNHANDLEABLE; | ||
@@ -2193,7 +2183,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt) | ||
|
||
static int em_jmp_abs(struct x86_emulate_ctxt *ctxt) | ||
{ | ||
- return assign_eip_near(ctxt, ctxt->src.val); | ||
+ return assign_eip(ctxt, ctxt->src.val); | ||
} | ||
|
||
static int em_call_near_abs(struct x86_emulate_ctxt *ctxt) | ||
@@ -2202,7 +2192,7 @@ static int em_call_near_abs(struct x86_emulate_ctxt *ctxt) | ||
long int old_eip; | ||
|
||
old_eip = ctxt->_eip; | ||
- rc = assign_eip_near(ctxt, ctxt->src.val); | ||
+ rc = assign_eip(ctxt, ctxt->src.val); | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
ctxt->src.val = old_eip; | ||
@@ -2240,7 +2230,7 @@ static int em_ret(struct x86_emulate_ctxt *ctxt) | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
|
||
- return assign_eip_near(ctxt, eip); | ||
+ return assign_eip(ctxt, eip); | ||
} | ||
|
||
static int em_ret_far(struct x86_emulate_ctxt *ctxt) | ||
@@ -2264,7 +2254,13 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt) | ||
&new_desc); | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
- rc = assign_eip_far(ctxt, eip); | ||
+ | ||
+ rc = update_emulation_mode(ctxt); | ||
+ if (rc != X86EMUL_CONTINUE) | ||
+ return rc; | ||
+ | ||
+ rc = assign_eip(ctxt, eip); | ||
+ | ||
/* Error handling is not implemented. */ | ||
if (rc != X86EMUL_CONTINUE) | ||
return X86EMUL_UNHANDLEABLE; | ||
@@ -3488,7 +3484,12 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt) | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
|
||
- rc = assign_eip_far(ctxt, ctxt->src.val); | ||
+ rc = update_emulation_mode(ctxt); | ||
+ if (rc != X86EMUL_CONTINUE) | ||
+ return rc; | ||
+ | ||
+ rc = assign_eip(ctxt, ctxt->src.val); | ||
+ | ||
if (rc != X86EMUL_CONTINUE) | ||
goto fail; | ||
|
||
@@ -3521,7 +3522,7 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) | ||
rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
- rc = assign_eip_near(ctxt, eip); | ||
+ rc = assign_eip(ctxt, eip); | ||
if (rc != X86EMUL_CONTINUE) | ||
return rc; | ||
rsp_increment(ctxt, ctxt->src.val); |
34 changes: 34 additions & 0 deletions
34
patches/kernel/0018-KVM-x86-emulator-update-the-emulation-mode-after-rsm.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Maxim Levitsky <mlevitsk@redhat.com> | ||
Date: Tue, 21 Jun 2022 18:08:55 +0300 | ||
Subject: [PATCH] KVM: x86: emulator: update the emulation mode after rsm | ||
|
||
This ensures that RIP will be correctly written back, | ||
because the RSM instruction can switch the CPU mode from | ||
32 bit (or less) to 64 bit. | ||
|
||
This fixes a guest crash in case the #SMI is received | ||
while the guest runs a code from an address > 32 bit. | ||
|
||
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||
--- | ||
arch/x86/kvm/emulate.c | 5 +++++ | ||
1 file changed, 5 insertions(+) | ||
|
||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c | ||
index 9e305e0cd815..c582639ea2b4 100644 | ||
--- a/arch/x86/kvm/emulate.c | ||
+++ b/arch/x86/kvm/emulate.c | ||
@@ -2635,6 +2635,11 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) | ||
if (ret != X86EMUL_CONTINUE) | ||
goto emulate_shutdown; | ||
|
||
+ | ||
+ ret = update_emulation_mode(ctxt); | ||
+ if (ret != X86EMUL_CONTINUE) | ||
+ goto emulate_shutdown; | ||
+ | ||
/* | ||
* Note, the ctxt->ops callbacks are responsible for handling side | ||
* effects when writing MSRs and CRs, e.g. MMU context resets, CPUID |
Oops, something went wrong.