[LDR] Protect calls from LdrpCallInitRoutine and LdrpCallTlsInitializers with SEH.
[reactos.git] / dll / ntdll / ldr / ldrinit.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrinit.c
5 * PURPOSE: User-Mode Process/Thread Startup
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #include <compat_undoc.h>
14 #include <compatguid_undoc.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* GLOBALS *******************************************************************/
21
22 HANDLE ImageExecOptionsKey;
23 HANDLE Wow64ExecOptionsKey;
24 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
25 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
26 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
27
28 BOOLEAN LdrpInLdrInit;
29 LONG LdrpProcessInitialized;
30 BOOLEAN LdrpLoaderLockInit;
31 BOOLEAN LdrpLdrDatabaseIsSetup;
32 BOOLEAN LdrpShutdownInProgress;
33 HANDLE LdrpShutdownThreadId;
34
35 BOOLEAN LdrpDllValidation;
36
37 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
38 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
39 WCHAR StringBuffer[156];
40 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
41 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
42 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
43
44 RTL_BITMAP TlsBitMap;
45 RTL_BITMAP TlsExpansionBitMap;
46 RTL_BITMAP FlsBitMap;
47 BOOLEAN LdrpImageHasTls;
48 LIST_ENTRY LdrpTlsList;
49 ULONG LdrpNumberOfTlsEntries;
50 ULONG LdrpNumberOfProcessors;
51 PVOID NtDllBase;
52 extern LARGE_INTEGER RtlpTimeout;
53 BOOLEAN RtlpTimeoutDisable;
54 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
55 LIST_ENTRY LdrpDllNotificationList;
56 HANDLE LdrpKnownDllObjectDirectory;
57 UNICODE_STRING LdrpKnownDllPath;
58 WCHAR LdrpKnownDllPathBuffer[128];
59 UNICODE_STRING LdrpDefaultPath;
60
61 PEB_LDR_DATA PebLdr;
62
63 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
64 RTL_CRITICAL_SECTION LdrpLoaderLock =
65 {
66 &LdrpLoaderLockDebug,
67 -1,
68 0,
69 0,
70 0,
71 0
72 };
73 RTL_CRITICAL_SECTION FastPebLock;
74
75 BOOLEAN ShowSnaps;
76
77 ULONG LdrpFatalHardErrorCount;
78 ULONG LdrpActiveUnloadCount;
79
80 //extern LIST_ENTRY RtlCriticalSectionList;
81
82 VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
83 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
84 VOID NTAPI RtlInitializeHeapManager(VOID);
85
86 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
87 ULONG RtlpShutdownProcessFlags; // TODO: Use it
88
89 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
90 void actctx_init(void);
91 extern BOOLEAN RtlpUse16ByteSLists;
92
93 #ifdef _WIN64
94 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
95 #else
96 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
97 #endif
98
99 /* FUNCTIONS *****************************************************************/
100
101 /*
102 * @implemented
103 */
104 NTSTATUS
105 NTAPI
106 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
107 IN BOOLEAN Wow64,
108 OUT PHANDLE NewKeyHandle)
109 {
110 PHANDLE RootKeyLocation;
111 HANDLE RootKey;
112 UNICODE_STRING SubKeyString;
113 OBJECT_ATTRIBUTES ObjectAttributes;
114 NTSTATUS Status;
115 PWCHAR p1;
116
117 /* Check which root key to open */
118 if (Wow64)
119 RootKeyLocation = &Wow64ExecOptionsKey;
120 else
121 RootKeyLocation = &ImageExecOptionsKey;
122
123 /* Get the current key */
124 RootKey = *RootKeyLocation;
125
126 /* Setup the object attributes */
127 InitializeObjectAttributes(&ObjectAttributes,
128 Wow64 ?
129 &Wow64OptionsString : &ImageExecOptionsString,
130 OBJ_CASE_INSENSITIVE,
131 NULL,
132 NULL);
133
134 /* Open the root key */
135 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
136 if (NT_SUCCESS(Status))
137 {
138 /* Write the key handle */
139 if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
140 {
141 /* Someone already opened it, use it instead */
142 NtClose(RootKey);
143 RootKey = *RootKeyLocation;
144 }
145
146 /* Extract the name */
147 SubKeyString = *SubKey;
148 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
149 while (SubKeyString.Length)
150 {
151 if (p1[-1] == L'\\') break;
152 p1--;
153 SubKeyString.Length -= sizeof(*p1);
154 }
155 SubKeyString.Buffer = p1;
156 SubKeyString.Length = SubKey->Length - SubKeyString.Length;
157
158 /* Setup the object attributes */
159 InitializeObjectAttributes(&ObjectAttributes,
160 &SubKeyString,
161 OBJ_CASE_INSENSITIVE,
162 RootKey,
163 NULL);
164
165 /* Open the setting key */
166 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
167 }
168
169 /* Return to caller */
170 return Status;
171 }
172
173 /*
174 * @implemented
175 */
176 NTSTATUS
177 NTAPI
178 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
179 IN PCWSTR ValueName,
180 IN ULONG Type,
181 OUT PVOID Buffer,
182 IN ULONG BufferSize,
183 OUT PULONG ReturnedLength OPTIONAL)
184 {
185 ULONG KeyInfo[256];
186 UNICODE_STRING ValueNameString, IntegerString;
187 ULONG KeyInfoSize, ResultSize;
188 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
189 BOOLEAN FreeHeap = FALSE;
190 NTSTATUS Status;
191
192 /* Build a string for the value name */
193 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
194 if (!NT_SUCCESS(Status)) return Status;
195
196 /* Query the value */
197 Status = ZwQueryValueKey(KeyHandle,
198 &ValueNameString,
199 KeyValuePartialInformation,
200 KeyValueInformation,
201 sizeof(KeyInfo),
202 &ResultSize);
203 if (Status == STATUS_BUFFER_OVERFLOW)
204 {
205 /* Our local buffer wasn't enough, allocate one */
206 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
207 KeyValueInformation->DataLength;
208 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
209 0,
210 KeyInfoSize);
211 if (KeyValueInformation != NULL)
212 {
213 /* Try again */
214 Status = ZwQueryValueKey(KeyHandle,
215 &ValueNameString,
216 KeyValuePartialInformation,
217 KeyValueInformation,
218 KeyInfoSize,
219 &ResultSize);
220 FreeHeap = TRUE;
221 }
222 else
223 {
224 /* Give up this time */
225 Status = STATUS_NO_MEMORY;
226 }
227 }
228
229 /* Check for success */
230 if (NT_SUCCESS(Status))
231 {
232 /* Handle binary data */
233 if (KeyValueInformation->Type == REG_BINARY)
234 {
235 /* Check validity */
236 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
237 {
238 /* Copy into buffer */
239 RtlMoveMemory(Buffer,
240 &KeyValueInformation->Data,
241 KeyValueInformation->DataLength);
242 }
243 else
244 {
245 Status = STATUS_BUFFER_OVERFLOW;
246 }
247
248 /* Copy the result length */
249 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
250 }
251 else if (KeyValueInformation->Type == REG_DWORD)
252 {
253 /* Check for valid type */
254 if (KeyValueInformation->Type != Type)
255 {
256 /* Error */
257 Status = STATUS_OBJECT_TYPE_MISMATCH;
258 }
259 else
260 {
261 /* Check validity */
262 if ((Buffer) &&
263 (BufferSize == sizeof(ULONG)) &&
264 (KeyValueInformation->DataLength <= BufferSize))
265 {
266 /* Copy into buffer */
267 RtlMoveMemory(Buffer,
268 &KeyValueInformation->Data,
269 KeyValueInformation->DataLength);
270 }
271 else
272 {
273 Status = STATUS_BUFFER_OVERFLOW;
274 }
275
276 /* Copy the result length */
277 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
278 }
279 }
280 else if (KeyValueInformation->Type != REG_SZ)
281 {
282 /* We got something weird */
283 Status = STATUS_OBJECT_TYPE_MISMATCH;
284 }
285 else
286 {
287 /* String, check what you requested */
288 if (Type == REG_DWORD)
289 {
290 /* Validate */
291 if (BufferSize != sizeof(ULONG))
292 {
293 /* Invalid size */
294 BufferSize = 0;
295 Status = STATUS_INFO_LENGTH_MISMATCH;
296 }
297 else
298 {
299 /* OK, we know what you want... */
300 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
301 IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
302 sizeof(WCHAR);
303 IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
304 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
305 }
306 }
307 else
308 {
309 /* Validate */
310 if (KeyValueInformation->DataLength > BufferSize)
311 {
312 /* Invalid */
313 Status = STATUS_BUFFER_OVERFLOW;
314 }
315 else
316 {
317 /* Set the size */
318 BufferSize = KeyValueInformation->DataLength;
319 }
320
321 /* Copy the string */
322 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
323 }
324
325 /* Copy the result length */
326 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
327 }
328 }
329
330 /* Check if buffer was in heap */
331 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
332
333 /* Return status */
334 return Status;
335 }
336
337 /*
338 * @implemented
339 */
340 NTSTATUS
341 NTAPI
342 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
343 IN PCWSTR ValueName,
344 IN ULONG Type,
345 OUT PVOID Buffer,
346 IN ULONG BufferSize,
347 OUT PULONG ReturnedLength OPTIONAL,
348 IN BOOLEAN Wow64)
349 {
350 NTSTATUS Status;
351 HANDLE KeyHandle;
352
353 /* Open a handle to the key */
354 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
355
356 /* Check for success */
357 if (NT_SUCCESS(Status))
358 {
359 /* Query the data */
360 Status = LdrQueryImageFileKeyOption(KeyHandle,
361 ValueName,
362 Type,
363 Buffer,
364 BufferSize,
365 ReturnedLength);
366
367 /* Close the key */
368 NtClose(KeyHandle);
369 }
370
371 /* Return to caller */
372 return Status;
373 }
374
375 /*
376 * @implemented
377 */
378 NTSTATUS
379 NTAPI
380 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
381 IN PCWSTR ValueName,
382 IN ULONG Type,
383 OUT PVOID Buffer,
384 IN ULONG BufferSize,
385 OUT PULONG ReturnedLength OPTIONAL)
386 {
387 /* Call the newer function */
388 return LdrQueryImageFileExecutionOptionsEx(SubKey,
389 ValueName,
390 Type,
391 Buffer,
392 BufferSize,
393 ReturnedLength,
394 FALSE);
395 }
396
397 VOID
398 NTAPI
399 LdrpEnsureLoaderLockIsHeld(VOID)
400 {
401 // Ignored atm
402 }
403
404 PVOID
405 NTAPI
406 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
407 {
408 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
409 ULONG DirSize;
410 PVOID Cookie = NULL;
411
412 /* Check NT header first */
413 if (!RtlImageNtHeader(BaseAddress)) return NULL;
414
415 /* Get the pointer to the config directory */
416 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
417 TRUE,
418 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
419 &DirSize);
420
421 /* Check for sanity */
422 if (!ConfigDir ||
423 (DirSize != 64 && ConfigDir->Size != DirSize) ||
424 (ConfigDir->Size < 0x48))
425 return NULL;
426
427 /* Now get the cookie */
428 Cookie = (PVOID)ConfigDir->SecurityCookie;
429
430 /* Check this cookie */
431 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
432 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
433 {
434 Cookie = NULL;
435 }
436
437 /* Return validated security cookie */
438 return Cookie;
439 }
440
441 PVOID
442 NTAPI
443 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
444 {
445 PULONG_PTR Cookie;
446 LARGE_INTEGER Counter;
447 ULONG_PTR NewCookie;
448
449 /* Fetch address of the cookie */
450 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
451
452 if (Cookie)
453 {
454 /* Check if it's a default one */
455 if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
456 (*Cookie == 0xBB40))
457 {
458 /* Make up a cookie from a bunch of values which may uniquely represent
459 current moment of time, environment, etc */
460 NtQueryPerformanceCounter(&Counter, NULL);
461
462 NewCookie = Counter.LowPart ^ Counter.HighPart;
463 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
464 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
465
466 /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
467 while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
468 {
469 YieldProcessor();
470 };
471
472 /* Calculate the milliseconds value and xor it to the cookie */
473 NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
474 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
475
476 /* Make the cookie 16bit if necessary */
477 if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
478
479 /* If the result is 0 or the same as we got, just subtract one from the existing value
480 and that's it */
481 if ((NewCookie == 0) || (NewCookie == *Cookie))
482 {
483 NewCookie = *Cookie - 1;
484 }
485
486 /* Set the new cookie value */
487 *Cookie = NewCookie;
488 }
489 }
490
491 return Cookie;
492 }
493
494 VOID
495 NTAPI
496 LdrpInitializeThread(IN PCONTEXT Context)
497 {
498 PPEB Peb = NtCurrentPeb();
499 PLDR_DATA_TABLE_ENTRY LdrEntry;
500 PLIST_ENTRY NextEntry, ListHead;
501 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
502 NTSTATUS Status;
503 PVOID EntryPoint;
504
505 DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
506 &LdrpImageEntry->BaseDllName,
507 NtCurrentTeb()->RealClientId.UniqueProcess,
508 NtCurrentTeb()->RealClientId.UniqueThread);
509
510 /* Allocate an Activation Context Stack */
511 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
512 Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
513 if (!NT_SUCCESS(Status))
514 {
515 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
516 }
517
518 /* Make sure we are not shutting down */
519 if (LdrpShutdownInProgress) return;
520
521 /* Allocate TLS */
522 LdrpAllocateTls();
523
524 /* Start at the beginning */
525 ListHead = &Peb->Ldr->InMemoryOrderModuleList;
526 NextEntry = ListHead->Flink;
527 while (NextEntry != ListHead)
528 {
529 /* Get the current entry */
530 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
531
532 /* Make sure it's not ourselves */
533 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
534 {
535 /* Check if we should call */
536 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
537 {
538 /* Get the entrypoint */
539 EntryPoint = LdrEntry->EntryPoint;
540
541 /* Check if we are ready to call it */
542 if ((EntryPoint) &&
543 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
544 (LdrEntry->Flags & LDRP_IMAGE_DLL))
545 {
546 /* Set up the Act Ctx */
547 ActCtx.Size = sizeof(ActCtx);
548 ActCtx.Format = 1;
549 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
550
551 /* Activate the ActCtx */
552 RtlActivateActivationContextUnsafeFast(&ActCtx,
553 LdrEntry->EntryPointActivationContext);
554
555 _SEH2_TRY
556 {
557 /* Check if it has TLS */
558 if (LdrEntry->TlsIndex)
559 {
560 /* Make sure we're not shutting down */
561 if (!LdrpShutdownInProgress)
562 {
563 /* Call TLS */
564 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
565 }
566 }
567
568 /* Make sure we're not shutting down */
569 if (!LdrpShutdownInProgress)
570 {
571 /* Call the Entrypoint */
572 DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
573 &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
574 NtCurrentTeb()->RealClientId.UniqueProcess,
575 NtCurrentTeb()->RealClientId.UniqueThread);
576 LdrpCallInitRoutine(LdrEntry->EntryPoint,
577 LdrEntry->DllBase,
578 DLL_THREAD_ATTACH,
579 NULL);
580 }
581 }
582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
583 {
584 /* Do nothing */
585 }
586 _SEH2_END;
587
588 /* Deactivate the ActCtx */
589 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
590 }
591 }
592 }
593
594 /* Next entry */
595 NextEntry = NextEntry->Flink;
596 }
597
598 /* Check for TLS */
599 if (LdrpImageHasTls && !LdrpShutdownInProgress)
600 {
601 /* Set up the Act Ctx */
602 ActCtx.Size = sizeof(ActCtx);
603 ActCtx.Format = 1;
604 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
605
606 /* Activate the ActCtx */
607 RtlActivateActivationContextUnsafeFast(&ActCtx,
608 LdrpImageEntry->EntryPointActivationContext);
609
610 _SEH2_TRY
611 {
612 /* Do TLS callbacks */
613 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
614 }
615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
616 {
617 /* Do nothing */
618 }
619 _SEH2_END;
620
621 /* Deactivate the ActCtx */
622 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
623 }
624
625 DPRINT("LdrpInitializeThread() done\n");
626 }
627
628 NTSTATUS
629 NTAPI
630 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
631 {
632 PLDR_DATA_TABLE_ENTRY LocalArray[16];
633 PLIST_ENTRY ListHead;
634 PLIST_ENTRY NextEntry;
635 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
636 PVOID EntryPoint;
637 ULONG Count, i;
638 //ULONG BreakOnInit;
639 NTSTATUS Status = STATUS_SUCCESS;
640 PPEB Peb = NtCurrentPeb();
641 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
642 ULONG BreakOnDllLoad;
643 PTEB OldTldTeb;
644 BOOLEAN DllStatus;
645
646 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
647 &LdrpImageEntry->BaseDllName,
648 NtCurrentTeb()->RealClientId.UniqueProcess,
649 NtCurrentTeb()->RealClientId.UniqueThread);
650
651 /* Check the Loader Lock */
652 LdrpEnsureLoaderLockIsHeld();
653
654 /* Get the number of entries to call */
655 if ((Count = LdrpClearLoadInProgress()))
656 {
657 /* Check if we can use our local buffer */
658 if (Count > 16)
659 {
660 /* Allocate space for all the entries */
661 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
662 0,
663 Count * sizeof(*LdrRootEntry));
664 if (!LdrRootEntry) return STATUS_NO_MEMORY;
665 }
666 else
667 {
668 /* Use our local array */
669 LdrRootEntry = LocalArray;
670 }
671 }
672 else
673 {
674 /* Don't need one */
675 LdrRootEntry = NULL;
676 }
677
678 /* Show debug message */
679 if (ShowSnaps)
680 {
681 DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
682 NtCurrentTeb()->RealClientId.UniqueThread,
683 NtCurrentTeb()->RealClientId.UniqueProcess,
684 &Peb->ProcessParameters->ImagePathName);
685 }
686
687 /* Loop in order */
688 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
689 NextEntry = ListHead->Flink;
690 i = 0;
691 while (NextEntry != ListHead)
692 {
693 /* Get the Data Entry */
694 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
695
696 /* Check if we have a Root Entry */
697 if (LdrRootEntry)
698 {
699 /* Check flags */
700 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
701 {
702 /* Setup the Cookie for the DLL */
703 LdrpInitSecurityCookie(LdrEntry);
704
705 /* Check for valid entrypoint */
706 if (LdrEntry->EntryPoint)
707 {
708 /* Write in array */
709 ASSERT(i < Count);
710 LdrRootEntry[i] = LdrEntry;
711
712 /* Display debug message */
713 if (ShowSnaps)
714 {
715 DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
716 NtCurrentTeb()->RealClientId.UniqueThread,
717 NtCurrentTeb()->RealClientId.UniqueProcess,
718 &LdrEntry->FullDllName,
719 LdrEntry->EntryPoint);
720 }
721 i++;
722 }
723 }
724 }
725
726 /* Set the flag */
727 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
728 NextEntry = NextEntry->Flink;
729 }
730
731 /* If we got a context, then we have to call Kernel32 for TS support */
732 if (Context)
733 {
734 /* Check if we have one */
735 //if (Kernel32ProcessInitPostImportfunction)
736 //{
737 /* Call it */
738 //Kernel32ProcessInitPostImportfunction();
739 //}
740
741 /* Clear it */
742 //Kernel32ProcessInitPostImportfunction = NULL;
743 //UNIMPLEMENTED;
744 }
745
746 /* No root entry? return */
747 if (!LdrRootEntry) return STATUS_SUCCESS;
748
749 /* Set the TLD TEB */
750 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
751 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
752
753 /* Loop */
754 i = 0;
755 while (i < Count)
756 {
757 /* Get an entry */
758 LdrEntry = LdrRootEntry[i];
759
760 /* FIXME: Verify NX Compat */
761
762 /* Move to next entry */
763 i++;
764
765 /* Get its entrypoint */
766 EntryPoint = LdrEntry->EntryPoint;
767
768 /* Are we being debugged? */
769 BreakOnDllLoad = 0;
770 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
771 {
772 /* Check if we should break on load */
773 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
774 L"BreakOnDllLoad",
775 REG_DWORD,
776 &BreakOnDllLoad,
777 sizeof(ULONG),
778 NULL);
779 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
780
781 /* Reset status back to STATUS_SUCCESS */
782 Status = STATUS_SUCCESS;
783 }
784
785 /* Break if aksed */
786 if (BreakOnDllLoad)
787 {
788 /* Check if we should show a message */
789 if (ShowSnaps)
790 {
791 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
792 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
793 }
794
795 /* Break in debugger */
796 DbgBreakPoint();
797 }
798
799 /* Make sure we have an entrypoint */
800 if (EntryPoint)
801 {
802 /* Save the old Dll Initializer and write the current one */
803 OldInitializer = LdrpCurrentDllInitializer;
804 LdrpCurrentDllInitializer = LdrEntry;
805
806 /* Set up the Act Ctx */
807 ActCtx.Size = sizeof(ActCtx);
808 ActCtx.Format = 1;
809 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
810
811 /* Activate the ActCtx */
812 RtlActivateActivationContextUnsafeFast(&ActCtx,
813 LdrEntry->EntryPointActivationContext);
814
815 _SEH2_TRY
816 {
817 /* Check if it has TLS */
818 if (LdrEntry->TlsIndex && Context)
819 {
820 /* Call TLS */
821 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
822 }
823
824 /* Call the Entrypoint */
825 if (ShowSnaps)
826 {
827 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
828 &LdrEntry->BaseDllName, EntryPoint);
829 }
830 DllStatus = LdrpCallInitRoutine(EntryPoint,
831 LdrEntry->DllBase,
832 DLL_PROCESS_ATTACH,
833 Context);
834 }
835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
836 {
837 DllStatus = FALSE;
838 }
839 _SEH2_END;
840
841 /* Deactivate the ActCtx */
842 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
843
844 /* Save the Current DLL Initializer */
845 LdrpCurrentDllInitializer = OldInitializer;
846
847 /* Mark the entry as processed */
848 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
849
850 /* Fail if DLL init failed */
851 if (!DllStatus)
852 {
853 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
854 &LdrEntry->BaseDllName, EntryPoint);
855
856 Status = STATUS_DLL_INIT_FAILED;
857 goto Quickie;
858 }
859 }
860 }
861
862 /* Loop in order */
863 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
864 NextEntry = NextEntry->Flink;
865 while (NextEntry != ListHead)
866 {
867 /* Get the Data Entry */
868 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
869
870 /* FIXME: Verify NX Compat */
871 // LdrpCheckNXCompatibility()
872
873 /* Next entry */
874 NextEntry = NextEntry->Flink;
875 }
876
877 /* Check for TLS */
878 if (LdrpImageHasTls && Context)
879 {
880 /* Set up the Act Ctx */
881 ActCtx.Size = sizeof(ActCtx);
882 ActCtx.Format = 1;
883 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
884
885 /* Activate the ActCtx */
886 RtlActivateActivationContextUnsafeFast(&ActCtx,
887 LdrpImageEntry->EntryPointActivationContext);
888
889 _SEH2_TRY
890 {
891 /* Do TLS callbacks */
892 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
893 }
894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
895 {
896 /* Do nothing */
897 }
898 _SEH2_END;
899
900 /* Deactivate the ActCtx */
901 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
902 }
903
904 Quickie:
905 /* Restore old TEB */
906 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
907
908 /* Check if the array is in the heap */
909 if (LdrRootEntry != LocalArray)
910 {
911 /* Free the array */
912 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
913 }
914
915 /* Return to caller */
916 DPRINT("LdrpRunInitializeRoutines() done\n");
917 return Status;
918 }
919
920 /*
921 * @implemented
922 */
923 NTSTATUS
924 NTAPI
925 LdrShutdownProcess(VOID)
926 {
927 PPEB Peb = NtCurrentPeb();
928 PLDR_DATA_TABLE_ENTRY LdrEntry;
929 PLIST_ENTRY NextEntry, ListHead;
930 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
931 PVOID EntryPoint;
932
933 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
934 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
935
936 /* Tell the Shim Engine */
937 if (g_ShimsEnabled)
938 {
939 VOID(NTAPI *SE_ProcessDying)();
940 SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
941 SE_ProcessDying();
942 }
943
944 /* Tell the world */
945 if (ShowSnaps)
946 {
947 DPRINT1("\n");
948 }
949
950 /* Set the shutdown variables */
951 LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
952 LdrpShutdownInProgress = TRUE;
953
954 /* Enter the Loader Lock */
955 RtlEnterCriticalSection(&LdrpLoaderLock);
956
957 /* Cleanup trace logging data (Etw) */
958 if (SharedUserData->TraceLogging)
959 {
960 /* FIXME */
961 DPRINT1("We don't support Etw yet.\n");
962 }
963
964 /* Start at the end */
965 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
966 NextEntry = ListHead->Blink;
967 while (NextEntry != ListHead)
968 {
969 /* Get the current entry */
970 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
971 NextEntry = NextEntry->Blink;
972
973 /* Make sure it's not ourselves */
974 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
975 {
976 /* Get the entrypoint */
977 EntryPoint = LdrEntry->EntryPoint;
978
979 /* Check if we are ready to call it */
980 if (EntryPoint &&
981 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
982 LdrEntry->Flags)
983 {
984 /* Set up the Act Ctx */
985 ActCtx.Size = sizeof(ActCtx);
986 ActCtx.Format = 1;
987 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
988
989 /* Activate the ActCtx */
990 RtlActivateActivationContextUnsafeFast(&ActCtx,
991 LdrEntry->EntryPointActivationContext);
992
993 _SEH2_TRY
994 {
995 /* Check if it has TLS */
996 if (LdrEntry->TlsIndex)
997 {
998 /* Call TLS */
999 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
1000 }
1001
1002 /* Call the Entrypoint */
1003 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1004 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1005 LdrpCallInitRoutine(EntryPoint,
1006 LdrEntry->DllBase,
1007 DLL_PROCESS_DETACH,
1008 (PVOID)1);
1009 }
1010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1011 {
1012 /* Do nothing */
1013 }
1014 _SEH2_END;
1015
1016 /* Deactivate the ActCtx */
1017 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1018 }
1019 }
1020 }
1021
1022 /* Check for TLS */
1023 if (LdrpImageHasTls)
1024 {
1025 /* Set up the Act Ctx */
1026 ActCtx.Size = sizeof(ActCtx);
1027 ActCtx.Format = 1;
1028 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1029
1030 /* Activate the ActCtx */
1031 RtlActivateActivationContextUnsafeFast(&ActCtx,
1032 LdrpImageEntry->EntryPointActivationContext);
1033
1034 _SEH2_TRY
1035 {
1036 /* Do TLS callbacks */
1037 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
1038 }
1039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1040 {
1041 /* Do nothing */
1042 }
1043 _SEH2_END;
1044
1045 /* Deactivate the ActCtx */
1046 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1047 }
1048
1049 /* FIXME: Do Heap detection and Etw final shutdown */
1050
1051 /* Release the lock */
1052 RtlLeaveCriticalSection(&LdrpLoaderLock);
1053 DPRINT("LdrpShutdownProcess() done\n");
1054
1055 return STATUS_SUCCESS;
1056 }
1057
1058 /*
1059 * @implemented
1060 */
1061 NTSTATUS
1062 NTAPI
1063 LdrShutdownThread(VOID)
1064 {
1065 PPEB Peb = NtCurrentPeb();
1066 PTEB Teb = NtCurrentTeb();
1067 PLDR_DATA_TABLE_ENTRY LdrEntry;
1068 PLIST_ENTRY NextEntry, ListHead;
1069 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1070 PVOID EntryPoint;
1071
1072 DPRINT("LdrShutdownThread() called for %wZ\n",
1073 &LdrpImageEntry->BaseDllName);
1074
1075 /* Cleanup trace logging data (Etw) */
1076 if (SharedUserData->TraceLogging)
1077 {
1078 /* FIXME */
1079 DPRINT1("We don't support Etw yet.\n");
1080 }
1081
1082 /* Get the Ldr Lock */
1083 RtlEnterCriticalSection(&LdrpLoaderLock);
1084
1085 /* Start at the end */
1086 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1087 NextEntry = ListHead->Blink;
1088 while (NextEntry != ListHead)
1089 {
1090 /* Get the current entry */
1091 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1092 NextEntry = NextEntry->Blink;
1093
1094 /* Make sure it's not ourselves */
1095 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1096 {
1097 /* Check if we should call */
1098 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1099 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1100 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1101 {
1102 /* Get the entrypoint */
1103 EntryPoint = LdrEntry->EntryPoint;
1104
1105 /* Check if we are ready to call it */
1106 if (EntryPoint)
1107 {
1108 /* Set up the Act Ctx */
1109 ActCtx.Size = sizeof(ActCtx);
1110 ActCtx.Format = 1;
1111 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1112
1113 /* Activate the ActCtx */
1114 RtlActivateActivationContextUnsafeFast(&ActCtx,
1115 LdrEntry->EntryPointActivationContext);
1116
1117 _SEH2_TRY
1118 {
1119 /* Check if it has TLS */
1120 if (LdrEntry->TlsIndex)
1121 {
1122 /* Make sure we're not shutting down */
1123 if (!LdrpShutdownInProgress)
1124 {
1125 /* Call TLS */
1126 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
1127 }
1128 }
1129
1130 /* Make sure we're not shutting down */
1131 if (!LdrpShutdownInProgress)
1132 {
1133 /* Call the Entrypoint */
1134 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1135 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1136 LdrpCallInitRoutine(EntryPoint,
1137 LdrEntry->DllBase,
1138 DLL_THREAD_DETACH,
1139 NULL);
1140 }
1141 }
1142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1143 {
1144 /* Do nothing */
1145 }
1146 _SEH2_END;
1147
1148 /* Deactivate the ActCtx */
1149 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1150 }
1151 }
1152 }
1153 }
1154
1155 /* Check for TLS */
1156 if (LdrpImageHasTls)
1157 {
1158 /* Set up the Act Ctx */
1159 ActCtx.Size = sizeof(ActCtx);
1160 ActCtx.Format = 1;
1161 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1162
1163 /* Activate the ActCtx */
1164 RtlActivateActivationContextUnsafeFast(&ActCtx,
1165 LdrpImageEntry->EntryPointActivationContext);
1166
1167 _SEH2_TRY
1168 {
1169 /* Do TLS callbacks */
1170 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH);
1171 }
1172 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1173 {
1174 /* Do nothing */
1175 }
1176 _SEH2_END;
1177
1178 /* Deactivate the ActCtx */
1179 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1180 }
1181
1182 /* Free TLS */
1183 LdrpFreeTls();
1184 RtlLeaveCriticalSection(&LdrpLoaderLock);
1185
1186 /* Check for expansion slots */
1187 if (Teb->TlsExpansionSlots)
1188 {
1189 /* Free expansion slots */
1190 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1191 }
1192
1193 /* Check for FLS Data */
1194 if (Teb->FlsData)
1195 {
1196 /* FIXME */
1197 DPRINT1("We don't support FLS Data yet\n");
1198 }
1199
1200 /* Check for Fiber data */
1201 if (Teb->HasFiberData)
1202 {
1203 /* Free Fiber data*/
1204 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1205 Teb->NtTib.FiberData = NULL;
1206 }
1207
1208 /* Free the activation context stack */
1209 RtlFreeThreadActivationContextStack();
1210 DPRINT("LdrShutdownThread() done\n");
1211
1212 return STATUS_SUCCESS;
1213 }
1214
1215 NTSTATUS
1216 NTAPI
1217 LdrpInitializeTls(VOID)
1218 {
1219 PLIST_ENTRY NextEntry, ListHead;
1220 PLDR_DATA_TABLE_ENTRY LdrEntry;
1221 PIMAGE_TLS_DIRECTORY TlsDirectory;
1222 PLDRP_TLS_DATA TlsData;
1223 ULONG Size;
1224
1225 /* Initialize the TLS List */
1226 InitializeListHead(&LdrpTlsList);
1227
1228 /* Loop all the modules */
1229 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1230 NextEntry = ListHead->Flink;
1231 while (ListHead != NextEntry)
1232 {
1233 /* Get the entry */
1234 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1235 NextEntry = NextEntry->Flink;
1236
1237 /* Get the TLS directory */
1238 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1239 TRUE,
1240 IMAGE_DIRECTORY_ENTRY_TLS,
1241 &Size);
1242
1243 /* Check if we have a directory */
1244 if (!TlsDirectory) continue;
1245
1246 /* Check if the image has TLS */
1247 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1248
1249 /* Show debug message */
1250 if (ShowSnaps)
1251 {
1252 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1253 &LdrEntry->BaseDllName,
1254 TlsDirectory);
1255 }
1256
1257 /* Allocate an entry */
1258 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1259 if (!TlsData) return STATUS_NO_MEMORY;
1260
1261 /* Lock the DLL and mark it for TLS Usage */
1262 LdrEntry->LoadCount = -1;
1263 LdrEntry->TlsIndex = -1;
1264
1265 /* Save the cached TLS data */
1266 TlsData->TlsDirectory = *TlsDirectory;
1267 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1268
1269 /* Update the index */
1270 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1271 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1272 }
1273
1274 /* Done setting up TLS, allocate entries */
1275 return LdrpAllocateTls();
1276 }
1277
1278 NTSTATUS
1279 NTAPI
1280 LdrpAllocateTls(VOID)
1281 {
1282 PTEB Teb = NtCurrentTeb();
1283 PLIST_ENTRY NextEntry, ListHead;
1284 PLDRP_TLS_DATA TlsData;
1285 SIZE_T TlsDataSize;
1286 PVOID *TlsVector;
1287
1288 /* Check if we have any entries */
1289 if (!LdrpNumberOfTlsEntries)
1290 return STATUS_SUCCESS;
1291
1292 /* Allocate the vector array */
1293 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1294 0,
1295 LdrpNumberOfTlsEntries * sizeof(PVOID));
1296 if (!TlsVector) return STATUS_NO_MEMORY;
1297 Teb->ThreadLocalStoragePointer = TlsVector;
1298
1299 /* Loop the TLS Array */
1300 ListHead = &LdrpTlsList;
1301 NextEntry = ListHead->Flink;
1302 while (NextEntry != ListHead)
1303 {
1304 /* Get the entry */
1305 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1306 NextEntry = NextEntry->Flink;
1307
1308 /* Allocate this vector */
1309 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1310 TlsData->TlsDirectory.StartAddressOfRawData;
1311 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1312 0,
1313 TlsDataSize);
1314 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1315 {
1316 /* Out of memory */
1317 return STATUS_NO_MEMORY;
1318 }
1319
1320 /* Show debug message */
1321 if (ShowSnaps)
1322 {
1323 DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1324 TlsVector,
1325 TlsData->TlsDirectory.Characteristics,
1326 &TlsVector[TlsData->TlsDirectory.Characteristics],
1327 TlsData->TlsDirectory.StartAddressOfRawData,
1328 TlsVector[TlsData->TlsDirectory.Characteristics]);
1329 }
1330
1331 /* Copy the data */
1332 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1333 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1334 TlsDataSize);
1335 }
1336
1337 /* Done */
1338 return STATUS_SUCCESS;
1339 }
1340
1341 VOID
1342 NTAPI
1343 LdrpFreeTls(VOID)
1344 {
1345 PLIST_ENTRY ListHead, NextEntry;
1346 PLDRP_TLS_DATA TlsData;
1347 PVOID *TlsVector;
1348 PTEB Teb = NtCurrentTeb();
1349
1350 /* Get a pointer to the vector array */
1351 TlsVector = Teb->ThreadLocalStoragePointer;
1352 if (!TlsVector) return;
1353
1354 /* Loop through it */
1355 ListHead = &LdrpTlsList;
1356 NextEntry = ListHead->Flink;
1357 while (NextEntry != ListHead)
1358 {
1359 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1360 NextEntry = NextEntry->Flink;
1361
1362 /* Free each entry */
1363 if (TlsVector[TlsData->TlsDirectory.Characteristics])
1364 {
1365 RtlFreeHeap(RtlGetProcessHeap(),
1366 0,
1367 TlsVector[TlsData->TlsDirectory.Characteristics]);
1368 }
1369 }
1370
1371 /* Free the array itself */
1372 RtlFreeHeap(RtlGetProcessHeap(),
1373 0,
1374 TlsVector);
1375 }
1376
1377 NTSTATUS
1378 NTAPI
1379 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1380 {
1381 NTSTATUS Status;
1382 HANDLE KeyHandle;
1383 ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1384
1385 /* Return error if we were not provided a pointer where to save the options key handle */
1386 if (!OptionsKey) return STATUS_INVALID_HANDLE;
1387
1388 /* Zero initialize the options key pointer */
1389 *OptionsKey = NULL;
1390
1391 /* Open the options key */
1392 Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1393
1394 /* Save it if it was opened successfully */
1395 if (NT_SUCCESS(Status))
1396 *OptionsKey = KeyHandle;
1397
1398 if (KeyHandle)
1399 {
1400 /* There are image specific options, read them starting with NXCOMPAT */
1401 Status = LdrQueryImageFileKeyOption(KeyHandle,
1402 L"ExecuteOptions",
1403 4,
1404 &ExecuteOptions,
1405 sizeof(ExecuteOptions),
1406 0);
1407
1408 if (NT_SUCCESS(Status))
1409 {
1410 /* TODO: Set execution options for the process */
1411 /*
1412 if (ExecuteOptions == 0)
1413 ExecuteOptions = 1;
1414 else
1415 ExecuteOptions = 2;
1416 ZwSetInformationProcess(NtCurrentProcess(),
1417 ProcessExecuteFlags,
1418 &ExecuteOptions,
1419 sizeof(ULONG));*/
1420
1421 }
1422
1423 /* Check if this image uses large pages */
1424 if (Peb->ImageUsesLargePages)
1425 {
1426 /* TODO: If it does, open large page key */
1427 UNIMPLEMENTED;
1428 }
1429
1430 /* Get various option values */
1431 LdrQueryImageFileKeyOption(KeyHandle,
1432 L"DisableHeapLookaside",
1433 REG_DWORD,
1434 &RtlpDisableHeapLookaside,
1435 sizeof(RtlpDisableHeapLookaside),
1436 NULL);
1437
1438 LdrQueryImageFileKeyOption(KeyHandle,
1439 L"ShutdownFlags",
1440 REG_DWORD,
1441 &RtlpShutdownProcessFlags,
1442 sizeof(RtlpShutdownProcessFlags),
1443 NULL);
1444
1445 LdrQueryImageFileKeyOption(KeyHandle,
1446 L"MinimumStackCommitInBytes",
1447 REG_DWORD,
1448 &MinimumStackCommit,
1449 sizeof(MinimumStackCommit),
1450 NULL);
1451
1452 /* Update PEB's minimum stack commit if it's lower */
1453 if (Peb->MinimumStackCommit < MinimumStackCommit)
1454 Peb->MinimumStackCommit = MinimumStackCommit;
1455
1456 /* Set the global flag */
1457 Status = LdrQueryImageFileKeyOption(KeyHandle,
1458 L"GlobalFlag",
1459 REG_DWORD,
1460 &GlobalFlag,
1461 sizeof(GlobalFlag),
1462 NULL);
1463
1464 if (NT_SUCCESS(Status))
1465 Peb->NtGlobalFlag = GlobalFlag;
1466 else
1467 GlobalFlag = 0;
1468
1469 /* Call AVRF if necessary */
1470 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1471 {
1472 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1473 if (!NT_SUCCESS(Status))
1474 {
1475 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1476 }
1477 }
1478 }
1479 else
1480 {
1481 /* There are no image-specific options, so perform global initialization */
1482 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1483 {
1484 /* Initialize app verifier package */
1485 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1486 if (!NT_SUCCESS(Status))
1487 {
1488 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1489 }
1490 }
1491 }
1492
1493 return STATUS_SUCCESS;
1494 }
1495
1496 VOID
1497 NTAPI
1498 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1499 {
1500 UNIMPLEMENTED;
1501 }
1502
1503 VOID
1504 NTAPI
1505 LdrpInitializeProcessCompat(PVOID* pOldShimData)
1506 {
1507 static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8,
1508 &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA };
1509 static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA };
1510
1511 ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1512 ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1513 SIZE_T SizeRequired;
1514 NTSTATUS Status;
1515 DWORD n, cur;
1516 ReactOS_ShimData* pShimData = *pOldShimData;
1517
1518 C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions));
1519
1520 if (pShimData)
1521 {
1522 if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1523 pShimData->dwSize != sizeof(ReactOS_ShimData))
1524 {
1525 DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1526 return;
1527 }
1528 if (pShimData->dwRosProcessCompatVersion)
1529 {
1530 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1531 return;
1532 }
1533 }
1534
1535 SizeRequired = sizeof(Buffer);
1536 Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1537 NULL,
1538 NULL,
1539 CompatibilityInformationInActivationContext,
1540 Buffer,
1541 sizeof(Buffer),
1542 &SizeRequired);
1543
1544 if (!NT_SUCCESS(Status))
1545 {
1546 DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1547 return;
1548 }
1549
1550 ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1551 /* No Compatibility elements present, bail out */
1552 if (ContextCompatInfo->ElementCount == 0)
1553 return;
1554
1555 /* Search for known GUID's, starting from newest to oldest. */
1556 for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur)
1557 {
1558 for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1559 {
1560 if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1561 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID))
1562 {
1563 /* If this process did not need shim data before, allocate and store it */
1564 if (pShimData == NULL)
1565 {
1566 PPEB Peb = NtCurrentPeb();
1567
1568 ASSERT(Peb->pShimData == NULL);
1569 pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1570
1571 if (!pShimData)
1572 {
1573 DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1574 return;
1575 }
1576
1577 pShimData->dwSize = sizeof(*pShimData);
1578 pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1579
1580 Peb->pShimData = pShimData;
1581 *pOldShimData = pShimData;
1582 }
1583
1584 /* Store the highest found version, and bail out. */
1585 pShimData->dwRosProcessCompatVersion = GuidVersions[cur];
1586 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]);
1587 return;
1588 }
1589 }
1590 }
1591 }
1592
1593
1594 NTSTATUS
1595 NTAPI
1596 LdrpInitializeProcess(IN PCONTEXT Context,
1597 IN PVOID SystemArgument1)
1598 {
1599 RTL_HEAP_PARAMETERS HeapParameters;
1600 ULONG ComSectionSize;
1601 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1602 PVOID OldShimData;
1603 OBJECT_ATTRIBUTES ObjectAttributes;
1604 //UNICODE_STRING LocalFileName, FullImageName;
1605 HANDLE SymLinkHandle;
1606 //ULONG DebugHeapOnly;
1607 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1608 PPEB Peb = NtCurrentPeb();
1609 BOOLEAN IsDotNetImage = FALSE;
1610 BOOLEAN FreeCurDir = FALSE;
1611 //HANDLE CompatKey;
1612 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1613 //LPWSTR ImagePathBuffer;
1614 ULONG ConfigSize;
1615 UNICODE_STRING CurrentDirectory;
1616 HANDLE OptionsKey;
1617 ULONG HeapFlags;
1618 PIMAGE_NT_HEADERS NtHeader;
1619 LPWSTR NtDllName = NULL;
1620 NTSTATUS Status, ImportStatus;
1621 NLSTABLEINFO NlsTable;
1622 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1623 PTEB Teb = NtCurrentTeb();
1624 PLIST_ENTRY ListHead;
1625 PLIST_ENTRY NextEntry;
1626 ULONG i;
1627 PWSTR ImagePath;
1628 ULONG DebugProcessHeapOnly = 0;
1629 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1630 PWCHAR Current;
1631 ULONG ExecuteOptions = 0;
1632 PVOID ViewBase;
1633
1634 /* Set a NULL SEH Filter */
1635 RtlSetUnhandledExceptionFilter(NULL);
1636
1637 /* Get the image path */
1638 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1639
1640 /* Check if it's not normalized */
1641 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1642 {
1643 /* Normalize it*/
1644 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1645 }
1646
1647 /* Create a unicode string for the Image Path */
1648 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1649 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1650 ImagePathName.Buffer = ImagePath;
1651
1652 /* Get the NT Headers */
1653 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1654
1655 /* Get the execution options */
1656 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1657
1658 /* Check if this is a .NET executable */
1659 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1660 TRUE,
1661 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1662 &ComSectionSize))
1663 {
1664 /* Remember this for later */
1665 IsDotNetImage = TRUE;
1666 }
1667
1668 /* Save the NTDLL Base address */
1669 NtDllBase = SystemArgument1;
1670
1671 /* If this is a Native Image */
1672 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1673 {
1674 /* Then do DLL Validation */
1675 LdrpDllValidation = TRUE;
1676 }
1677
1678 /* Save the old Shim Data */
1679 OldShimData = Peb->pShimData;
1680
1681 /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1682 //Peb->pShimData = NULL;
1683
1684 /* Save the number of processors and CS Timeout */
1685 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1686 RtlpTimeout = Peb->CriticalSectionTimeout;
1687
1688 /* Normalize the parameters */
1689 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1690 if (ProcessParameters)
1691 {
1692 /* Save the Image and Command Line Names */
1693 ImageFileName = ProcessParameters->ImagePathName;
1694 CommandLine = ProcessParameters->CommandLine;
1695 }
1696 else
1697 {
1698 /* It failed, initialize empty strings */
1699 RtlInitUnicodeString(&ImageFileName, NULL);
1700 RtlInitUnicodeString(&CommandLine, NULL);
1701 }
1702
1703 /* Initialize NLS data */
1704 RtlInitNlsTables(Peb->AnsiCodePageData,
1705 Peb->OemCodePageData,
1706 Peb->UnicodeCaseTableData,
1707 &NlsTable);
1708
1709 /* Reset NLS Translations */
1710 RtlResetRtlTranslations(&NlsTable);
1711
1712 /* Get the Image Config Directory */
1713 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1714 TRUE,
1715 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1716 &ConfigSize);
1717
1718 /* Setup the Heap Parameters */
1719 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1720 HeapFlags = HEAP_GROWABLE;
1721 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1722
1723 /* Check if we have Configuration Data */
1724 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1725 {
1726 /* FIXME: Custom heap settings and misc. */
1727 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1728 }
1729
1730 /* Check for custom affinity mask */
1731 if (Peb->ImageProcessAffinityMask)
1732 {
1733 /* Set it */
1734 Status = NtSetInformationProcess(NtCurrentProcess(),
1735 ProcessAffinityMask,
1736 &Peb->ImageProcessAffinityMask,
1737 sizeof(Peb->ImageProcessAffinityMask));
1738 }
1739
1740 /* Check if verbose debugging (ShowSnaps) was requested */
1741 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1742
1743 /* Start verbose debugging messages right now if they were requested */
1744 if (ShowSnaps)
1745 {
1746 DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1747 Teb->ClientId.UniqueProcess,
1748 &CommandLine);
1749 }
1750
1751 /* If the timeout is too long */
1752 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1753 {
1754 /* Then disable CS Timeout */
1755 RtlpTimeoutDisable = TRUE;
1756 }
1757
1758 /* Initialize Critical Section Data */
1759 RtlpInitDeferedCriticalSection();
1760
1761 /* Initialize VEH Call lists */
1762 RtlpInitializeVectoredExceptionHandling();
1763
1764 /* Set TLS/FLS Bitmap data */
1765 Peb->FlsBitmap = &FlsBitMap;
1766 Peb->TlsBitmap = &TlsBitMap;
1767 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1768
1769 /* Initialize FLS Bitmap */
1770 RtlInitializeBitMap(&FlsBitMap,
1771 Peb->FlsBitmapBits,
1772 FLS_MAXIMUM_AVAILABLE);
1773 RtlSetBit(&FlsBitMap, 0);
1774
1775 /* Initialize TLS Bitmap */
1776 RtlInitializeBitMap(&TlsBitMap,
1777 Peb->TlsBitmapBits,
1778 TLS_MINIMUM_AVAILABLE);
1779 RtlSetBit(&TlsBitMap, 0);
1780 RtlInitializeBitMap(&TlsExpansionBitMap,
1781 Peb->TlsExpansionBitmapBits,
1782 TLS_EXPANSION_SLOTS);
1783 RtlSetBit(&TlsExpansionBitMap, 0);
1784
1785 /* Initialize the Hash Table */
1786 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1787 {
1788 InitializeListHead(&LdrpHashTable[i]);
1789 }
1790
1791 /* Initialize the Loader Lock */
1792 // FIXME: What's the point of initing it manually, if two lines lower
1793 // a call to RtlInitializeCriticalSection() is being made anyway?
1794 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1795 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1796 RtlInitializeCriticalSection(&LdrpLoaderLock);
1797 LdrpLoaderLockInit = TRUE;
1798
1799 /* Check if User Stack Trace Database support was requested */
1800 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1801 {
1802 DPRINT1("We don't support user stack trace databases yet\n");
1803 }
1804
1805 /* Setup Fast PEB Lock */
1806 RtlInitializeCriticalSection(&FastPebLock);
1807 Peb->FastPebLock = &FastPebLock;
1808 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1809 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1810
1811 /* Setup Callout Lock and Notification list */
1812 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1813 InitializeListHead(&LdrpDllNotificationList);
1814
1815 /* For old executables, use 16-byte aligned heap */
1816 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1817 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1818 {
1819 HeapFlags |= HEAP_CREATE_ALIGN_16;
1820 }
1821
1822 /* Setup the Heap */
1823 RtlInitializeHeapManager();
1824 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1825 NULL,
1826 NtHeader->OptionalHeader.SizeOfHeapReserve,
1827 NtHeader->OptionalHeader.SizeOfHeapCommit,
1828 NULL,
1829 &HeapParameters);
1830
1831 if (!Peb->ProcessHeap)
1832 {
1833 DPRINT1("Failed to create process heap\n");
1834 return STATUS_NO_MEMORY;
1835 }
1836
1837 /* Allocate an Activation Context Stack */
1838 Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
1839 if (!NT_SUCCESS(Status)) return Status;
1840
1841 // FIXME: Loader private heap is missing
1842 //DPRINT1("Loader private heap is missing\n");
1843
1844 /* Check for Debug Heap */
1845 if (OptionsKey)
1846 {
1847 /* Query the setting */
1848 Status = LdrQueryImageFileKeyOption(OptionsKey,
1849 L"DebugProcessHeapOnly",
1850 REG_DWORD,
1851 &DebugProcessHeapOnly,
1852 sizeof(ULONG),
1853 NULL);
1854
1855 if (NT_SUCCESS(Status))
1856 {
1857 /* Reset DPH if requested */
1858 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1859 {
1860 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
1861 RtlpPageHeapEnabled = FALSE;
1862 }
1863 }
1864 }
1865
1866 /* Build the NTDLL Path */
1867 FullPath.Buffer = StringBuffer;
1868 FullPath.Length = 0;
1869 FullPath.MaximumLength = sizeof(StringBuffer);
1870 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1871 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1872 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1873
1874 /* Open the Known DLLs directory */
1875 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1876 InitializeObjectAttributes(&ObjectAttributes,
1877 &KnownDllString,
1878 OBJ_CASE_INSENSITIVE,
1879 NULL,
1880 NULL);
1881 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1882 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1883 &ObjectAttributes);
1884
1885 /* Check if it exists */
1886 if (NT_SUCCESS(Status))
1887 {
1888 /* Open the Known DLLs Path */
1889 RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1890 InitializeObjectAttributes(&ObjectAttributes,
1891 &KnownDllString,
1892 OBJ_CASE_INSENSITIVE,
1893 LdrpKnownDllObjectDirectory,
1894 NULL);
1895 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1896 SYMBOLIC_LINK_QUERY,
1897 &ObjectAttributes);
1898 if (NT_SUCCESS(Status))
1899 {
1900 /* Query the path */
1901 LdrpKnownDllPath.Length = 0;
1902 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1903 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1904 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1905 NtClose(SymLinkHandle);
1906 if (!NT_SUCCESS(Status))
1907 {
1908 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1909 return Status;
1910 }
1911 }
1912 }
1913
1914 /* Check if we failed */
1915 if (!NT_SUCCESS(Status))
1916 {
1917 /* Assume System32 */
1918 LdrpKnownDllObjectDirectory = NULL;
1919 RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1920 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1921 }
1922
1923 /* If we have process parameters, get the default path and current path */
1924 if (ProcessParameters)
1925 {
1926 /* Check if we have a Dll Path */
1927 if (ProcessParameters->DllPath.Length)
1928 {
1929 /* Get the path */
1930 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1931 }
1932 else
1933 {
1934 /* We need a valid path */
1935 DPRINT1("No valid DllPath was given!\n");
1936 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1937 }
1938
1939 /* Set the current directory */
1940 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1941
1942 /* Check if it's empty or invalid */
1943 if ((!CurrentDirectory.Buffer) ||
1944 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1945 (!CurrentDirectory.Length))
1946 {
1947 /* Allocate space for the buffer */
1948 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1949 0,
1950 3 * sizeof(WCHAR) +
1951 sizeof(UNICODE_NULL));
1952 if (!CurrentDirectory.Buffer)
1953 {
1954 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1955 // FIXME: And what?
1956 }
1957
1958 /* Copy the drive of the system root */
1959 RtlMoveMemory(CurrentDirectory.Buffer,
1960 SharedUserData->NtSystemRoot,
1961 3 * sizeof(WCHAR));
1962 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1963 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1964 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1965
1966 FreeCurDir = TRUE;
1967 DPRINT("Using dynamically allocd curdir\n");
1968 }
1969 else
1970 {
1971 /* Use the local buffer */
1972 DPRINT("Using local system root\n");
1973 }
1974 }
1975
1976 /* Setup Loader Data */
1977 Peb->Ldr = &PebLdr;
1978 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1979 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1980 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1981 PebLdr.Length = sizeof(PEB_LDR_DATA);
1982 PebLdr.Initialized = TRUE;
1983
1984 /* Allocate a data entry for the Image */
1985 LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1986
1987 /* Set it up */
1988 LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
1989 LdrpImageEntry->LoadCount = -1;
1990 LdrpImageEntry->EntryPointActivationContext = 0;
1991 LdrpImageEntry->FullDllName = ImageFileName;
1992
1993 if (IsDotNetImage)
1994 LdrpImageEntry->Flags = LDRP_COR_IMAGE;
1995 else
1996 LdrpImageEntry->Flags = 0;
1997
1998 /* Check if the name is empty */
1999 if (!ImageFileName.Buffer[0])
2000 {
2001 /* Use the same Base name */
2002 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2003 }
2004 else
2005 {
2006 /* Find the last slash */
2007 Current = ImageFileName.Buffer;
2008 while (*Current)
2009 {
2010 if (*Current++ == '\\')
2011 {
2012 /* Set this path */
2013 NtDllName = Current;
2014 }
2015 }
2016
2017 /* Did we find anything? */
2018 if (!NtDllName)
2019 {
2020 /* Use the same Base name */
2021 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2022 }
2023 else
2024 {
2025 /* Setup the name */
2026 LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2027 LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2028 LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2029 (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2030 }
2031 }
2032
2033 /* Processing done, insert it */
2034 LdrpInsertMemoryTableEntry(LdrpImageEntry);
2035 LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2036
2037 /* Now add an entry for NTDLL */
2038 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2039 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2040 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2041 NtLdrEntry->LoadCount = -1;
2042 NtLdrEntry->EntryPointActivationContext = 0;
2043
2044 NtLdrEntry->FullDllName.Length = FullPath.Length;
2045 NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2046 NtLdrEntry->FullDllName.Buffer = StringBuffer;
2047 RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2048
2049 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2050 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2051 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2052
2053 /* Processing done, insert it */
2054 LdrpNtDllDataTableEntry = NtLdrEntry;
2055 LdrpInsertMemoryTableEntry(NtLdrEntry);
2056
2057 /* Let the world know */
2058 if (ShowSnaps)
2059 {
2060 DPRINT1("LDR: NEW PROCESS\n");
2061 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2062 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
2063 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
2064 }
2065
2066 /* Link the Init Order List */
2067 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2068 &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2069
2070 /* Initialize Wine's active context implementation for the current process */
2071 actctx_init();
2072
2073 /* ReactOS specific */
2074 LdrpInitializeProcessCompat(&OldShimData);
2075
2076 /* Set the current directory */
2077 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2078 if (!NT_SUCCESS(Status))
2079 {
2080 /* We failed, check if we should free it */
2081 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2082
2083 /* Set it to the NT Root */
2084 CurrentDirectory = NtSystemRoot;
2085 RtlSetCurrentDirectory_U(&CurrentDirectory);
2086 }
2087 else
2088 {
2089 /* We're done with it, free it */
2090 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2091 }
2092
2093 /* Check if we should look for a .local file */
2094 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
2095 {
2096 /* FIXME */
2097 DPRINT1("We don't support .local overrides yet\n");
2098 }
2099
2100 /* Check if the Application Verifier was enabled */
2101 if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2102 {
2103 Status = AVrfInitializeVerifier();
2104 if (!NT_SUCCESS(Status))
2105 {
2106 DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2107 return Status;
2108 }
2109
2110 }
2111
2112 if (IsDotNetImage)
2113 {
2114 /* FIXME */
2115 DPRINT1("We don't support .NET applications yet\n");
2116 }
2117
2118 /* FIXME: Load support for Terminal Services */
2119 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
2120 {
2121 /* Load kernel32 and call BasePostImportInit... */
2122 DPRINT("Unimplemented codepath!\n");
2123 }
2124
2125 /* Walk the IAT and load all the DLLs */
2126 ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2127
2128 /* Check if relocation is needed */
2129 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2130 {
2131 DPRINT1("LDR: Performing EXE relocation\n");
2132
2133 /* Change the protection to prepare for relocation */
2134 ViewBase = Peb->ImageBaseAddress;
2135 Status = LdrpSetProtection(ViewBase, FALSE);
2136 if (!NT_SUCCESS(Status)) return Status;
2137
2138 /* Do the relocation */
2139 Status = LdrRelocateImageWithBias(ViewBase,
2140 0LL,
2141 NULL,
2142 STATUS_SUCCESS,
2143 STATUS_CONFLICTING_ADDRESSES,
2144 STATUS_INVALID_IMAGE_FORMAT);
2145 if (!NT_SUCCESS(Status))
2146 {
2147 DPRINT1("LdrRelocateImageWithBias() failed\n");
2148 return Status;
2149 }
2150
2151 /* Check if a start context was provided */
2152 if (Context)
2153 {
2154 DPRINT1("WARNING: Relocated EXE Context");
2155 UNIMPLEMENTED; // We should support this
2156 return STATUS_INVALID_IMAGE_FORMAT;
2157 }
2158
2159 /* Restore the protection */
2160 Status = LdrpSetProtection(ViewBase, TRUE);
2161 if (!NT_SUCCESS(Status)) return Status;
2162 }
2163
2164 /* Lock the DLLs */
2165 ListHead = &Peb->Ldr->InLoadOrderModuleList;
2166 NextEntry = ListHead->Flink;
2167 while (ListHead != NextEntry)
2168 {
2169 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2170 NtLdrEntry->LoadCount = -1;
2171 NextEntry = NextEntry->Flink;
2172 }
2173
2174 /* Phase 0 is done */
2175 LdrpLdrDatabaseIsSetup = TRUE;
2176
2177 /* Check whether all static imports were properly loaded and return here */
2178 if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2179
2180 /* Initialize TLS */
2181 Status = LdrpInitializeTls();
2182 if (!NT_SUCCESS(Status))
2183 {
2184 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2185 Status);
2186 return Status;
2187 }
2188
2189 /* FIXME Mark the DLL Ranges for Stack Traces later */
2190
2191 /* Notify the debugger now */
2192 if (Peb->BeingDebugged)
2193 {
2194 /* Break */
2195 DbgBreakPoint();
2196
2197 /* Update show snaps again */
2198 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2199 }
2200
2201 /* Validate the Image for MP Usage */
2202 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2203
2204 /* Check NX Options */
2205 if (SharedUserData->NXSupportPolicy == 1)
2206 {
2207 ExecuteOptions = 0xD;
2208 }
2209 else if (!SharedUserData->NXSupportPolicy)
2210 {
2211 ExecuteOptions = 0xA;
2212 }
2213
2214 /* Let Mm know */
2215 ZwSetInformationProcess(NtCurrentProcess(),
2216 ProcessExecuteFlags,
2217 &ExecuteOptions,
2218 sizeof(ULONG));
2219
2220 // FIXME: Should be done by Application Compatibility features,
2221 // by reading the registry, etc...
2222 // For now, this is the old code from ntdll!RtlGetVersion().
2223 RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2224 if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2225 {
2226 WCHAR szCSDVersion[128];
2227 LONG i;
2228 ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
2229 i = _snwprintf(szCSDVersion, Length,
2230 L"Service Pack %d",
2231 ((Peb->OSCSDVersion >> 8) & 0xFF));
2232 if (i < 0)
2233 {
2234 /* Null-terminate if it was overflowed */
2235 szCSDVersion[Length] = UNICODE_NULL;
2236 }
2237
2238 Length *= sizeof(WCHAR);
2239 Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2240 0,
2241 Length + sizeof(UNICODE_NULL));
2242 if (Peb->CSDVersion.Buffer)
2243 {
2244 Peb->CSDVersion.Length = Length;
2245 Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2246
2247 RtlCopyMemory(Peb->CSDVersion.Buffer,
2248 szCSDVersion,
2249 Peb->CSDVersion.MaximumLength);
2250 Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2251 }
2252 }
2253
2254 /* Check if we had Shim Data */
2255 if (OldShimData)
2256 {
2257 /* Load the Shim Engine */
2258 Peb->AppCompatInfo = NULL;
2259 LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2260 }
2261 else
2262 {
2263 /* Check for Application Compatibility Goo */
2264 //LdrQueryApplicationCompatibilityGoo(hKey);
2265 DPRINT("Querying app compat hacks is missing!\n");
2266 }
2267
2268 /*
2269 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2270 * incompatible images.
2271 */
2272
2273 /* Now call the Init Routines */
2274 Status = LdrpRunInitializeRoutines(Context);
2275 if (!NT_SUCCESS(Status))
2276 {
2277 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2278 Status);
2279 return Status;
2280 }
2281
2282 /* Notify Shim Engine */
2283 if (g_ShimsEnabled)
2284 {
2285 VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2286 SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2287 SE_InstallAfterInit(&ImagePathName, OldShimData);
2288 }
2289
2290 /* Check if we have a user-defined Post Process Routine */
2291 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2292 {
2293 /* Call it */
2294 Peb->PostProcessInitRoutine();
2295 }
2296
2297 /* Close the key if we have one opened */
2298 if (OptionsKey) NtClose(OptionsKey);
2299
2300 /* Return status */
2301 return Status;
2302 }
2303
2304 VOID
2305 NTAPI
2306 LdrpInitFailure(NTSTATUS Status)
2307 {
2308 ULONG Response;
2309 PPEB Peb = NtCurrentPeb();
2310
2311 /* Print a debug message */
2312 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2313 &Peb->ProcessParameters->ImagePathName, Status);
2314
2315 /* Raise a hard error */
2316 if (!LdrpFatalHardErrorCount)
2317 {
2318 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2319 }
2320 }
2321
2322 VOID
2323 NTAPI
2324 LdrpInit(PCONTEXT Context,
2325 PVOID SystemArgument1,
2326 PVOID SystemArgument2)
2327 {
2328 LARGE_INTEGER Timeout;
2329 PTEB Teb = NtCurrentTeb();
2330 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2331 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2332 PPEB Peb = NtCurrentPeb();
2333
2334 DPRINT("LdrpInit() %p/%p\n",
2335 NtCurrentTeb()->RealClientId.UniqueProcess,
2336 NtCurrentTeb()->RealClientId.UniqueThread);
2337
2338 #ifdef _WIN64
2339 /* Set the SList header usage */
2340 RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2341 #endif /* _WIN64 */
2342
2343 /* Check if we have a deallocation stack */
2344 if (!Teb->DeallocationStack)
2345 {
2346 /* We don't, set one */
2347 Status = NtQueryVirtualMemory(NtCurrentProcess(),
2348 Teb->NtTib.StackLimit,
2349 MemoryBasicInformation,
2350 &MemoryBasicInfo,
2351 sizeof(MEMORY_BASIC_INFORMATION),
2352 NULL);
2353 if (!NT_SUCCESS(Status))
2354 {
2355 /* Fail */
2356 LdrpInitFailure(Status);
2357 RtlRaiseStatus(Status);
2358 return;
2359 }
2360
2361 /* Set the stack */
2362 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2363 }
2364
2365 /* Now check if the process is already being initialized */
2366 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2367 1,
2368 0) == 1)
2369 {
2370 /* Set the timeout to 30 milliseconds */
2371 Timeout.QuadPart = Int32x32To64(30, -10000);
2372
2373 /* Make sure the status hasn't changed */
2374 while (LdrpProcessInitialized == 1)
2375 {
2376 /* Do the wait */
2377 ZwDelayExecution(FALSE, &Timeout);
2378 }
2379 }
2380
2381 /* Check if we have already setup LDR data */
2382 if (!Peb->Ldr)
2383 {
2384 /* Setup the Loader Lock */
2385 Peb->LoaderLock = &LdrpLoaderLock;
2386
2387 /* Let other code know we're initializing */
2388 LdrpInLdrInit = TRUE;
2389
2390 /* Protect with SEH */
2391 _SEH2_TRY
2392 {
2393 /* Initialize the Process */
2394 LoaderStatus = LdrpInitializeProcess(Context,
2395 SystemArgument1);
2396
2397 /* Check for success and if MinimumStackCommit was requested */
2398 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2399 {
2400 /* Enforce the limit */
2401 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2402 UNIMPLEMENTED;
2403 }
2404 }
2405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2406 {
2407 /* Fail with the SEH error */
2408 LoaderStatus = _SEH2_GetExceptionCode();
2409 }
2410 _SEH2_END;
2411
2412 /* We're not initializing anymore */
2413 LdrpInLdrInit = FALSE;
2414
2415 /* Check if init worked */
2416 if (NT_SUCCESS(LoaderStatus))
2417 {
2418 /* Set the process as Initialized */
2419 _InterlockedIncrement(&LdrpProcessInitialized);
2420 }
2421 }
2422 else
2423 {
2424 /* Loader data is there... is this a fork() ? */
2425 if(Peb->InheritedAddressSpace)
2426 {
2427 /* Handle the fork() */
2428 //LoaderStatus = LdrpForkProcess();
2429 LoaderStatus = STATUS_NOT_IMPLEMENTED;
2430 UNIMPLEMENTED;
2431 }
2432 else
2433 {
2434 /* This is a new thread initializing */
2435 LdrpInitializeThread(Context);
2436 }
2437 }
2438
2439 /* All done, test alert the thread */
2440 NtTestAlert();
2441
2442 /* Return */
2443 if (!NT_SUCCESS(LoaderStatus))
2444 {
2445 /* Fail */
2446 LdrpInitFailure(LoaderStatus);
2447 RtlRaiseStatus(LoaderStatus);
2448 }
2449 }
2450
2451 /* EOF */