From a83532d8dd5e99226dbccf0398083b052f033b9a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 22 Jan 2018 15:14:56 +0100 Subject: [PATCH] ntdll: Store the context on the thread stack after the initial suspend. The initial stack pointer may have been modified during suspend. Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/process.c | 22 ++++++--- dlls/ntdll/signal_arm.c | 63 +++++++++++++++++++------- dlls/ntdll/signal_i386.c | 84 ++++++++++++++++++++++++----------- dlls/ntdll/signal_x86_64.c | 68 +++++++++++++++++++++------- 4 files changed, 174 insertions(+), 63 deletions(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index b5c8fc529db..59df58a4596 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3059,11 +3059,11 @@ static void test_SuspendProcessNewThread(void) ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); ok(!ret, "IAT entry resolved prematurely\n"); - ctx.ContextFlags = CONTEXT_FULL; + ctx.ContextFlags = CONTEXT_ALL; ret = GetThreadContext( thread_handle, &ctx ); ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() ); + ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); #ifdef __x86_64__ - ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags ); ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr ); @@ -3080,8 +3080,10 @@ static void test_SuspendProcessNewThread(void) ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); + ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); + ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); + ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); #else - ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags ); ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); if (!ctx.Ebp) /* winxp is completely different */ { @@ -3094,6 +3096,9 @@ static void test_SuspendProcessNewThread(void) ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx ); ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); + ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); + ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); + ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); #endif ResumeThread( thread_handle ); @@ -3193,9 +3198,10 @@ static void test_SuspendProcessState(void) ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError()); /* Set up the remote process environment */ - ctx.ContextFlags = CONTEXT_FULL; + ctx.ContextFlags = CONTEXT_ALL; ret = GetThreadContext(pi.hThread, &ctx); ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError()); + ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE); ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError()); @@ -3210,7 +3216,6 @@ static void test_SuspendProcessState(void) ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError()); #ifdef __x86_64__ - ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags ); ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi ); @@ -3225,6 +3230,9 @@ static void test_SuspendProcessState(void) ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); + ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); + ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); + ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); entry_ptr = (void *)ctx.Rcx; peb_ptr = (void *)ctx.Rdx; @@ -3242,7 +3250,6 @@ static void test_SuspendProcessState(void) ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL); ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError()); #else - ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags ); ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); if (!ctx.Ebp) /* winxp is completely different */ { @@ -3253,6 +3260,9 @@ static void test_SuspendProcessState(void) } ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); + ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); + ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); + ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); entry_ptr = (void *)ctx.Eax; peb_ptr = (void *)ctx.Ebx; diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 272fc7b3fd8..355817b0a97 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -1228,24 +1228,17 @@ __ASM_GLOBAL_FUNC( start_thread, /* store exit frame */ "ldr r4, [sp, #40]\n\t" /* teb */ "str sp, [r4, #0x1d4]\n\t" /* teb->SystemReserved2 */ - /* build initial context on thread stack */ - "ldr r4, [r4, #4]\n\t" /* teb->Tib.StackBase */ - "sub r5, r4, #0x1a0\n\t" /* sizeof(CONTEXT) */ - "mov ip, #0x0200000\n\t" /* CONTEXT_ARM */ - "add ip, #0x3\n\t" /* CONTEXT_FULL */ - "str ip, [r5]\n\t" /* context->ContextFlags */ - "str r0, [r5, #0x4]\n\t" /* context->R0 = entry */ - "str r1, [r5, #0x8]\n\t" /* context->R1 = arg */ - "str r4, [r5, #0x38]\n\t" /* context->Sp = stack */ - "str r3, [r5, #0x40]\n\t" /* context->Pc = relay */ /* switch to thread stack */ - "mov sp, r5\n\t" + "ldr r4, [r4, #4]\n\t" /* teb->Tib.StackBase */ + "sub sp, r4, #0x1000\n\t" /* attach dlls */ - "mov r0, r5\n\t" /* context */ - "mov r1, r2\n\t" /* suspend */ - "bl " __ASM_NAME("attach_dlls") "\n\t" + "bl " __ASM_NAME("attach_thread") "\n\t" + "mov sp, r0\n\t" + /* clear the stack */ + "and r0, #~0xff0\n\t" /* round down to page size */ + "bl " __ASM_NAME("virtual_clear_thread_stack") "\n\t" /* switch to the initial context */ - "mov r0, r5\n\t" + "mov r0, sp\n\t" "b " __ASM_NAME("set_cpu_context") ) extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb ); @@ -1258,6 +1251,46 @@ __ASM_GLOBAL_FUNC( call_thread_exit_func, "movne sp, r3\n\t" "blx r1" ) +/*********************************************************************** + * init_thread_context + */ +static void init_thread_context( CONTEXT *context, LPTHREAD_START_ROUTINE entry, void *arg, void *relay ) +{ + context->R0 = (DWORD)entry; + context->R1 = (DWORD)arg; + context->Sp = (DWORD)NtCurrentTeb()->Tib.StackBase; + context->Pc = (DWORD)relay; +} + + +/*********************************************************************** + * attach_thread + */ +PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, + BOOL suspend, void *relay ) +{ + CONTEXT *ctx; + + if (suspend) + { + CONTEXT context = { CONTEXT_ALL }; + + init_thread_context( &context, entry, arg, relay ); + wait_suspend( &context ); + ctx = (CONTEXT *)((ULONG_PTR)context.Sp & ~15) - 1; + *ctx = context; + } + else + { + ctx = (CONTEXT *)NtCurrentTeb()->Tib.StackBase - 1; + init_thread_context( ctx, entry, arg, relay ); + } + ctx->ContextFlags = CONTEXT_FULL; + attach_dlls( ctx, FALSE ); + return ctx; +} + + /*********************************************************************** * signal_start_thread * diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index dcca0f59a39..9bf36c10f11 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -2865,39 +2865,24 @@ __ASM_GLOBAL_FUNC( start_thread, __ASM_CFI(".cfi_rel_offset %edi,-12\n\t") /* store exit frame */ "movl %ebp,%fs:0x1f4\n\t" /* x86_thread_data()->exit_frame */ - /* build initial context on thread stack */ - "movl %fs:4,%eax\n\t" /* NtCurrentTeb()->StackBase */ - "leal -0x2dc(%eax),%esi\n\t" /* sizeof(context) + 16 */ - "movl $0x10007,(%esi)\n\t" /* context->ContextFlags = CONTEXT_FULL */ - "movw %cs,0xbc(%esi)\n\t" /* context->SegCs */ - "movw %ds,0x98(%esi)\n\t" /* context->SegDs */ - "movw %es,0x94(%esi)\n\t" /* context->SegEs */ - "movw %fs,0x90(%esi)\n\t" /* context->SegFs */ - "movw %gs,0x8c(%esi)\n\t" /* context->SegGs */ - "movw %ss,0xc8(%esi)\n\t" /* context->SegSs */ - "movl 8(%ebp),%eax\n\t" - "movl %eax,0xb0(%esi)\n\t" /* context->Eax = entry */ - "movl 12(%ebp),%eax\n\t" - "movl %eax,0xa4(%esi)\n\t" /* context->Ebx = arg */ - "movl 20(%ebp),%eax\n\t" - "movl %eax,0xb8(%esi)\n\t" /* context->Eip = relay */ - "leal 0x2cc(%esi),%eax\n\t" - "movl %eax,0xc4(%esi)\n\t" /* context->Esp */ /* switch to thread stack */ - "leal -12(%esi),%esp\n\t" + "movl %fs:4,%eax\n\t" /* NtCurrentTeb()->StackBase */ + "leal -0x1000(%eax),%esp\n\t" /* attach dlls */ + "pushl 20(%ebp)\n\t" /* relay */ "pushl 16(%ebp)\n\t" /* suspend */ - "pushl %esi\n\t" /* context */ + "pushl 12(%ebp)\n\t" /* arg */ + "pushl 8(%ebp)\n\t" /* entry */ "xorl %ebp,%ebp\n\t" - "call " __ASM_NAME("attach_dlls") "\n\t" - "addl $20,%esp\n\t" + "call " __ASM_NAME("attach_thread") "\n\t" + "movl %eax,%esi\n\t" + "leal -12(%eax),%esp\n\t" /* clear the stack */ - "leal -0xd24(%esi),%eax\n\t" /* round down to page size */ - "pushl %eax\n\t" + "andl $~0xfff,%eax\n\t" /* round down to page size */ + "movl %eax,(%esp)\n\t" "call " __ASM_NAME("virtual_clear_thread_stack") "\n\t" /* switch to the initial context */ "movl %esi,(%esp)\n\t" - "movl $0x10007,(%esi)\n\t" /* context->ContextFlags = CONTEXT_FULL */ "call " __ASM_NAME("set_cpu_context") ) extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int) ); @@ -2967,6 +2952,55 @@ void DECLSPEC_HIDDEN call_thread_func( LPTHREAD_START_ROUTINE entry, void *arg ) } +/*********************************************************************** + * init_thread_context + */ +static void init_thread_context( CONTEXT *context, LPTHREAD_START_ROUTINE entry, void *arg, void *relay ) +{ + context->SegCs = wine_get_cs(); + context->SegDs = wine_get_ds(); + context->SegEs = wine_get_es(); + context->SegFs = wine_get_fs(); + context->SegGs = wine_get_gs(); + context->SegSs = wine_get_ss(); + context->EFlags = 0x202; + context->Eax = (DWORD)entry; + context->Ebx = (DWORD)arg; + context->Esp = (DWORD)NtCurrentTeb()->Tib.StackBase - 16; + context->Eip = (DWORD)relay; + context->FloatSave.ControlWord = 0x27f; + ((XMM_SAVE_AREA32 *)context->ExtendedRegisters)->ControlWord = 0x27f; +} + + +/*********************************************************************** + * attach_thread + */ +PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, + BOOL suspend, void *relay ) +{ + CONTEXT *ctx; + + if (suspend) + { + CONTEXT context = { CONTEXT_ALL }; + + init_thread_context( &context, entry, arg, relay ); + wait_suspend( &context ); + ctx = (CONTEXT *)((ULONG_PTR)context.Esp & ~15) - 1; + *ctx = context; + } + else + { + ctx = (CONTEXT *)((char *)NtCurrentTeb()->Tib.StackBase - 16) - 1; + init_thread_context( ctx, entry, arg, relay ); + } + ctx->ContextFlags = CONTEXT_FULL; + attach_dlls( ctx, FALSE ); + return ctx; +} + + /*********************************************************************** * signal_start_thread * diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 60da3f393c5..946c0f1bcd5 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -4094,26 +4094,15 @@ __ASM_GLOBAL_FUNC( start_thread, /* store exit frame */ "movq %gs:0x30,%rax\n\t" "movq %rsp,0x330(%rax)\n\t" /* amd64_thread_data()->exit_frame */ - /* build initial context on thread stack */ - "movq 8(%rax),%r8\n\t" /* NtCurrentTeb()->Tib.StackBase */ - "leaq -0x500(%r8),%r10\n\t" /* sizeof(context) + 0x30 for function params */ - "movq $0x001000b,0x30(%r10)\n\t" /* context->ContextFlags = CONTEXT_FULL */ - "movw %cs,0x38(%r10)\n\t" /* context->SegCs */ - "movw %ss,0x42(%r10)\n\t" /* context->SegSs */ - "movq %rdi,0x80(%r10)\n\t" /* context->Rcx = entry */ - "movq %rsi,0x88(%r10)\n\t" /* context->Rdx = arg */ - "leaq -0x28(%r8),%rax\n\t" - "movq %rax,0x98(%r10)\n\t" /* context->Rsp */ - "movq %rcx,0xf8(%r10)\n\t" /* context->Rip = relay */ - "fxsave 0x100(%r10)\n\t" /* context->FtlSave */ /* switch to thread stack */ - "movq %r10,%rsp\n\t" + "movq 8(%rax),%rax\n\t" /* NtCurrentTeb()->Tib.StackBase */ + "leaq -0x1000(%rax),%rsp\n\t" /* attach dlls */ - "movq %r10,%rdi\n\t" /* context */ - "movq %rdx,%rsi\n\t" /* suspend */ - "call " __ASM_NAME("attach_dlls") "\n\t" + "call " __ASM_NAME("attach_thread") "\n\t" + "movq %rax,%rsp\n\t" /* clear the stack */ - "leaq -0xb00(%rsp),%rdi\n\t" /* round down to page size */ + "andq $~0xfff,%rax\n\t" /* round down to page size */ + "movq %rax,%rdi\n\t" "call " __ASM_NAME("virtual_clear_thread_stack") "\n\t" /* switch to the initial context */ "movq %rsp,%rdi\n\t" @@ -4140,6 +4129,51 @@ __ASM_GLOBAL_FUNC( call_thread_exit_func, "call *%rsi" ) +/*********************************************************************** + * init_thread_context + */ +static void init_thread_context( CONTEXT *context, LPTHREAD_START_ROUTINE entry, void *arg, void *relay ) +{ + __asm__( "movw %%cs,%0" : "=m" (context->SegCs) ); + __asm__( "movw %%ss,%0" : "=m" (context->SegSs) ); + __asm__( "fxsave %0" : "=m" (context->u.FltSave) ); + context->Rcx = (ULONG_PTR)entry; + context->Rdx = (ULONG_PTR)arg; + context->Rsp = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase - 0x28; + context->Rip = (ULONG_PTR)relay; + context->EFlags = 0x200; +} + + +/*********************************************************************** + * attach_thread + */ +PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, + BOOL suspend, void *relay ) +{ + CONTEXT *ctx; + + if (suspend) + { + CONTEXT context = { 0 }; + + context.ContextFlags = CONTEXT_ALL; + init_thread_context( &context, entry, arg, relay ); + wait_suspend( &context ); + ctx = (CONTEXT *)((ULONG_PTR)context.Rsp & ~15) - 1; + *ctx = context; + } + else + { + ctx = (CONTEXT *)((char *)NtCurrentTeb()->Tib.StackBase - 0x30) - 1; + init_thread_context( ctx, entry, arg, relay ); + } + ctx->ContextFlags = CONTEXT_FULL; + attach_dlls( ctx, FALSE ); + return ctx; +} + + /*********************************************************************** * signal_start_thread *