Skip to content

Commit 23043ce

Browse files
win32ssDarkFire01
andauthored
[NTDLL:LDR] Add Implicit Thread Local Storage Support (reactos#7594)
Before Windows Vista, TLS directories were ignored by Ldr* in any module loaded after process creation, which meant that the TLS index in any delay-loaded module remained 0. This means that when running an application targeting Vista and above and its delay-load modules have TLS directories, the following events can happen: One or more delay-load modules claim ThreadLocalStoragePointer idx 0, resulting in data corruption and possible buffer overflows as data intended for one of the immediate-load modules is overwritten. None of the immediate-load modules has a TLS directory, so ThreadLocalStoragePointer is not initialized. This means that the program crashes when one of the delay-load modules attempts to access its TLS data. Adding implicit TLS support improves support for NT 6.x/10 user-mode applications, including all contemporary major web browsers. JIRA issue: CORE-19413 --------- Co-authored-by: Justin Miller <justin.miller@reactos.org>
1 parent 97cc325 commit 23043ce

10 files changed

Lines changed: 426 additions & 33 deletions

File tree

dll/ntdll/include/ntdllp.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ typedef struct _LDRP_TLS_DATA
2929
IMAGE_TLS_DIRECTORY TlsDirectory;
3030
} LDRP_TLS_DATA, *PLDRP_TLS_DATA;
3131

32+
typedef struct _LDRP_OLD_TLS_VECTOR_ENTRY
33+
{
34+
LIST_ENTRY TlsVectorLinks;
35+
PVOID* OldTlsVector;
36+
} LDRP_OLD_TLS_VECTOR_ENTRY, *PLDRP_OLD_TLS_VECTOR_ENTRY;
37+
38+
typedef struct _LDRP_TEB_LIST_ENTRY
39+
{
40+
LIST_ENTRY TebLinks;
41+
PTEB Teb;
42+
} LDRP_TEB_LIST_ENTRY, *PLDRP_TEB_LIST_ENTRY;
43+
3244
typedef
3345
NTSTATUS
3446
(NTAPI* PLDR_APP_COMPAT_DLL_REDIRECTION_CALLBACK_FUNCTION)(
@@ -71,7 +83,7 @@ extern PVOID g_pfnSE_ProcessDying;
7183
NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL);
7284
VOID NTAPI LdrpInitializeThread(IN PCONTEXT Context);
7385
NTSTATUS NTAPI LdrpInitializeTls(VOID);
74-
NTSTATUS NTAPI LdrpAllocateTls(VOID);
86+
NTSTATUS NTAPI LdrpAllocateTls(_In_ PTEB Teb);
7587
VOID NTAPI LdrpFreeTls(VOID);
7688
VOID NTAPI LdrpCallTlsInitializers(IN PLDR_DATA_TABLE_ENTRY LdrEntry, IN ULONG Reason);
7789
BOOLEAN NTAPI LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint, IN PVOID BaseAddress, IN ULONG Reason, IN PVOID Context);

dll/ntdll/ldr/ldrinit.c

Lines changed: 153 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ RTL_BITMAP TlsExpansionBitMap;
5151
RTL_BITMAP FlsBitMap;
5252
BOOLEAN LdrpImageHasTls;
5353
LIST_ENTRY LdrpTlsList;
54+
LIST_ENTRY LdrpActiveTebList;
5455
ULONG LdrpNumberOfTlsEntries;
5556
ULONG LdrpNumberOfProcessors;
5657
PVOID NtDllBase;
@@ -509,6 +510,8 @@ NTAPI
509510
LdrpInitializeThread(IN PCONTEXT Context)
510511
{
511512
PPEB Peb = NtCurrentPeb();
513+
PTEB Teb = NtCurrentTeb();
514+
PLDRP_TEB_LIST_ENTRY TebEntry;
512515
PLDR_DATA_TABLE_ENTRY LdrEntry;
513516
PLIST_ENTRY NextEntry, ListHead;
514517
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
@@ -535,7 +538,13 @@ LdrpInitializeThread(IN PCONTEXT Context)
535538
if (LdrpShutdownInProgress) goto Exit;
536539

537540
/* Allocate TLS */
538-
LdrpAllocateTls();
541+
LdrpAllocateTls(Teb);
542+
543+
/* Add thread to active TEB list */
544+
ListHead = &LdrpActiveTebList;
545+
TebEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*TebEntry));
546+
TebEntry->Teb = NtCurrentTeb();
547+
InsertTailList(&LdrpActiveTebList, &TebEntry->TebLinks);
539548

