kernelbase: Don't modify non-volatile regs in RaiseException() on x64.

This commit is contained in:
Paul Gofman 2023-05-30 14:40:53 -06:00 committed by Alexandre Julliard
parent 1db53cdcbb
commit e7845fc330
2 changed files with 145 additions and 0 deletions

View file

@ -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)
/*******************************************************************

View file

@ -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__)