Skip to content

Commit 8b24139

Browse files
committed
ntdll: Add a machine frame to the KiUserApcDispatcher stack on x86-64.
1 parent 061c612 commit 8b24139

File tree

3 files changed

+142
-42
lines changed

3 files changed

+142
-42
lines changed

dlls/ntdll/signal_x86_64.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -652,30 +652,40 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
652652
/*******************************************************************
653653
* KiUserApcDispatcher (NTDLL.@)
654654
*/
655-
void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
656-
void (CALLBACK *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR,CONTEXT*) )
657-
{
658-
func( arg1, arg2, arg3, context );
659-
NtContinue( context, TRUE );
660-
}
661-
662655
__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
663-
"addq $0x8,%rsp\n\t"
664-
"mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
665-
"mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
666-
"mov %r11,-0x8(%r10)\n\t"
667-
"mov %rbp,-0x10(%r10)\n\t"
668-
"lea -0x10(%r10),%rbp\n\t"
669-
__ASM_SEH(".seh_pushreg %rbp\n\t")
670-
__ASM_SEH(".seh_setframe %rbp,0\n\t")
671-
__ASM_SEH(".seh_endprologue\n\t")
672-
__ASM_CFI(".cfi_signal_frame\n\t")
673-
__ASM_CFI(".cfi_adjust_cfa_offset 0x10\n\t")
674-
__ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
675-
__ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
676-
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
677-
"call " __ASM_NAME("dispatch_apc") "\n\t"
678-
"int3")
656+
__ASM_SEH(".seh_pushframe\n\t")
657+
__ASM_SEH(".seh_stackalloc 0x4d0\n\t") /* sizeof(CONTEXT) */
658+
__ASM_SEH(".seh_savereg %rbx,0x90\n\t")
659+
__ASM_SEH(".seh_savereg %rbp,0xa0\n\t")
660+
__ASM_SEH(".seh_savereg %rsi,0xa8\n\t")
661+
__ASM_SEH(".seh_savereg %rdi,0xb0\n\t")
662+
__ASM_SEH(".seh_savereg %r12,0xd8\n\t")
663+
__ASM_SEH(".seh_savereg %r13,0xe0\n\t")
664+
__ASM_SEH(".seh_savereg %r14,0xe8\n\t")
665+
__ASM_SEH(".seh_savereg %r15,0xf0\n\t")
666+
__ASM_SEH(".seh_endprologue\n\t")
667+
__ASM_CFI(".cfi_signal_frame\n\t")
668+
__ASM_CFI(".cfi_def_cfa_offset 0\n\t")
669+
__ASM_CFI(".cfi_offset %rbx,0x90\n\t")
670+
__ASM_CFI(".cfi_offset %rbp,0xa0\n\t")
671+
__ASM_CFI(".cfi_offset %rsi,0xa8\n\t")
672+
__ASM_CFI(".cfi_offset %rdi,0xb0\n\t")
673+
__ASM_CFI(".cfi_offset %r12,0xd8\n\t")
674+
__ASM_CFI(".cfi_offset %r13,0xe0\n\t")
675+
__ASM_CFI(".cfi_offset %r14,0xe8\n\t")
676+
__ASM_CFI(".cfi_offset %r15,0xf0\n\t")
677+
__ASM_CFI(".cfi_offset %rip,0x4d0\n\t")
678+
__ASM_CFI(".cfi_offset %rsp,0x4e8\n\t")
679+
"movq 0x00(%rsp),%rcx\n\t" /* context->P1Home = arg1 */
680+
"movq 0x08(%rsp),%rdx\n\t" /* context->P2Home = arg2 */
681+
"movq 0x10(%rsp),%r8\n\t" /* context->P3Home = arg3 */
682+
"movq 0x18(%rsp),%rax\n\t" /* context->P4Home = func */
683+
"movq %rsp,%r9\n\t" /* context */
684+
"callq *%rax\n\t"
685+
"movq %rsp,%rcx\n\t" /* context */
686+
"movl $1,%edx\n\t" /* alertable */
687+
"call " __ASM_NAME("NtContinue") "\n\t"
688+
"int3" )
679689

680690