540549
/* Start at the beginning */
541550
ListHead = &Peb->Ldr->InMemoryOrderModuleList;
@@ -1094,6 +1103,7 @@ LdrShutdownThread(VOID)
10941103
{
10951104
PPEB Peb = NtCurrentPeb();
10961105
PTEB Teb = NtCurrentTeb();
1106+
PLDRP_TEB_LIST_ENTRY TebEntry;
10971107
PLDR_DATA_TABLE_ENTRY LdrEntry;
10981108
PLIST_ENTRY NextEntry, ListHead;
10991109
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
@@ -1112,6 +1122,20 @@ LdrShutdownThread(VOID)
11121122
/* Get the Ldr Lock */
11131123
RtlEnterCriticalSection(&LdrpLoaderLock);
11141124

1125+
/* Remove the thread from the active TEB list */
1126+
ListHead = &LdrpActiveTebList;
1127+
for (NextEntry = ListHead->Blink;
1128+
NextEntry != ListHead;
1129+
NextEntry = NextEntry->Blink)
1130+
{
1131+
TebEntry = CONTAINING_RECORD(NextEntry, LDRP_TEB_LIST_ENTRY, TebLinks);
1132+
if (TebEntry->Teb == Teb)
1133+
{
1134+
RemoveEntryList(NextEntry);
1135+
break;
1136+
}
1137+
}
1138+
11151139
/* Start at the end */
11161140
ListHead = &Peb->Ldr->InInitializationOrderModuleList;
11171141
NextEntry = ListHead->Blink;
@@ -1270,12 +1294,16 @@ LdrpInitializeTls(VOID)
12701294
{
12711295
PLIST_ENTRY NextEntry, ListHead;
12721296
PLDR_DATA_TABLE_ENTRY LdrEntry;
1297+
PLDRP_TEB_LIST_ENTRY TebEntry;
12731298
PIMAGE_TLS_DIRECTORY TlsDirectory;
12741299
PLDRP_TLS_DATA TlsData;
12751300
ULONG Size;
1301+
NTSTATUS Status;
1302+
BOOLEAN AllocateTls = FALSE;
12761303

12771304
/* Initialize the TLS List */
1278-
InitializeListHead(&LdrpTlsList);
1305+
if (!LdrpImageHasTls)
1306+
InitializeListHead(&LdrpTlsList);
12791307

12801308
/* Loop all the modules */
12811309
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
@@ -1295,8 +1323,12 @@ LdrpInitializeTls(VOID)
12951323
/* Check if we have a directory */
12961324
if (!TlsDirectory) continue;
12971325

1326+
if (LdrEntry->Flags & LDRP_TLS_LOADED)
1327+
continue;
1328+
12981329
/* Check if the image has TLS */
12991330
if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1331+
AllocateTls = TRUE;
13001332

13011333
/* Show debug message */
13021334
if (ShowSnaps)
@@ -1313,6 +1345,7 @@ LdrpInitializeTls(VOID)
13131345
/* Lock the DLL and mark it for TLS Usage */
13141346
LdrEntry->LoadCount = -1;
13151347
LdrEntry->TlsIndex = -1;
1348+
LdrEntry->Flags |= LDRP_TLS_LOADED;
13161349

13171350
/* Save the cached TLS data */
13181351
TlsData->TlsDirectory = *TlsDirectory;
@@ -1324,29 +1357,57 @@ LdrpInitializeTls(VOID)
13241357
}
13251358

13261359
/* Done setting up TLS, allocate entries */
1327-
return LdrpAllocateTls();
1360+
if (AllocateTls)
1361+
{
1362+
Status = LdrpAllocateTls(NtCurrentTeb());
1363+
if (Status != STATUS_SUCCESS)
1364+
return Status;
1365+
1366+
ListHead = &LdrpActiveTebList;
1367+
NextEntry = ListHead->Blink;
1368+
1369+
for (NextEntry = ListHead->Blink;
1370+
NextEntry != ListHead;
1371+
NextEntry = NextEntry->Blink)
1372+
{
1373+
TebEntry = CONTAINING_RECORD(NextEntry, LDRP_TEB_LIST_ENTRY, TebLinks);
1374+
if (TebEntry->Teb != NtCurrentTeb())
1375+
{
1376+
Status = LdrpAllocateTls(TebEntry->Teb);
1377+
if (Status != STATUS_SUCCESS)
1378+
return Status;
1379+
}
1380+
}
1381+
}
1382+
1383+
return STATUS_SUCCESS;
13281384
}
13291385

