From: Paolo Bonzini pbonzini@redhat.com
TRY_ASM() mishandles exceptions thrown by the forced-emulation-triggered emulator. While the faulting address stored in the exception table points at forced emulation prefix, when an exceptions comes, RIP is 5 bytes (size of KVM_FEP) ahead and the exception ends up unhandled.
Signed-off-by: Michal Luczaj mhal@rbox.co --- For the sake of completeness, I've added `prefix` to 32-bit __TRY_ASM() as well.
lib/x86/desc.h | 8 ++++++-- x86/emulator.c | 1 + 2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 2a285eb..8854fcc 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -81,21 +81,25 @@ typedef struct __attribute__((packed)) { } tss64_t;
#ifdef __x86_64 -#define ASM_TRY(catch) \ +#define __ASM_TRY(prefix, catch) \ "movl $0, %%gs:4 \n\t" \ ".pushsection .data.ex \n\t" \ ".quad 1111f, " catch "\n\t" \ ".popsection \n\t" \ + prefix \ "1111:" #else -#define ASM_TRY(catch) \ +#define __ASM_TRY(prefix, catch) \ "movl $0, %%gs:4 \n\t" \ ".pushsection .data.ex \n\t" \ ".long 1111f, " catch "\n\t" \ ".popsection \n\t" \ + prefix \ "1111:" #endif
+#define ASM_TRY(catch) __ASM_TRY("", catch) + /* * selector 32-bit 64-bit * 0x00 NULL descriptor NULL descriptor diff --git a/x86/emulator.c b/x86/emulator.c index 96d3ccd..0eb7c1a 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -19,6 +19,7 @@ static int exceptions;
/* Forced emulation prefix, used to invoke the emulator unconditionally. */ #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" +#define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch)
struct regs { u64 rax, rbx, rcx, rdx;