681691
/*******************************************************************

dlls/ntdll/tests/exception.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feat
7979
static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask);
8080
static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
8181

82+
static void *pKiUserApcDispatcher;
8283
static void *pKiUserExceptionDispatcher;
8384

8485
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@@ -4930,6 +4931,94 @@ static void test_KiUserExceptionDispatcher(void)
49304931
ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
49314932
}
49324933

4934+
4935+
static BYTE saved_KiUserApcDispatcher[12];
4936+
static BOOL apc_called;
4937+
4938+
static void CALLBACK apc_func( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
4939+
{
4940+
ok( arg1 == 0x1234, "wrong arg1 %Ix\n", arg1 );
4941+
ok( arg2 == 0x5678, "wrong arg2 %Ix\n", arg2 );
4942+
ok( arg3 == 0xdeadbeef, "wrong arg3 %Ix\n", arg3 );
4943+
apc_called = TRUE;
4944+
}
4945+
4946+
static void * WINAPI hook_KiUserApcDispatcher(CONTEXT *context)
4947+
{
4948+
struct machine_frame *frame = (struct machine_frame *)(context + 1);
4949+
UINT i;
4950+
4951+
trace( "context %p, context->Rip %#Ix, context->Rsp %#Ix (%#Ix), ContextFlags %#lx.\n",
4952+
context, context->Rip, context->Rsp,
4953+
(char *)context->Rsp - (char *)context, context->ContextFlags );
4954+
4955+
ok( context->P1Home == 0x1234, "wrong p1 %#Ix\n", context->P1Home );
4956+
ok( context->P2Home == 0x5678, "wrong p2 %#Ix\n", context->P2Home );
4957+
ok( context->P3Home == 0xdeadbeef, "wrong p3 %#Ix\n", context->P3Home );
4958+
ok( context->P4Home == (ULONG_PTR)apc_func, "wrong p4 %#Ix / %p\n", context->P4Home, apc_func );
4959+
4960+
/* machine frame offset varies between Windows versions */
4961+
for (i = 0; i < 16; i++)
4962+
{
4963+
if (frame->rip == context->Rip) break;
4964+
frame = (struct machine_frame *)((ULONG64 *)frame + 2);
4965+
}
4966+
trace( "machine frame %p (%#Ix): rip=%#Ix cs=%#Ix eflags=%#Ix rsp=%#Ix ss=%#Ix\n",
4967+
frame, (char *)frame - (char *)context,
4968+
frame->rip, frame->cs, frame->eflags, frame->rsp, frame->ss );
4969+
ok( frame->rip == context->Rip, "wrong rip %#Ix / %#Ix\n", frame->rip, context->Rip );
4970+
ok( frame->rsp == context->Rsp, "wrong rsp %#Ix / %#Ix\n", frame->rsp, context->Rsp );
4971+
4972+
hook_called = TRUE;
4973+
memcpy( pKiUserApcDispatcher, saved_KiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher));
4974+
return pKiUserApcDispatcher;
4975+
}
4976+
4977+
static void test_KiUserApcDispatcher(void)
4978+
{
4979+
BYTE hook_trampoline[] =
4980+
{
4981+
0x48, 0x89, 0xe1, /* mov %rsp,%rcx */
4982+
0x48, 0xb8, /* movabs hook_KiUserApcDispatcher,%rax */
4983+
0,0,0,0,0,0,0,0, /* offset 5 */
4984+
0xff, 0xd0, /* callq *rax */
4985+
0xff, 0xe0, /* jmpq *rax */
4986+
};
4987+
4988+
BYTE patched_KiUserApcDispatcher[12];
4989+
DWORD old_protect;
4990+
BYTE *ptr;
4991+
BOOL ret;
4992+
4993+
*(ULONG_PTR *)(hook_trampoline + 5) = (ULONG_PTR)hook_KiUserApcDispatcher;
4994+
memcpy(code_mem, hook_trampoline, sizeof(hook_trampoline));
4995+
4996+
ret = VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher),
4997+
PAGE_EXECUTE_READWRITE, &old_protect );
4998+
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
4999+
5000+
memcpy( saved_KiUserApcDispatcher, pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher) );
5001+
ptr = patched_KiUserApcDispatcher;
5002+
/* mov $code_mem, %rax */
5003+
*ptr++ = 0x48;
5004+
*ptr++ = 0xb8;
5005+
*(void **)ptr = code_mem;
5006+
ptr += sizeof(ULONG64);
5007+
/* jmp *rax */
5008+
*ptr++ = 0xff;
5009+
*ptr++ = 0xe0;
5010+
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
5011+
5012+
hook_called = FALSE;
5013+
apc_called = FALSE;
5014+
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234, 0x5678, 0xdeadbeef );
5015+
SleepEx( 0, TRUE );
5016+
ok( apc_called, "APC was not called\n" );
5017+
ok( hook_called, "hook was not called\n" );
5018+
5019+
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
5020+
}
5021+
49335022
static BOOL got_nested_exception, got_prev_frame_exception;
49345023
static void *nested_exception_initial_frame;
49355024