13301386
NTSTATUS
13311387
NTAPI
1332-
LdrpAllocateTls(VOID)
1388+
LdrpAllocateTls(_In_ PTEB Teb)
13331389
{
1334-
PTEB Teb = NtCurrentTeb();
13351390
PLIST_ENTRY NextEntry, ListHead;
13361391
PLDRP_TLS_DATA TlsData;
13371392
SIZE_T TlsDataSize;
13381393
PVOID *TlsVector;
1394+
PVOID *OldTlsVector;
1395+
PLDRP_OLD_TLS_VECTOR_ENTRY OldTlsVectorEntry;
13391396

13401397
/* Check if we have any entries */
13411398
if (!LdrpNumberOfTlsEntries)
13421399
return STATUS_SUCCESS;
1400+
/* Check if there are new entries to add to the vector */
1401+
if (LdrpNumberOfTlsEntries == Teb->UserReserved.ThreadNumberOfTlsEntries)
1402+
return STATUS_SUCCESS;
13431403

13441404
/* Allocate the vector array */
13451405
TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1346-
0,
1347-
LdrpNumberOfTlsEntries * sizeof(PVOID));
1406+
0,
1407+
LdrpNumberOfTlsEntries * sizeof(PVOID));
13481408
if (!TlsVector) return STATUS_NO_MEMORY;
1349-
Teb->ThreadLocalStoragePointer = TlsVector;
1409+
/* Grab old TLS vector to retrieve existing values */
1410+
OldTlsVector = Teb->ThreadLocalStoragePointer;
13501411

13511412
/* Loop the TLS Array */
13521413
ListHead = &LdrpTlsList;
@@ -1360,32 +1421,74 @@ LdrpAllocateTls(VOID)
13601421
/* Allocate this vector */
13611422
TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
13621423
TlsData->TlsDirectory.StartAddressOfRawData;
1363-
TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1364-
0,
1365-
TlsDataSize);
1366-
if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1424+
1425+
if (!OldTlsVector || ((TlsData->TlsDirectory.Characteristics + 1) > Teb->UserReserved.ThreadNumberOfTlsEntries))
13671426
{
1368-
/* Out of memory */
1369-
return STATUS_NO_MEMORY;
1370-
}
1427+
TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1428+
0,
1429+
TlsDataSize);
1430+
if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1431+
{
1432+
/* Out of memory */
1433+
return STATUS_NO_MEMORY;
1434+
}
13711435

