This flag seems to have always been supported. Unlike BYPASS_PROCESS_FREEZE
From: Billy Laws blaws05@gmail.com
--- dlls/ntdll/tests/Makefile.in | 2 + dlls/ntdll/tests/testdll.c | 40 ++++++++++++++++ dlls/ntdll/tests/testdll.spec | 2 + dlls/ntdll/tests/thread.c | 86 +++++++++++++++++++++++++++++++++++ include/winternl.h | 66 +++++++++++++++++++++++++-- 5 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 dlls/ntdll/tests/testdll.c create mode 100644 dlls/ntdll/tests/testdll.spec
diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in index 3742968c415..04657aee627 100644 --- a/dlls/ntdll/tests/Makefile.in +++ b/dlls/ntdll/tests/Makefile.in @@ -23,6 +23,8 @@ SOURCES = \ string.c \ sync.c \ thread.c \ + testdll.c \ + testdll.spec \ threadpool.c \ time.c \ unwind.c \ diff --git a/dlls/ntdll/tests/testdll.c b/dlls/ntdll/tests/testdll.c new file mode 100644 index 00000000000..7be1c9f84c7 --- /dev/null +++ b/dlls/ntdll/tests/testdll.c @@ -0,0 +1,40 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#if 0 +#pragma makedep testdll +#endif + +#include <windows.h> + +BOOL seen_thread_attach; +BOOL seen_thread_detach; + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_THREAD_ATTACH: + seen_thread_attach = TRUE; + break; + case DLL_THREAD_DETACH: + seen_thread_detach = TRUE; + break; + } + + return TRUE; +} diff --git a/dlls/ntdll/tests/testdll.spec b/dlls/ntdll/tests/testdll.spec new file mode 100644 index 00000000000..75feb73a990 --- /dev/null +++ b/dlls/ntdll/tests/testdll.spec @@ -0,0 +1,2 @@ +@ extern seen_thread_attach +@ extern seen_thread_detach diff --git a/dlls/ntdll/tests/thread.c b/dlls/ntdll/tests/thread.c index 4941b791bcd..926e3b0bc8c 100644 --- a/dlls/ntdll/tests/thread.c +++ b/dlls/ntdll/tests/thread.c @@ -356,6 +356,91 @@ static void test_NtQueueApcThreadEx(void) SleepEx( 0, TRUE ); }
+static void extract_resource(const char *name, const char *type, const char *path) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", path, GetLastError()); + + res = FindResourceA(NULL, name, type); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +struct skip_thread_attach_args +{ + BOOL teb_flag; + PVOID teb_tls_pointer; + PVOID teb_fls_slots; +}; + +static void CALLBACK test_skip_thread_attach_proc(void *param) +{ + struct skip_thread_attach_args *args = param; + args->teb_flag = NtCurrentTeb()->SkipThreadAttach; + args->teb_tls_pointer = NtCurrentTeb()->ThreadLocalStoragePointer; + args->teb_fls_slots = NtCurrentTeb()->FlsSlots; +} + +static void test_skip_thread_attach(void) +{ + BOOL *seen_thread_attach, *seen_thread_detach; + struct skip_thread_attach_args args; + HANDLE thread; + NTSTATUS status; + char path_dll_local[MAX_PATH + 11]; + char path_tmp[MAX_PATH]; + HMODULE module; + + if (!pNtCreateThreadEx) + { + win_skip( "NtCreateThreadEx is not available.\n" ); + return; + } + + GetTempPathA(sizeof(path_tmp), path_tmp); + + sprintf(path_dll_local, "%s%s", path_tmp, "testdll.dll"); + extract_resource("testdll.dll", "TESTDLL", path_dll_local); + + module = LoadLibraryA(path_dll_local); + if (!module) { + trace("Could not load testdll.\n"); + goto delete; + } + + seen_thread_attach = (BOOL *)GetProcAddress(module, "seen_thread_attach"); + seen_thread_detach = (BOOL *)GetProcAddress(module, "seen_thread_detach"); + + ok( !*seen_thread_attach, "Unexpected\n" ); + ok( !*seen_thread_detach, "Unexpected\n" ); + + status = pNtCreateThreadEx( &thread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_skip_thread_attach_proc, + &args, THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH, 0, 0, 0, NULL ); + todo_wine ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status ); + + WaitForSingleObject( thread, INFINITE ); + + CloseHandle( thread ); + + todo_wine ok( !*seen_thread_attach, "Unexpected\n" ); + todo_wine ok( !*seen_thread_detach, "Unexpected\n" ); + todo_wine ok( args.teb_flag, "Unexpected\n" ); + todo_wine ok( !args.teb_tls_pointer, "Unexpected\n" ); + todo_wine ok( !args.teb_fls_slots, "Unexpected\n" ); + + FreeLibrary(module); +delete: + DeleteFileA(path_dll_local); +} + START_TEST(thread) { init_function_pointers(); @@ -378,4 +463,5 @@ START_TEST(thread) test_NtCreateUserProcess(); test_thread_bypass_process_freeze(); test_NtQueueApcThreadEx(); + test_skip_thread_attach(); } diff --git a/include/winternl.h b/include/winternl.h index 64e82b20eca..52d4703145c 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -610,7 +610,27 @@ typedef struct _TEB PVOID MergedPrefLanguages; /* fc0/17e0 */ ULONG MuiImpersonation; /* fc4/17e8 */ USHORT CrossTebFlags; /* fc8/17ec */ - USHORT SameTebFlags; /* fca/17ee */ + union { + USHORT SameTebFlags; /* fca/17ee */ + struct { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SkipFileAPIBrokering : 1; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME1; PVOID TxnScopeEnterCallback; /* fcc/17f0 */ PVOID TxnScopeExitCallback; /* fd0/17f8 */ PVOID TxnScopeContext; /* fd4/1800 */ @@ -1143,7 +1163,27 @@ typedef struct _TEB32 ULONG MergedPrefLanguages; /* 0fc0 */ ULONG MuiImpersonation; /* 0fc4 */ USHORT CrossTebFlags; /* 0fc8 */ - USHORT SameTebFlags; /* 0fca */ + union { + USHORT SameTebFlags; /* 0fca */ + struct { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SkipFileAPIBrokering : 1; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME1; ULONG TxnScopeEnterCallback; /* 0fcc */ ULONG TxnScopeExitCallback; /* 0fd0 */ ULONG TxnScopeContext; /* 0fd4 */ @@ -1249,7 +1289,27 @@ typedef struct _TEB64 ULONG64 MergedPrefLanguages; /* 17e0 */ ULONG MuiImpersonation; /* 17e8 */ USHORT CrossTebFlags; /* 17ec */ - USHORT SameTebFlags; /* 17ee */ + union { + USHORT SameTebFlags; /* 17ee */ + struct { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SkipFileAPIBrokering : 1; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME1; ULONG64 TxnScopeEnterCallback; /* 17f0 */ ULONG64 TxnScopeExitCallback; /* 17f8 */ ULONG64 TxnScopeContext; /* 1800 */
From: Billy Laws blaws05@gmail.com
--- dlls/ntdll/loader.c | 13 +++++++++++++ dlls/ntdll/tests/thread.c | 12 ++++++------ dlls/ntdll/unix/thread.c | 11 +++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 6b089c990b5..8ef5f69b9ca 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3909,6 +3909,12 @@ void WINAPI LdrShutdownThread(void) /* don't do any detach calls if process is exiting */ if (process_detaching) return;
+ if (NtCurrentTeb()->SkipThreadAttach) + { + heap_thread_detach(); + return; + } + RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
RtlEnterCriticalSection( &loader_section ); @@ -4474,6 +4480,13 @@ void loader_init( CONTEXT *context, void **entry ) #ifdef __arm64ec__ arm64ec_thread_init(); #endif + + if (NtCurrentTeb()->SkipThreadAttach) + { + RtlLeaveCriticalSection( &loader_section ); + return; + } + wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress ); }
diff --git a/dlls/ntdll/tests/thread.c b/dlls/ntdll/tests/thread.c index 926e3b0bc8c..9fd23809488 100644 --- a/dlls/ntdll/tests/thread.c +++ b/dlls/ntdll/tests/thread.c @@ -424,17 +424,17 @@ static void test_skip_thread_attach(void)
status = pNtCreateThreadEx( &thread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_skip_thread_attach_proc, &args, THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH, 0, 0, 0, NULL ); - todo_wine ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status ); + ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
WaitForSingleObject( thread, INFINITE );
CloseHandle( thread );
- todo_wine ok( !*seen_thread_attach, "Unexpected\n" ); - todo_wine ok( !*seen_thread_detach, "Unexpected\n" ); - todo_wine ok( args.teb_flag, "Unexpected\n" ); - todo_wine ok( !args.teb_tls_pointer, "Unexpected\n" ); - todo_wine ok( !args.teb_fls_slots, "Unexpected\n" ); + ok( !*seen_thread_attach, "Unexpected\n" ); + ok( !*seen_thread_detach, "Unexpected\n" ); + ok( args.teb_flag, "Unexpected\n" ); + ok( !args.teb_tls_pointer, "Unexpected\n" ); + ok( !args.teb_fls_slots, "Unexpected\n" );
FreeLibrary(module); delete: diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 6c1ea2d0a00..d9907ba14cc 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1315,8 +1315,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit, SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list ) { - static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER | - THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE; + static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH | + THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER | THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE; sigset_t sigset; pthread_t pthread_id; pthread_attr_t pthread_attr; @@ -1326,6 +1326,7 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT DWORD tid = 0; int request_pipe[2]; TEB *teb; + WOW_TEB *wow_teb; unsigned int status;
if (flags & ~supported_flags) @@ -1411,6 +1412,12 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
set_thread_id( teb, GetCurrentProcessId(), tid );
+ teb->SkipThreadAttach = !!(flags & THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH); + wow_teb = get_wow_teb( teb ); + if (wow_teb) { + wow_teb->SkipThreadAttach = teb->SkipThreadAttach; + } + thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; thread_data->request_fd = request_pipe[1]; thread_data->start = start;