@@ -11476,6 +11565,7 @@ START_TEST(exception)
1147611565
X(RtlGetExtendedFeaturesMask);
1147711566
X(RtlCopyContext);
1147811567
X(RtlCopyExtendedContext);
11568+
X(KiUserApcDispatcher);
1147911569
X(KiUserExceptionDispatcher);
1148011570
#undef X
1148111571

@@ -11637,6 +11727,7 @@ START_TEST(exception)
1163711727
test_dpe_exceptions();
1163811728
test_wow64_context();
1163911729
test_KiUserExceptionDispatcher();
11730+
test_KiUserApcDispatcher();
1164011731
test_nested_exception();
1164111732
test_collided_unwind();
1164211733

dlls/ntdll/unix/signal_x86_64.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,16 @@ C_ASSERT( offsetof(struct exc_stack_layout, rec) == 0x4f0 );
365365
C_ASSERT( offsetof(struct exc_stack_layout, machine_frame) == 0x590 );
366366
C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
367367

368+
/* stack layout when calling KiUserApcDispatcher */
369+
struct apc_stack_layout
370+
{
371+
CONTEXT context; /* 000 */
372+
struct machine_frame machine_frame; /* 4d0 */
373+
ULONG64 align; /* 4f8 */
374+
};
375+
C_ASSERT( offsetof(struct apc_stack_layout, machine_frame) == 0x4d0 );
376+
C_ASSERT( sizeof(struct apc_stack_layout) == 0x500 );
377+
368378
/* flags to control the behavior of the syscall dispatcher */
369379
#define SYSCALL_HAVE_XSAVE 1
370380
#define SYSCALL_HAVE_XSAVEC 2
@@ -373,18 +383,6 @@ C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
373383

374384
static unsigned int syscall_flags;
375385

376-
/* stack layout when calling an user apc function.
377-
* FIXME: match Windows ABI. */
378-
struct apc_stack_layout
379-
{
380-
ULONG64 save_regs[4];
381-
void *func;
382-
ULONG64 align;
383-
CONTEXT context;
384-
ULONG64 rbp;
385-
ULONG64 rip;
386-
};
387-
388386
struct syscall_frame
389387
{
390388
ULONG64 rax; /* 0000 */
@@ -1492,15 +1490,16 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
14921490
NtGetContextThread( GetCurrentThread(), &stack->context );
14931491
stack->context.Rax = status;
14941492
}
1493+
stack->context.P1Home = arg1;
1494+
stack->context.P2Home = arg2;
1495+
stack->context.P3Home = arg3;
1496+
stack->context.P4Home = (ULONG64)func;
1497+
stack->machine_frame.rip = stack->context.Rip;
1498+
stack->machine_frame.rsp = stack->context.Rsp;
14951499
frame->rbp = stack->context.Rbp;
1496-
frame->rsp = (ULONG64)stack - 8;
1500+
frame->rsp = (ULONG64)stack;
14971501
frame->rip = (ULONG64)pKiUserApcDispatcher;
1498-
frame->rcx = (ULONG64)&stack->context;
1499-
frame->rdx = arg1;
1500-
frame->r8 = arg2;
1501-
frame->r9 = arg3;
1502-
stack->func = func;
1503-
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
1502+
frame->restore_flags |= CONTEXT_CONTROL;
15041503
return status;
15051504
}
15061505

0 commit comments

Comments
 (0)