1372-
/* Show debug message */
1373-
if (ShowSnaps)
1436+
/* Show debug message */
1437+
if (ShowSnaps)
1438+
{
1439+
DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1440+
TlsVector,
1441+
TlsData->TlsDirectory.Characteristics,
1442+
&TlsVector[TlsData->TlsDirectory.Characteristics],
1443+
TlsData->TlsDirectory.StartAddressOfRawData,
1444+
TlsVector[TlsData->TlsDirectory.Characteristics]);
1445+
}
1446+
1447+
/* Copy the data */
1448+
RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1449+
(PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1450+
TlsDataSize);
1451+
}
1452+
else
13741453
{
1375-
DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1376-
TlsVector,
1377-
TlsData->TlsDirectory.Characteristics,
1378-
&TlsVector[TlsData->TlsDirectory.Characteristics],
1379-
TlsData->TlsDirectory.StartAddressOfRawData,
1380-
TlsVector[TlsData->TlsDirectory.Characteristics]);
1454+
/* Reuse the previous thread-local copy of the TLS data in the new vector. */
1455+
TlsVector[TlsData->TlsDirectory.Characteristics] = OldTlsVector[TlsData->TlsDirectory.Characteristics];
1456+
/* Show debug message */
1457+
if (ShowSnaps)
1458+
{
1459+
DPRINT1("LDR: TlsVector %p Index %lu = %p recycled from %x to %p\n",
1460+
TlsVector,
1461+
TlsData->TlsDirectory.Characteristics,
1462+
&OldTlsVector[TlsData->TlsDirectory.Characteristics],
1463+
OldTlsVector[TlsData->TlsDirectory.Characteristics],
1464+
TlsVector[TlsData->TlsDirectory.Characteristics]);
1465+
}
13811466
}
1382-
1383-
/* Copy the data */
1384-
RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1385-
(PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1386-
TlsDataSize);
13871467
}
13881468

1469+
if (OldTlsVector)
1470+
{
1471+
OldTlsVectorEntry = RtlAllocateHeap(RtlGetProcessHeap(), 0,
1472+
sizeof(*OldTlsVectorEntry));
1473+
if (!OldTlsVectorEntry)
1474+
{
1475+
RtlFreeHeap(RtlGetProcessHeap(), 0, TlsVector);
1476+
return STATUS_NO_MEMORY;
1477+
}
1478+
OldTlsVectorEntry->OldTlsVector = OldTlsVector;
1479+
if (Teb->SystemReserved1.OldTlsVectorList)
1480+
{
1481+
InsertTailList((PLIST_ENTRY)Teb->SystemReserved1.OldTlsVectorList,
1482+
&OldTlsVectorEntry->TlsVectorLinks);
1483+
}
1484+
else
1485+
{
1486+
InitializeListHead(&OldTlsVectorEntry->TlsVectorLinks);
1487+
Teb->SystemReserved1.OldTlsVectorList = OldTlsVectorEntry;
1488+
}
1489+
}
1490+
Teb->ThreadLocalStoragePointer = TlsVector;
1491+
Teb->UserReserved.ThreadNumberOfTlsEntries = LdrpNumberOfTlsEntries;
13891492
/* Done */
13901493
return STATUS_SUCCESS;
13911494
}
@@ -1396,6 +1499,7 @@ LdrpFreeTls(VOID)
13961499
{
13971500
PLIST_ENTRY ListHead, NextEntry;
13981501
PLDRP_TLS_DATA TlsData;
1502+
PLDRP_OLD_TLS_VECTOR_ENTRY OldTlsVectorDataEntry;
13991503
PVOID *TlsVector;
14001504
PTEB Teb = NtCurrentTeb();
14011505

@@ -1424,6 +1528,24 @@ LdrpFreeTls(VOID)
14241528
RtlFreeHeap(RtlGetProcessHeap(),
14251529
0,
14261530
TlsVector);
1531+
1532+
if (Teb->SystemReserved1.OldTlsVectorList)
1533+
{
1534+
/* Loop through it */
1535+
ListHead = (PLIST_ENTRY)Teb->SystemReserved1.OldTlsVectorList;
1536+
NextEntry = ListHead->Flink;
1537+
while (NextEntry != ListHead)
1538+
{
1539+
OldTlsVectorDataEntry = CONTAINING_RECORD(NextEntry,
1540+
LDRP_OLD_TLS_VECTOR_ENTRY,
1541+
TlsVectorLinks);
1542+
NextEntry = NextEntry->Flink;
1543+
1544+
/* Free each old TLS vector and the entry itself */
1545+
RtlFreeHeap(RtlGetProcessHeap(), 0, OldTlsVectorDataEntry->OldTlsVector);
1546+
RtlFreeHeap(RtlGetProcessHeap(), 0, OldTlsVectorDataEntry);
1547+
}
1548+
}
14271549
}
14281550

