mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 18:07:21 +00:00
ntdll: Fix stack layout for KiUserCallbackDispatcher on i386.
This commit is contained in:
parent
3774b00f31
commit
e60a97c1b4
|
@ -2175,6 +2175,61 @@ static void test_KiUserApcDispatcher(void)
|
||||||
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
|
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CDECL hook_KiUserCallbackDispatcher( void *eip, ULONG id, ULONG *args, ULONG len,
|
||||||
|
ULONG unk1, ULONG unk2, ULONG arg0, ULONG arg1 )
|
||||||
|
{
|
||||||
|
NTSTATUS (WINAPI *func)(void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id];
|
||||||
|
|
||||||
|
trace( "eip %p id %lx args %p (%x) len %lx unk1 %lx unk2 %lx args %lx,%lx\n",
|
||||||
|
eip, id, args, (char *)args - (char *)&eip, len, unk1, unk2, arg0, arg1 );
|
||||||
|
|
||||||
|
if (args[0] != arg0) /* new style with extra esp */
|
||||||
|
{
|
||||||
|
void *esp = (void *)arg0;
|
||||||
|
|
||||||
|
ok( args[0] == arg1, "wrong arg1 %lx / %lx\n", args[0], arg1 );
|
||||||
|
ok( (char *)esp - ((char *)args + len) < 0x10, "wrong esp offset %p / %p\n", esp, args );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eip && pRtlPcToFileHeader)
|
||||||
|
{
|
||||||
|
void *mod, *win32u = GetModuleHandleA("win32u.dll");
|
||||||
|
|
||||||
|
pRtlPcToFileHeader( eip, &mod );
|
||||||
|
if (win32u) ok( mod == win32u, "ret address %p not in win32u %p\n", eip, win32u );
|
||||||
|
else trace( "ret address %p in %p\n", eip, mod );
|
||||||
|
}
|
||||||
|
NtCallbackReturn( NULL, 0, func( args, len ));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_KiUserCallbackDispatcher(void)
|
||||||
|
{
|
||||||
|
BYTE saved_code[7], patched_code[7];
|
||||||
|
DWORD old_protect;
|
||||||
|
BYTE *ptr;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
ret = VirtualProtect( pKiUserCallbackDispatcher, sizeof(saved_code),
|
||||||
|
PAGE_EXECUTE_READWRITE, &old_protect );
|
||||||
|
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
|
||||||
|
|
||||||
|
memcpy( saved_code, pKiUserCallbackDispatcher, sizeof(saved_code) );
|
||||||
|
ptr = patched_code;
|
||||||
|
/* mov $hook_trampoline, %eax */
|
||||||
|
*ptr++ = 0xb8;
|
||||||
|
*(void **)ptr = hook_KiUserCallbackDispatcher;
|
||||||
|
ptr += sizeof(void *);
|
||||||
|
/* call *eax */
|
||||||
|
*ptr++ = 0xff;
|
||||||
|
*ptr++ = 0xd0;
|
||||||
|
memcpy( pKiUserCallbackDispatcher, patched_code, sizeof(patched_code) );
|
||||||
|
|
||||||
|
DestroyWindow( CreateWindowA( "Static", "test", 0, 0, 0, 0, 0, 0, 0, 0, 0 ));
|
||||||
|
|
||||||
|
memcpy( pKiUserCallbackDispatcher, saved_code, sizeof(saved_code));
|
||||||
|
VirtualProtect( pKiUserCallbackDispatcher, sizeof(saved_code), old_protect, &old_protect );
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
#define UNW_FLAG_NHANDLER 0
|
#define UNW_FLAG_NHANDLER 0
|
||||||
|
@ -12121,6 +12176,7 @@ START_TEST(exception)
|
||||||
test_prot_fault();
|
test_prot_fault();
|
||||||
test_KiUserExceptionDispatcher();
|
test_KiUserExceptionDispatcher();
|
||||||
test_KiUserApcDispatcher();
|
test_KiUserApcDispatcher();
|
||||||
|
test_KiUserCallbackDispatcher();
|
||||||
test_extended_context();
|
test_extended_context();
|
||||||
test_copy_context();
|
test_copy_context();
|
||||||
test_set_live_context();
|
test_set_live_context();
|
||||||
|
|
|
@ -465,6 +465,19 @@ struct apc_stack_layout
|
||||||
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x14 );
|
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x14 );
|
||||||
C_ASSERT( sizeof(struct apc_stack_layout) == 0x308 );
|
C_ASSERT( sizeof(struct apc_stack_layout) == 0x308 );
|
||||||
|
|
||||||
|
/* stack layout when calling KiUserCallbackDispatcher */
|
||||||
|
struct callback_stack_layout
|
||||||
|
{
|
||||||
|
ULONG eip; /* 000 */
|
||||||
|
ULONG id; /* 004 */
|
||||||
|
void *args; /* 008 */
|
||||||
|
ULONG len; /* 00c */
|
||||||
|
ULONG unk[2]; /* 010 */
|
||||||
|
ULONG esp; /* 018 */
|
||||||
|
BYTE args_data[0]; /* 01c */
|
||||||
|
};
|
||||||
|
C_ASSERT( sizeof(struct callback_stack_layout) == 0x1c );
|
||||||
|
|
||||||
struct syscall_frame
|
struct syscall_frame
|
||||||
{
|
{
|
||||||
WORD syscall_flags; /* 000 */
|
WORD syscall_flags; /* 000 */
|
||||||
|
@ -1595,8 +1608,8 @@ NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* call_user_mode_callback
|
* call_user_mode_callback
|
||||||
*/
|
*/
|
||||||
extern NTSTATUS call_user_mode_callback( ULONG id, void *args, ULONG len, void **ret_ptr,
|
extern NTSTATUS call_user_mode_callback( ULONG user_esp, void **ret_ptr, ULONG *ret_len,
|
||||||
ULONG *ret_len, void *func, TEB *teb );
|
void *func, TEB *teb );
|
||||||
__ASM_GLOBAL_FUNC( call_user_mode_callback,
|
__ASM_GLOBAL_FUNC( call_user_mode_callback,
|
||||||
"pushl %ebp\n\t"
|
"pushl %ebp\n\t"
|
||||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||||
|
@ -1609,7 +1622,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
|
||||||
__ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
|
__ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
|
||||||
"pushl %edi\n\t"
|
"pushl %edi\n\t"
|
||||||
__ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
|
__ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
|
||||||
"movl 0x20(%ebp),%edx\n\t" /* teb */
|
"movl 0x18(%ebp),%edx\n\t" /* teb */
|
||||||
"pushl 0(%edx)\n\t" /* teb->Tib.ExceptionList */
|
"pushl 0(%edx)\n\t" /* teb->Tib.ExceptionList */
|
||||||
"subl $0x380,%esp\n\t" /* sizeof(struct syscall_frame) */
|
"subl $0x380,%esp\n\t" /* sizeof(struct syscall_frame) */
|
||||||
"andl $~63,%esp\n\t"
|
"andl $~63,%esp\n\t"
|
||||||
|
@ -1620,14 +1633,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
|
||||||
"movl %eax,(%esp)\n\t"
|
"movl %eax,(%esp)\n\t"
|
||||||
"movl %ecx,0x3c(%esp)\n\t" /* frame->prev_frame */
|
"movl %ecx,0x3c(%esp)\n\t" /* frame->prev_frame */
|
||||||
"movl %esp,0x1f8(%edx)\n\t" /* x86_thread_data()->syscall_frame */
|
"movl %esp,0x1f8(%edx)\n\t" /* x86_thread_data()->syscall_frame */
|
||||||
"movl 0x1c(%ebp),%ecx\n\t" /* func */
|
"movl 0x14(%ebp),%ecx\n\t" /* func */
|
||||||
"movl 0x0c(%ebp),%edx\n\t" /* args */
|
|
||||||
/* switch to user stack */
|
/* switch to user stack */
|
||||||
"leal -4(%edx),%esp\n\t"
|
"movl 8(%ebp),%esp\n\t"
|
||||||
"pushl 0x10(%ebp)\n\t" /* len */
|
|
||||||
"pushl %edx\n\t" /* args */
|
|
||||||
"pushl 0x08(%ebp)\n\t" /* id */
|
|
||||||
"pushl $0\n\t"
|
|
||||||
"xorl %ebp,%ebp\n\t"
|
"xorl %ebp,%ebp\n\t"
|
||||||
"jmpl *%ecx" )
|
"jmpl *%ecx" )
|
||||||
|
|
||||||
|
@ -1654,9 +1662,9 @@ __ASM_GLOBAL_FUNC( user_mode_callback_return,
|
||||||
"movl 8(%esp),%edi\n\t" /* ret_len */
|
"movl 8(%esp),%edi\n\t" /* ret_len */
|
||||||
"movl 12(%esp),%eax\n\t" /* status */
|
"movl 12(%esp),%eax\n\t" /* status */
|
||||||
"leal -16(%ebp),%esp\n\t"
|
"leal -16(%ebp),%esp\n\t"
|
||||||
"movl 0x14(%ebp),%ecx\n\t" /* ret_ptr */
|
"movl 0x0c(%ebp),%ecx\n\t" /* ret_ptr */
|
||||||
"movl %esi,(%ecx)\n\t"
|
"movl %esi,(%ecx)\n\t"
|
||||||
"movl 0x18(%ebp),%ecx\n\t" /* ret_len */
|
"movl 0x10(%ebp),%ecx\n\t" /* ret_len */
|
||||||
"movl %edi,(%ecx)\n\t"
|
"movl %edi,(%ecx)\n\t"
|
||||||
"popl 0(%edx)\n\t" /* teb->Tib.ExceptionList */
|
"popl 0(%edx)\n\t" /* teb->Tib.ExceptionList */
|
||||||
"popl %edi\n\t"
|
"popl %edi\n\t"
|
||||||
|
@ -1698,14 +1706,19 @@ __ASM_GLOBAL_FUNC( user_mode_abort_thread,
|
||||||
NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_ptr, ULONG *ret_len )
|
NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_ptr, ULONG *ret_len )
|
||||||
{
|
{
|
||||||
struct syscall_frame *frame = x86_thread_data()->syscall_frame;
|
struct syscall_frame *frame = x86_thread_data()->syscall_frame;
|
||||||
void *args_data = (void *)((frame->esp - len) & ~15);
|
ULONG esp = (frame->esp - offsetof(struct callback_stack_layout, args_data[len])) & ~3;
|
||||||
|
struct callback_stack_layout *stack = (struct callback_stack_layout *)esp;
|
||||||
|
|
||||||
if ((char *)ntdll_get_thread_data()->kernel_stack + min_kernel_stack > (char *)&frame)
|
if ((char *)ntdll_get_thread_data()->kernel_stack + min_kernel_stack > (char *)&frame)
|
||||||
return STATUS_STACK_OVERFLOW;
|
return STATUS_STACK_OVERFLOW;
|
||||||
|
|
||||||
memcpy( args_data, args, len );
|
stack->eip = frame->eip;
|
||||||
return call_user_mode_callback( id, args_data, len, ret_ptr, ret_len,
|
stack->id = id;
|
||||||
pKiUserCallbackDispatcher, NtCurrentTeb() );
|
stack->args = stack->args_data;
|
||||||
|
stack->len = len;
|
||||||
|
stack->esp = frame->esp;
|
||||||
|
memcpy( stack->args_data, args, len );
|
||||||
|
return call_user_mode_callback( esp, ret_ptr, ret_len, pKiUserCallbackDispatcher, NtCurrentTeb() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1095,20 +1095,31 @@ NTSTATUS WINAPI Wow64KiUserCallbackDispatcher( ULONG id, void *args, ULONG len,
|
||||||
{
|
{
|
||||||
case IMAGE_FILE_MACHINE_I386:
|
case IMAGE_FILE_MACHINE_I386:
|
||||||
{
|
{
|
||||||
|
/* stack layout when calling 32-bit KiUserCallbackDispatcher */
|
||||||
|
struct callback_stack_layout32
|
||||||
|
{
|
||||||
|
ULONG eip; /* 000 */
|
||||||
|
ULONG id; /* 004 */
|
||||||
|
ULONG args; /* 008 */
|
||||||
|
ULONG len; /* 00c */
|
||||||
|
ULONG unk[2]; /* 010 */
|
||||||
|
ULONG esp; /* 018 */
|
||||||
|
BYTE args_data[0]; /* 01c */
|
||||||
|
} *stack;
|
||||||
I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
|
I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
|
||||||
void *args_data;
|
|
||||||
ULONG *stack;
|
C_ASSERT( sizeof(struct callback_stack_layout32) == 0x1c );
|
||||||
|
|
||||||
pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
|
pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
|
||||||
orig_ctx = ctx;
|
orig_ctx = ctx;
|
||||||
|
|
||||||
stack = args_data = ULongToPtr( (ctx.Esp - len) & ~15 );
|
stack = ULongToPtr( (ctx.Esp - offsetof(struct callback_stack_layout32,args_data[len])) & ~15 );
|
||||||
memcpy( args_data, args, len );
|
stack->eip = ctx.Eip;
|
||||||
*(--stack) = 0;
|
stack->id = id;
|
||||||
*(--stack) = len;
|
stack->args = PtrToUlong( stack->args_data );
|
||||||
*(--stack) = PtrToUlong( args_data );
|
stack->len = len;
|
||||||
*(--stack) = id;
|
stack->esp = ctx.Esp;
|
||||||
*(--stack) = 0xdeadbabe;
|
memcpy( stack->args_data, args, len );
|
||||||
|
|
||||||
ctx.Esp = PtrToUlong( stack );
|
ctx.Esp = PtrToUlong( stack );
|
||||||
ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
|
ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
|
||||||
|
|
Loading…
Reference in a new issue