ntdll: Fix stack layout for KiUserApcDispatcher on i386.

This commit is contained in:
Alexandre Julliard 2023-11-30 17:40:57 +01:00
parent 58a00854c3
commit 3774b00f31
4 changed files with 164 additions and 38 deletions

View file

@ -255,12 +255,14 @@ __ASM_STDCALL_FUNC( KiUserExceptionDispatcher, 8,
/*******************************************************************
* KiUserApcDispatcher (NTDLL.@)
*/
void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
PNTAPCFUNC func )
{
func( ctx, arg1, arg2 );
NtContinue( context, TRUE );
}
__ASM_STDCALL_FUNC( KiUserApcDispatcher, 20,
"leal 0x14(%esp),%ebx\n\t" /* context */
"pop %eax\n\t" /* func */
"call *%eax\n\t"
"pushl -4(%ebx)\n\t" /* alertable */
"pushl %ebx\n\t" /* context */
"call " __ASM_STDCALL("NtContinue", 8) "\n\t"
"int3" )
/*******************************************************************

View file

@ -2070,6 +2070,111 @@ static void test_KiUserExceptionDispatcher(void)
ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
}
static BYTE saved_KiUserApcDispatcher[7];
static UINT apc_count;
static void CALLBACK apc_func( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
ok( arg1 == 0x1234 + apc_count, "wrong arg1 %Ix\n", arg1 );
ok( arg2 == 0x5678, "wrong arg2 %Ix\n", arg2 );
ok( arg3 == 0xdeadbeef, "wrong arg3 %Ix\n", arg3 );
apc_count++;
}
static void * CDECL hook_KiUserApcDispatcher( void *func, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
CONTEXT *context = (CONTEXT *)((ULONG_PTR)&arg3 + sizeof(ULONG));
ok( func == apc_func, "wrong function %p / %p\n", func, apc_func );
ok( arg1 == 0x1234 + apc_count, "wrong arg1 %Ix\n", arg1 );
ok( arg2 == 0x5678, "wrong arg2 %Ix\n", arg2 );
ok( arg3 == 0xdeadbeef, "wrong arg3 %Ix\n", arg3 );
if (context->ContextFlags != 1)
{
trace( "context %p eip %lx ebp %lx esp %lx (%x)\n",
context, context->Eip, context->Ebp, context->Esp, (char *)context->Esp - (char *)&func );
}
else /* new style with alertable arg and CONTEXT_EX */
{
CONTEXT_EX *xctx;
ULONG *alertable = (ULONG *)context;
context = (CONTEXT *)(alertable + 1);
xctx = (CONTEXT_EX *)(context + 1);
trace( "alertable %lx context %p eip %lx ebp %lx esp %lx (%x)\n", *alertable,
context, context->Eip, context->Ebp, context->Esp, (char *)context->Esp - (char *)&func );
if ((void *)(xctx + 1) < (void *)context->Esp)
{
ok( xctx->All.Offset == -sizeof(CONTEXT), "wrong All.Offset %lx\n", xctx->All.Offset );
ok( xctx->All.Length >= sizeof(CONTEXT) + sizeof(CONTEXT_EX), "wrong All.Length %lx\n", xctx->All.Length );
ok( xctx->Legacy.Offset == -sizeof(CONTEXT), "wrong Legacy.Offset %lx\n", xctx->All.Offset );
ok( xctx->Legacy.Length == sizeof(CONTEXT), "wrong Legacy.Length %lx\n", xctx->All.Length );
}
if (apc_count) *alertable = 0;
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count + 1, 0x5678, 0xdeadbeef );
}
hook_called = TRUE;
memcpy( pKiUserApcDispatcher, saved_KiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher));
return pKiUserApcDispatcher;
}
static void test_KiUserApcDispatcher(void)
{
BYTE hook_trampoline[] =
{
0xff, 0x15,
/* offset: 2 bytes */
0x00, 0x00, 0x00, 0x00, /* call *addr */ /* call hook implementation. */
0xff, 0xe0, /* jmp *%eax */
};
BYTE patched_KiUserApcDispatcher[7];
void *phook_KiUserApcDispatcher = hook_KiUserApcDispatcher;
DWORD old_protect;
BYTE *ptr;
BOOL ret;
*(ULONG_PTR *)(hook_trampoline + 2) = (ULONG_PTR)&phook_KiUserApcDispatcher;
memcpy(code_mem, hook_trampoline, sizeof(hook_trampoline));
ret = VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher),
PAGE_EXECUTE_READWRITE, &old_protect );
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
memcpy( saved_KiUserApcDispatcher, pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher) );
ptr = patched_KiUserApcDispatcher;
/* mov $hook_trampoline, %eax */
*ptr++ = 0xb8;
*(void **)ptr = code_mem;
ptr += sizeof(void *);
/* jmp *eax */
*ptr++ = 0xff;
*ptr++ = 0xe0;
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
apc_count = 0;
hook_called = FALSE;
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234, 0x5678, 0xdeadbeef );
SleepEx( 0, TRUE );
ok( apc_count == 1 || apc_count == 2, "APC count %u\n", apc_count );
ok( hook_called, "hook was not called\n" );
if (apc_count == 2)
{
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count, 0x5678, 0xdeadbeef );
SleepEx( 0, TRUE );
ok( apc_count == 3, "APC count %u\n", apc_count );
SleepEx( 0, TRUE );
ok( apc_count == 4, "APC count %u\n", apc_count );
}
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
}
#elif defined(__x86_64__)
#define UNW_FLAG_NHANDLER 0
@ -12015,6 +12120,7 @@ START_TEST(exception)
test_dpe_exceptions();
test_prot_fault();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_extended_context();
test_copy_context();
test_set_live_context();

