TRY_ASM() mishandles #UD thrown by the forced-emulation-triggered emulator. While the faulting address stored in the exception table points at forced emulation prefix, when #UD comes, RIP is 5 bytes (size of KVM_FEP) ahead and the exception ends up unhandled.
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Michal Luczaj mhal@rbox.co --- While here, I've also took the opportunity to merge both 32 and 64-bit versions of ASM_TRY() (.dc.a for .long and .quad), but perhaps there were some reasons for not using .dc.a?
lib/x86/desc.h | 11 +++++------ x86/emulator.c | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 2a285eb..99cc224 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -80,21 +80,20 @@ typedef struct __attribute__((packed)) { u16 iomap_base; } tss64_t;
-#ifdef __x86_64 #define ASM_TRY(catch) \ "movl $0, %%gs:4 \n\t" \ ".pushsection .data.ex \n\t" \ - ".quad 1111f, " catch "\n\t" \ + ".dc.a 1111f, " catch "\n\t" \ ".popsection \n\t" \ "1111:" -#else -#define ASM_TRY(catch) \ + +#define ASM_TRY_PREFIXED(prefix, catch) \ "movl $0, %%gs:4 \n\t" \ ".pushsection .data.ex \n\t" \ - ".long 1111f, " catch "\n\t" \ + ".dc.a 1111f, " catch "\n\t" \ ".popsection \n\t" \ + prefix "\n\t" \ "1111:" -#endif
/* * selector 32-bit 64-bit diff --git a/x86/emulator.c b/x86/emulator.c index df0bc49..d2a5302 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -900,8 +900,8 @@ static void test_illegal_lea(void) { unsigned int vector;
- asm volatile (ASM_TRY("1f") - KVM_FEP ".byte 0x8d; .byte 0xc0\n\t" + asm volatile (ASM_TRY_PREFIXED(KVM_FEP, "1f") + ".byte 0x8d; .byte 0xc0\n\t" "1:" : : : "memory", "eax");