14291551
NTSTATUS
@@ -2436,6 +2558,9 @@ LdrpInitializeProcess(IN PCONTEXT Context,
24362558
RtlpInitializeKeyedEvent();
24372559
RtlpInitializeThreadPooling();
24382560

2561+
/* Initialize Active TEB List */
2562+
InitializeListHead(&LdrpActiveTebList);
2563+
24392564
/* Initialize TLS */
24402565
Status = LdrpInitializeTls();
24412566
if (!NT_SUCCESS(Status))

dll/ntdll/ldr/ldrutils.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2580,6 +2580,18 @@ LdrpLoadDll(IN BOOLEAN Redirected,
25802580
}
25812581

25822582
/* Run the init routine */
2583+
Status = LdrpInitializeTls();
2584+
if (!NT_SUCCESS(Status))
2585+
{
2586+
/* Failed, unload the DLL */
2587+
if (ShowSnaps)
2588+
{
2589+
DbgPrint("LDR: Unloading %wZ because dynamic TLS allocation failed; status = 0x%08lx\n",
2590+
DllName,
2591+
Status);
2592+
}
2593+
LdrUnloadDll(LdrEntry->DllBase);
2594+
}
25832595
Status = LdrpRunInitializeRoutines(NULL);
25842596
if (!NT_SUCCESS(Status))
25852597
{

modules/rostests/apitests/ntdll/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11

2+
add_subdirectory(implicit_tls)
23
add_subdirectory(load_notifications)
34
add_subdirectory(empty_dll)
45

6+
include_directories($<TARGET_FILE_DIR:implicit_tls>)
57
include_directories($<TARGET_FILE_DIR:load_notifications>)
68
include_directories($<TARGET_FILE_DIR:empty_dll>)
79
include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
@@ -38,6 +40,7 @@ add_dependencies(ntdll_crt_test_lib psdk)
3840

3941
list(APPEND SOURCE
4042
DllLoadNotification.c
43+
implicit_tls.c
4144
LdrEnumResources.c
4245
LdrFindResource_U.c
4346
LdrLoadDll.c
@@ -161,6 +164,7 @@ endif()
161164
list(APPEND PCH_SKIP_SOURCE
162165
testlist.c)
163166

167+
add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/implicit_tls/implicit_tls.dll)
164168
add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/load_notifications/load_notifications.dll)
165169
add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/empty_dll/empty_dll.dll)
166170

@@ -180,7 +184,7 @@ target_link_libraries(ntdll_apitest ntdll_crt_test_lib rtl_test_lib wine uuid ${
180184
set_module_type(ntdll_apitest win32cui)
181185
add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll)
182186
add_pch(ntdll_apitest precomp.h "${PCH_SKIP_SOURCE}")
183-
add_dependencies(ntdll_apitest load_notifications empty_dll)
187+
add_dependencies(ntdll_apitest implicit_tls load_notifications empty_dll)
184188

185189
if(NOT MSVC)
186190
set_source_files_properties(

0 commit comments

Comments
 (0)