[PATCH 0/1] MR11027: ntdll: Properly set NT_TIB FiberData
Applications may inline the IsThreadAFiber function which checks wether the FiberData field is the constant 0x1E00. Since Wine didn't set it to this value, applications would think the thread is a fiber and attempt to dereference the value, causing a segfault. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59296 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11027
From: Rose Hellsing <rose@pinkro.se> Applications may inline the IsThreadAFiber functions which check wether the FiberData field is the constant 0x1E00. Since Wine didn't set it to this value, applications would think the thread is a fiber and attempt to dereference the value, causing a segfault. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59296 --- dlls/kernel32/tests/fiber.c | 28 ++++++++++++++++++++++++++++ dlls/kernelbase/thread.c | 9 +++++---- dlls/ntdll/unix/virtual.c | 6 ++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index 9d730b3e65e..852b45974e9 100644 --- a/dlls/kernel32/tests/fiber.c +++ b/dlls/kernel32/tests/fiber.c @@ -180,6 +180,33 @@ static void test_ConvertFiberToThread(void) } } +/* Windows initialises NT_TIB.FiberData to 0x1E00 for non-fiber threads. + * Some applications inline IsThreadAFiber and dereference FiberData + * when it differs from this sentinel, so the value must match Windows exactly. + */ +static DWORD WINAPI fiberdata_sentinel_thread(void *arg) +{ + return (DWORD)(ULONG_PTR)NtCurrentTeb()->Tib.FiberData; +} + +static void test_FiberDataSentinel(void) +{ + HANDLE thread; + DWORD exit_code; + + ok(NtCurrentTeb()->Tib.FiberData == (void *)0x1E00, + "Tib.FiberData on main thread is %p, expected 0x1E00\n", + NtCurrentTeb()->Tib.FiberData); + + thread = CreateThread(NULL, 0, fiberdata_sentinel_thread, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed with error %lu\n", GetLastError()); + WaitForSingleObject(thread, INFINITE); + GetExitCodeThread(thread, &exit_code); + ok(exit_code == 0x1E00, + "Tib.FiberData on fresh thread is %#lx, expected 0x1E00\n", exit_code); + CloseHandle(thread); +} + static void test_FiberHandling(void) { fiberCount = 0; @@ -1086,6 +1113,7 @@ START_TEST(fiber) return; } + test_FiberDataSentinel(); test_FiberHandling(); test_FiberLocalStorage(); test_FiberLocalStorageCallback(FiberLocalStorageProc); diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index 13040915817..96042886c50 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -1151,10 +1151,10 @@ BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void) { struct fiber_data *fiber = NtCurrentTeb()->Tib.FiberData; - if (fiber) + if (fiber && fiber != (void *)0x1E00) { relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack ); - NtCurrentTeb()->Tib.FiberData = NULL; + NtCurrentTeb()->Tib.FiberData = (void *)0x1E00; HeapFree( GetProcessHeap(), 0, fiber ); } return TRUE; @@ -1177,7 +1177,7 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag { struct fiber_data *fiber; - if (NtCurrentTeb()->Tib.FiberData) + if (NtCurrentTeb()->Tib.FiberData && NtCurrentTeb()->Tib.FiberData != (void *)0x1E00) { SetLastError( ERROR_ALREADY_FIBER ); return NULL; @@ -1228,7 +1228,8 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) */ BOOL WINAPI DECLSPEC_HOTPATCH IsThreadAFiber(void) { - return NtCurrentTeb()->Tib.FiberData != NULL; + void *fiber = NtCurrentTeb()->Tib.FiberData; + return fiber != NULL && fiber != (void *)0x1E00; } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a2ea5244b9f..a00023954e0 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4001,6 +4001,9 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb32->Peb = PtrToUlong( (char *)peb + page_size ); teb32->Tib.Self = PtrToUlong( teb32 ); teb32->Tib.ExceptionList = ~0u; + + /* non-fiber thread, needs to be set for some applications */ + teb32->Tib.FiberData = 0x1E00; teb32->ActivationContextStackPointer = PtrToUlong( &teb32->ActivationContextStack ); teb32->ActivationContextStack.FrameListCache.Flink = teb32->ActivationContextStack.FrameListCache.Blink = @@ -4013,9 +4016,11 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) #else teb = (TEB *)teb32; teb32->Tib.ExceptionList = ~0u; + teb32->Tib.FiberData = 0x1E00; teb64->Peb = PtrToUlong( (char *)peb - page_size ); teb64->Tib.Self = PtrToUlong( teb64 ); teb64->Tib.ExceptionList = PtrToUlong( teb32 ); + teb64->Tib.FiberData = 0x1E00; teb64->ActivationContextStackPointer = PtrToUlong( &teb64->ActivationContextStack ); teb64->ActivationContextStack.FrameListCache.Flink = teb64->ActivationContextStack.FrameListCache.Blink = @@ -4032,6 +4037,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->Peb = peb; teb->Tib.Self = &teb->Tib; teb->Tib.StackBase = (void *)~0ul; + teb->Tib.FiberData = (void *)0x1E00; teb->ActivationContextStackPointer = &teb->ActivationContextStack; InitializeListHead( &teb->ActivationContextStack.FrameListCache ); teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11027
participants (2)
-
Rose Hellsing -
Rose Hellsing (@axtlos)