View file

@ -450,6 +450,21 @@ C_ASSERT( offsetof(struct exc_stack_layout, context) == 0x58 );
C_ASSERT( offsetof(struct exc_stack_layout, xstate) == 0x33c );
C_ASSERT( sizeof(struct exc_stack_layout) == 0x4c0 );
/* stack layout when calling KiUserApcDispatcher */
struct apc_stack_layout
{
PNTAPCFUNC func; /* 000 */
UINT arg1; /* 004 */
UINT arg2; /* 008 */
UINT arg3; /* 00c */
UINT alertable; /* 010 */
CONTEXT context; /* 014 */
CONTEXT_EX xctx; /* 2e0 */
UINT unk2[4]; /* 2f8 */
};
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x14 );
C_ASSERT( sizeof(struct apc_stack_layout) == 0x308 );
struct syscall_frame
{
WORD syscall_flags; /* 000 */
@ -1495,17 +1510,6 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
setup_raise_exception( sigcontext, stack, rec, &xcontext );
}
/* stack layout when calling an user apc function.
* FIXME: match Windows ABI. */
struct apc_stack_layout
{
CONTEXT *context_ptr;
ULONG_PTR arg1;
ULONG_PTR arg2;
ULONG_PTR arg3;
PNTAPCFUNC func;
CONTEXT context;
};
/***********************************************************************
* call_user_apc_dispatcher
@ -1525,13 +1529,14 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
}
else memmove( &stack->context, context, sizeof(stack->context) );
stack->context_ptr = &stack->context;
stack->arg1 = arg1;
stack->arg2 = arg2;
stack->arg3 = arg3;
stack->func = func;
context_init_xstate( &stack->context, NULL );
stack->func = func;
stack->arg1 = arg1;
stack->arg2 = arg2;
stack->arg3 = arg3;
stack->alertable = TRUE;
frame->ebp = stack->context.Ebp;
frame->esp = (ULONG)stack - 4;
frame->esp = (ULONG)stack;
frame->eip = (ULONG)pKiUserApcDispatcher;
return status;
}

View file

@ -1000,26 +1000,39 @@ void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CON
{
case IMAGE_FILE_MACHINE_I386:
{
struct apc_stack_layout
/* stack layout when calling 32-bit KiUserApcDispatcher */
struct apc_stack_layout32
{
ULONG ret;
ULONG context_ptr;
ULONG arg1;
ULONG arg2;
ULONG arg3;
ULONG func;
I386_CONTEXT context;
ULONG func; /* 000 */
UINT arg1; /* 004 */
UINT arg2; /* 008 */
UINT arg3; /* 00c */
UINT alertable; /* 010 */
I386_CONTEXT context; /* 014 */
CONTEXT_EX32 xctx; /* 2e0 */
UINT unk2[4]; /* 2f8 */
} *stack;
I386_CONTEXT ctx = { CONTEXT_I386_FULL };
C_ASSERT( offsetof(struct apc_stack_layout32, context) == 0x14 );
C_ASSERT( sizeof(struct apc_stack_layout32) == 0x308 );
pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
stack->context_ptr = PtrToUlong( &stack->context );
stack->func = arg1 >> 32;
stack->arg1 = arg1;
stack->arg2 = arg2;
stack->arg3 = arg3;
stack->context = ctx;
stack = (struct apc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
stack->func = arg1 >> 32;
stack->arg1 = arg1;
stack->arg2 = arg2;
stack->arg3 = arg3;
stack->alertable = TRUE;
stack->context = ctx;
stack->xctx.Legacy.Offset = -(LONG)sizeof(stack->context);
stack->xctx.Legacy.Length = sizeof(stack->context);
stack->xctx.All.Offset = -(LONG)sizeof(stack->context);
stack->xctx.All.Length = sizeof(stack->context) + sizeof(stack->xctx);
stack->xctx.XState.Offset = 25;
stack->xctx.XState.Length = 0;
ctx.Esp = PtrToUlong( stack );
ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
frame.wow_context = &stack->context;