Module: wine Branch: master Commit: e7845fc3305c9c170730b6b7375caadc853ada87 URL: https://gitlab.winehq.org/wine/wine/-/commit/e7845fc3305c9c170730b6b7375caad...
Author: Paul Gofman pgofman@codeweavers.com Date: Tue May 30 14:40:53 2023 -0600
kernelbase: Don't modify non-volatile regs in RaiseException() on x64.
---
dlls/kernelbase/debug.c | 46 ++++++++++++++++++++ dlls/ntdll/tests/exception.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+)
diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 4eff7ad1cca..df1b9a63604 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -283,6 +283,51 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) /******************************************************************* * RaiseException (kernelbase.@) */ +#if defined(__x86_64__) +/* Some DRMs depend on RaiseException not altering non-volatile registers. */ +__ASM_GLOBAL_FUNC( RaiseException, + ".byte 0x48,0x8d,0xa4,0x24,0x00,0x00,0x00,0x00\n\t" /* hotpatch prolog */ + "sub $0xc8,%rsp\n\t" + __ASM_SEH(".seh_stackalloc 0xc8\n\t") + __ASM_SEH(".seh_endprologue\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 0xc8\n\t") + "leaq 0x20(%rsp),%rax\n\t" + "movl %ecx,(%rax)\n\t" /* ExceptionCode */ + "and $1,%edx\n\t" + "movl %edx,4(%rax)\n\t" /* ExceptionFlags */ + "movq $0,8(%rax)\n\t" /* ExceptionRecord */ + "leaq " __ASM_NAME("RaiseException") "(%rip),%rcx\n\t" + "movq %rcx,0x10(%rax)\n\t" /* ExceptionAddress */ + "movq %rax,%rcx\n\t" + "movl $0,0x18(%rcx)\n\t" /* NumberParameters */ + "testl %r8d,%r8d\n\t" + "jz 2f\n\t" + "testq %r9,%r9\n\t" + "jz 2f\n\t" + "movl $15,%edx\n\t" + "cmp %edx,%r8d\n\t" + "cmovb %r8d,%edx\n\t" + "movl %edx,0x18(%rcx)\n\t" /* NumberParameters */ + "leaq 0x20(%rcx),%rax\n" /* ExceptionInformation */ + "1:\tmovq (%r9),%r8\n\t" + "movq %r8,(%rax)\n\t" + "decl %edx\n\t" + "jz 2f\n\t" + "addq $8,%rax\n\t" + "addq $8,%r9\n\t" + "jmp 1b\n" + "2:\tcall " __ASM_NAME("RtlRaiseException") "\n\t" + "add $0xc8,%rsp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -0xc8\n\t") + "ret" ) + +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionCode) == 0 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionFlags) == 4 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionRecord) == 8 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionAddress) == 0x10 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, NumberParameters) == 0x18 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionInformation) == 0x20 ); +#else void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) { EXCEPTION_RECORD record; @@ -301,6 +346,7 @@ void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD cou
RtlRaiseException( &record ); } +#endif __ASM_STDCALL_IMPORT(RaiseException,16)
/******************************************************************* diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 128b2adde3b..f2ba16f4bae 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5031,6 +5031,104 @@ static void test_syscall_clobbered_regs(void) ok(regs.r11 == regs.eflags, "Expected r11 (%#I64x) to equal EFLAGS (%#x).\n", regs.r11, regs.eflags);
} + +static CONTEXT test_raiseexception_regs_context; +static LONG CALLBACK test_raiseexception_regs_handle(EXCEPTION_POINTERS *exception_info) +{ + EXCEPTION_RECORD *rec = exception_info->ExceptionRecord; + unsigned int i; + + test_raiseexception_regs_context = *exception_info->ContextRecord; + ok(rec->NumberParameters == EXCEPTION_MAXIMUM_PARAMETERS, "got %lu.\n", rec->NumberParameters); + ok(rec->ExceptionCode == 0xdeadbeaf, "got %#lx.\n", rec->ExceptionCode); + ok(!rec->ExceptionRecord, "got %p.\n", rec->ExceptionRecord); + ok(!rec->ExceptionFlags, "got %#lx.\n", rec->ExceptionFlags); + for (i = 0; i < rec->NumberParameters; ++i) + ok(rec->ExceptionInformation[i] == i, "got %Iu, i %u.\n", rec->ExceptionInformation[i], i); + return EXCEPTION_CONTINUE_EXECUTION; +} + +static void test_raiseexception_regs(void) +{ + static const BYTE code[] = + { + 0xb8, 0x00, 0xb0, 0xad, 0xde, /* mov $0xdeadb000,%eax */ + 0x53, /* push %rbx */ + 0x48, 0x89, 0xc3, /* mov %rax,%rbx */ + 0x56, /* push %rsi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc6, /* mov %rax,%rsi */ + 0x57, /* push %rdi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc7, /* mov %rax,%rdi */ + 0x55, /* push %rbp */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc5, /* mov %rax,%rbp */ + 0x41, 0x54, /* push %r12 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc4, /* mov %rax,%r12 */ + 0x41, 0x55, /* push %r13 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc5, /* mov %rax,%r13 */ + 0x41, 0x56, /* push %r14 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc6, /* mov %rax,%r14 */ + 0x41, 0x57, /* push %r15 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc7, /* mov %rax,%r15 */ + + 0x50, /* push %rax */ /* align stack */ + 0x48, 0x89, 0xc8, /* mov %rcx,%rax */ + 0xb9, 0xaf, 0xbe, 0xad, 0xde, /* mov $0xdeadbeaf,%ecx */ + 0xff, 0xd0, /* call *%rax */ + 0x58, /* pop %rax */ + + 0x41, 0x5f, /* pop %r15 */ + 0x41, 0x5e, /* pop %r14 */ + 0x41, 0x5d, /* pop %r13 */ + 0x41, 0x5c, /* pop %r12 */ + 0x5d, /* pop %rbp */ + 0x5f, /* pop %rdi */ + 0x5e, /* pop %rsi */ + 0x5b, /* pop %rbx */ + 0xc3, /* ret */ + }; + void (WINAPI *pRaiseException)( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) = RaiseException; + void (WINAPI *func)(void *raise_exception, DWORD flags, DWORD count, const ULONG_PTR *args); + void *vectored_handler; + ULONG_PTR args[20]; + ULONG64 expected; + unsigned int i; + + vectored_handler = AddVectoredExceptionHandler(TRUE, test_raiseexception_regs_handle); + ok(!!vectored_handler, "failed.\n"); + + memcpy(code_mem, code, sizeof(code)); + func = code_mem; + + for (i = 0; i < ARRAY_SIZE(args); ++i) + args[i] = i; + + func(pRaiseException, 0, ARRAY_SIZE(args), args); + expected = 0xdeadb000; + ok(test_raiseexception_regs_context.Rbx == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbx); + ++expected; + ok(test_raiseexception_regs_context.Rsi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rsi); + ++expected; + ok(test_raiseexception_regs_context.Rdi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rdi); + ++expected; + ok(test_raiseexception_regs_context.Rbp == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbp); + ++expected; + ok(test_raiseexception_regs_context.R12 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R12); + ++expected; + ok(test_raiseexception_regs_context.R13 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R13); + ++expected; + ok(test_raiseexception_regs_context.R14 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R14); + ++expected; + ok(test_raiseexception_regs_context.R15 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R15); + + RemoveVectoredExceptionHandler(vectored_handler); +} #elif defined(__arm__)
#define UNW_FLAG_NHANDLER 0 @@ -10974,6 +11072,7 @@ START_TEST(exception) test_copy_context(); test_unwind_from_apc(); test_syscall_clobbered_regs(); + test_raiseexception_regs();
#elif defined(__aarch64__)