-- v3: ntdll: Filter EFlags from user-supplied CONTEXT on x86 and x64. ntdll/tests: Test for setting x86 / x64 EFLAGS register in context.
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/tests/exception.c | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 820e435bc1b..73383a09f17 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -10673,6 +10673,95 @@ static void test_copy_context(void) dst_xs->Mask == 4, sizeof(dst_xs->YmmContext)); } } + +static DWORD WINAPI signal_and_wait_proc( void *arg ) +{ + HANDLE *events = arg; + /* Signal event and block thread without returning to userspace. */ + return SignalObjectAndWait(events[0], events[1], INFINITE, FALSE); +} + +static void test_eflags_sanitization(void) +{ + DWORD min_eflags, max_eflags, max_eflags_broken; + HANDLE event_in, event_out; + HANDLE thread; + HANDLE thread_args[2]; + HANDLE waits[2]; + NTSTATUS status; + CONTEXT context; + DWORD result, old_eflags; + int i; + +#if defined(__x86_64__) + min_eflags = 0x00000200; + max_eflags = 0x00210fd5; + max_eflags_broken = max_eflags; +#elif defined(__i386__) + min_eflags = is_wow64 ? 0x00000202 : 0x00000200; + max_eflags = is_wow64 ? 0x003f0fd7 : 0x003f4fd7; + max_eflags_broken = max_eflags & ~((DWORD)!is_wow64 << 17); +#endif + + event_in = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(event_in != NULL, "CreateEventW failed with %#lx\n", GetLastError()); + event_out = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(event_out != NULL, "CreateEventW failed with %#lx\n", GetLastError()); + + thread_args[0] = event_in; + thread_args[1] = event_out; + thread = CreateThread(NULL, 0, signal_and_wait_proc, thread_args, CREATE_SUSPENDED, NULL); + ok(thread != NULL, "CreateThread failed with %#lx.\n", GetLastError()); + + for (i = 0; ; i++) + { + context.ContextFlags = CONTEXT_CONTROL; + status = pNtGetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %lx\n", status); + old_eflags = context.EFlags; + + context.EFlags = 0; + status = pNtSetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", status); + status = pNtGetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %lx\n", status); + todo_wine + ok(context.EFlags == min_eflags, "Expected EFlags to be %#lx, got %#lx\n", min_eflags, context.EFlags); + + context.EFlags = -1; + status = pNtSetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", status); + status = pNtGetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %lx\n", status); + todo_wine + ok(context.EFlags == max_eflags || broken(context.EFlags == max_eflags_broken), + "Expected EFlags to be %#lx, got %#lx\n", max_eflags, context.EFlags); + + context.EFlags = old_eflags; + status = pNtSetContextThread(thread, &context); + ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", status); + + if (i == 1) break; + + ResumeThread(thread); + waits[0] = event_in; + waits[1] = thread; + result = WaitForMultipleObjects(2, waits, FALSE, INFINITE); + ok(result == WAIT_OBJECT_0, "Expected WAIT_OBJECT_0, got %#lx\n", result); + } + + ok(SetEvent(event_out), "SetEvent failed: %#lx\n", GetLastError()); + + result = WaitForSingleObject(thread, INFINITE); + ok(result == WAIT_OBJECT_0, "Expected WAIT_OBJECT_0, got %#lx\n", result); + + ok(GetExitCodeThread(thread, &result), "Failed to get thread exit code: %#lx\n", GetLastError()); + ok(result == WAIT_OBJECT_0, "Expected WAIT_OBJECT_0, got %#lx\n", result); + + CloseHandle(thread); + CloseHandle(event_in); + CloseHandle(event_out); +} #endif
START_TEST(exception) @@ -10847,6 +10936,7 @@ START_TEST(exception) test_kiuserexceptiondispatcher(); test_extended_context(); test_copy_context(); + test_eflags_sanitization();
#elif defined(__x86_64__)
@@ -10891,6 +10981,7 @@ START_TEST(exception) test_copy_context(); test_unwind_from_apc(); test_syscall_clobbered_regs(); + test_eflags_sanitization();
#elif defined(__aarch64__)
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/tests/exception.c | 2 -- dlls/ntdll/unix/signal_i386.c | 2 +- dlls/ntdll/unix/signal_x86_64.c | 4 ++-- dlls/ntdll/unix/thread.c | 20 +++++++++++++++++++- dlls/ntdll/unix/unix_private.h | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 73383a09f17..5101839230b 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -10725,7 +10725,6 @@ static void test_eflags_sanitization(void) ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", status); status = pNtGetContextThread(thread, &context); ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %lx\n", status); - todo_wine ok(context.EFlags == min_eflags, "Expected EFlags to be %#lx, got %#lx\n", min_eflags, context.EFlags);
context.EFlags = -1; @@ -10733,7 +10732,6 @@ static void test_eflags_sanitization(void) ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", status); status = pNtGetContextThread(thread, &context); ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %lx\n", status); - todo_wine ok(context.EFlags == max_eflags || broken(context.EFlags == max_eflags_broken), "Expected EFlags to be %#lx, got %#lx\n", max_eflags, context.EFlags);
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 7be0c39c424..9be0769904d 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -941,7 +941,7 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) frame->esp = context->Esp; frame->ebp = context->Ebp; frame->eip = context->Eip; - frame->eflags = context->EFlags; + frame->eflags = arch_flags_reg_from_user( context->EFlags, IMAGE_FILE_MACHINE_I386 ); frame->cs = context->SegCs; frame->ss = context->SegSs; } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 6c87e347eac..c4f67a16cc9 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1788,7 +1788,7 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) frame->rsp = context->Rsp; frame->rbp = context->Rbp; frame->rip = context->Rip; - frame->eflags = context->EFlags; + frame->eflags = arch_flags_reg_from_user( context->EFlags, IMAGE_FILE_MACHINE_AMD64 ); frame->cs = context->SegCs; frame->ss = context->SegSs; } @@ -2002,7 +2002,7 @@ NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size ) wow_frame->Esp = context->Esp; wow_frame->Ebp = context->Ebp; wow_frame->Eip = context->Eip; - wow_frame->EFlags = context->EFlags; + wow_frame->EFlags = arch_flags_reg_from_user( context->EFlags, IMAGE_FILE_MACHINE_I386 ); wow_frame->SegCs = cs32_sel; wow_frame->SegSs = ds64_sel; cpu->Flags |= WOW64_CPURESERVED_FLAG_RESET_STATE; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index ad47a5fce74..e0d44bb4a38 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1663,13 +1663,31 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1 NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine ) { context_t server_contexts[2]; - unsigned int count = 0; + unsigned int count = 0, i; NTSTATUS ret;
context_to_server( &server_contexts[count++], native_machine, context, machine ); if (machine != native_machine) context_to_server( &server_contexts[count++], machine, context, machine );
+ for (i = 0; i < count; i++) + { + unsigned int *flags_ptr; + if (!(server_contexts[i].flags & SERVER_CTX_CONTROL)) continue; + switch (server_contexts[i].machine) + { + case IMAGE_FILE_MACHINE_I386: + flags_ptr = &server_contexts[i].ctl.i386_regs.eflags; + break; + case IMAGE_FILE_MACHINE_AMD64: + flags_ptr = &server_contexts[i].ctl.x86_64_regs.flags; + break; + default: + continue; + } + *flags_ptr = arch_flags_reg_from_user( *flags_ptr, machine ); + } + SERVER_START_REQ( set_thread_context ) { req->handle = wine_server_obj_handle( handle ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 795fc148479..4160f731563 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -458,4 +458,21 @@ static inline NTSTATUS map_section( HANDLE mapping, void **ptr, SIZE_T *size, UL 0, NULL, size, ViewShare, 0, protect ); }
+static inline DWORD arch_flags_reg_from_user( DWORD flags, USHORT machine ) +{ + switch (machine) + { + case IMAGE_FILE_MACHINE_I386: + if (machine == native_machine) + { + return (flags & 0x003f4fd7) | 0x00000200; + } + return (flags & 0x003f0fd7) | 0x00000202; + case IMAGE_FILE_MACHINE_AMD64: + return (flags & 0x00210fd5) | 0x00000200; + default: + return flags; + } +} + #endif /* __NTDLL_UNIX_PRIVATE_H */
Clarified the "atomic" wording in the comment that explains the rationale for SignalObjectAndWait.