1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * ReactOS Portable Systems Group
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define MODULE_INVOLVED_IN_ARM3
17 #include <mm/ARM3/miarm.h>
18
19 /* GLOBALS ********************************************************************/
20
21 LIST_ENTRY PsLoadedModuleList;
22 LIST_ENTRY MmLoadedUserImageList;
23 KSPIN_LOCK PsLoadedModuleSpinLock;
24 ERESOURCE PsLoadedModuleResource;
25 ULONG_PTR PsNtosImageBase;
26 KMUTANT MmSystemLoadLock;
27
28 PFN_NUMBER MmTotalSystemDriverPages;
29
30 PVOID MmUnloadedDrivers;
31 PVOID MmLastUnloadedDrivers;
32
33 BOOLEAN MmMakeLowMemory;
34 BOOLEAN MmEnforceWriteProtection = TRUE;
35
36 PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte;
37 ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
38 ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
39
40 #ifdef _WIN64
41 #define COOKIE_MAX 0x0000FFFFFFFFFFFFll
42 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
43 #else
44 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
45 #endif
46
47 /* FUNCTIONS ******************************************************************/
48
49 PVOID
50 NTAPI
MiCacheImageSymbols(IN PVOID BaseAddress)51 MiCacheImageSymbols(IN PVOID BaseAddress)
52 {
53 ULONG DebugSize;
54 PVOID DebugDirectory = NULL;
55 PAGED_CODE();
56
57 /* Make sure it's safe to access the image */
58 _SEH2_TRY
59 {
60 /* Get the debug directory */
61 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
62 TRUE,
63 IMAGE_DIRECTORY_ENTRY_DEBUG,
64 &DebugSize);
65 }
66 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
67 {
68 /* Nothing */
69 }
70 _SEH2_END;
71
72 /* Return the directory */
73 return DebugDirectory;
74 }
75
76 NTSTATUS
77 NTAPI
MiLoadImageSection(_Inout_ PSECTION * SectionPtr,_Out_ PVOID * ImageBase,_In_ PUNICODE_STRING FileName,_In_ BOOLEAN SessionLoad,_In_ PLDR_DATA_TABLE_ENTRY LdrEntry)78 MiLoadImageSection(_Inout_ PSECTION *SectionPtr,
79 _Out_ PVOID *ImageBase,
80 _In_ PUNICODE_STRING FileName,
81 _In_ BOOLEAN SessionLoad,
82 _In_ PLDR_DATA_TABLE_ENTRY LdrEntry)
83 {
84 PSECTION Section = *SectionPtr;
85 NTSTATUS Status;
86 PEPROCESS Process;
87 PVOID Base = NULL;
88 SIZE_T ViewSize = 0;
89 KAPC_STATE ApcState;
90 LARGE_INTEGER SectionOffset = {{0, 0}};
91 BOOLEAN LoadSymbols = FALSE;
92 PFN_COUNT PteCount;
93 PMMPTE PointerPte, LastPte;
94 PVOID DriverBase;
95 MMPTE TempPte;
96 KIRQL OldIrql;
97 PFN_NUMBER PageFrameIndex;
98 PAGED_CODE();
99
100 /* Detect session load */
101 if (SessionLoad)
102 {
103 /* Fail */
104 UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
105 return STATUS_NOT_IMPLEMENTED;
106 }
107
108 /* Not session load, shouldn't have an entry */
109 ASSERT(LdrEntry == NULL);
110
111 /* Attach to the system process */
112 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
113
114 /* Check if we need to load symbols */
115 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
116 {
117 /* Yes we do */
118 LoadSymbols = TRUE;
119 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
120 }
121
122 /* Map the driver */
123 Process = PsGetCurrentProcess();
124 Status = MmMapViewOfSection(Section,
125 Process,
126 &Base,
127 0,
128 0,
129 &SectionOffset,
130 &ViewSize,
131 ViewUnmap,
132 0,
133 PAGE_EXECUTE);
134
135 /* Re-enable the flag */
136 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
137
138 /* Check if we failed with distinguished status code */
139 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
140 {
141 /* Change it to something more generic */
142 Status = STATUS_INVALID_IMAGE_FORMAT;
143 }
144
145 /* Now check if we failed */
146 if (!NT_SUCCESS(Status))
147 {
148 /* Detach and return */
149 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status);
150 KeUnstackDetachProcess(&ApcState);
151 return Status;
152 }
153
154 /* Reserve system PTEs needed */
155 PteCount = ROUND_TO_PAGES(((PMM_IMAGE_SECTION_OBJECT)Section->Segment)->ImageInformation.ImageFileSize) >> PAGE_SHIFT;
156 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
157 if (!PointerPte)
158 {
159 DPRINT1("MiReserveSystemPtes failed\n");
160 KeUnstackDetachProcess(&ApcState);
161 return STATUS_INSUFFICIENT_RESOURCES;
162 }
163
164 /* New driver base */
165 LastPte = PointerPte + PteCount;
166 DriverBase = MiPteToAddress(PointerPte);
167
168 /* The driver is here */
169 *ImageBase = DriverBase;
170 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount);
171
172 /* Lock the PFN database */
173 OldIrql = MiAcquirePfnLock();
174
175 /* Loop the new driver PTEs */
176 TempPte = ValidKernelPte;
177 while (PointerPte < LastPte)
178 {
179 /* Make sure the PTE is not valid for whatever reason */
180 ASSERT(PointerPte->u.Hard.Valid == 0);
181
182 /* Some debug stuff */
183 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
184 #if MI_TRACE_PFNS
185 MI_SET_PROCESS_USTR(FileName);
186 #endif
187
188 /* Grab a page */
189 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
190
191 /* Initialize its PFN entry */
192 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
193
194 /* Write the PTE */
195 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
196 MI_WRITE_VALID_PTE(PointerPte, TempPte);
197
198 /* Move on */
199 PointerPte++;
200 }
201
202 /* Release the PFN lock */
203 MiReleasePfnLock(OldIrql);
204
205 /* Copy the image */
206 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
207
208 /* Now unmap the view */
209 Status = MmUnmapViewOfSection(Process, Base);
210 ASSERT(NT_SUCCESS(Status));
211
212 /* Detach and return status */
213 KeUnstackDetachProcess(&ApcState);
214 return Status;
215 }
216
217 #ifndef RVA
218 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
219 #endif
220
221 USHORT
222 NTAPI
NameToOrdinal(_In_ PCSTR ExportName,_In_ PVOID ImageBase,_In_ ULONG NumberOfNames,_In_ PULONG NameTable,_In_ PUSHORT OrdinalTable)223 NameToOrdinal(
224 _In_ PCSTR ExportName,
225 _In_ PVOID ImageBase,
226 _In_ ULONG NumberOfNames,
227 _In_ PULONG NameTable,
228 _In_ PUSHORT OrdinalTable)
229 {
230 LONG Low, Mid, High, Ret;
231
232 /* Fail if no names */
233 if (!NumberOfNames)
234 return -1;
235
236 /* Do a binary search */
237 Low = Mid = 0;
238 High = NumberOfNames - 1;
239 while (High >= Low)
240 {
241 /* Get new middle value */
242 Mid = (Low + High) >> 1;
243
244 /* Compare name */
245 Ret = strcmp(ExportName, (PCHAR)RVA(ImageBase, NameTable[Mid]));
246 if (Ret < 0)
247 {
248 /* Update high */
249 High = Mid - 1;
250 }
251 else if (Ret > 0)
252 {
253 /* Update low */
254 Low = Mid + 1;
255 }
256 else
257 {
258 /* We got it */
259 break;
260 }
261 }
262
263 /* Check if we couldn't find it */
264 if (High < Low)
265 return -1;
266
267 /* Otherwise, this is the ordinal */
268 return OrdinalTable[Mid];
269 }
270
271 /**
272 * @brief
273 * ReactOS-only helper routine for RtlFindExportedRoutineByName(),
274 * that provides a finer granularity regarding the nature of the
275 * export, and the failure reasons.
276 *
277 * @param[in] ImageBase
278 * The base address of the loaded image.
279 *
280 * @param[in] ExportName
281 * The name of the export, given as an ANSI NULL-terminated string.
282 *
283 * @param[out] Function
284 * The address of the named exported routine, or NULL if not found.
285 * If the export is a forwarder (see @p IsForwarder below), this
286 * address points to the forwarder name.
287 *
288 * @param[out] IsForwarder
289 * An optional pointer to a BOOLEAN variable, that is set to TRUE
290 * if the found export is a forwarder, and FALSE otherwise.
291 *
292 * @param[in] NotFoundStatus
293 * The status code to return in case the export could not be found
294 * (examples: STATUS_ENTRYPOINT_NOT_FOUND, STATUS_PROCEDURE_NOT_FOUND).
295 *
296 * @return
297 * A status code as follows:
298 * - STATUS_SUCCESS if the named exported routine is found;
299 * - The custom @p NotFoundStatus if the export could not be found;
300 * - STATUS_INVALID_PARAMETER if the image is invalid or does not
301 * contain an Export Directory.
302 *
303 * @note
304 * See RtlFindExportedRoutineByName() for more remarks.
305 * Used by psmgr.c PspLookupSystemDllEntryPoint() as well.
306 **/
307 NTSTATUS
308 NTAPI
RtlpFindExportedRoutineByName(_In_ PVOID ImageBase,_In_ PCSTR ExportName,_Out_ PVOID * Function,_Out_opt_ PBOOLEAN IsForwarder,_In_ NTSTATUS NotFoundStatus)309 RtlpFindExportedRoutineByName(
310 _In_ PVOID ImageBase,
311 _In_ PCSTR ExportName,
312 _Out_ PVOID* Function,
313 _Out_opt_ PBOOLEAN IsForwarder,
314 _In_ NTSTATUS NotFoundStatus)
315 {
316 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
317 PULONG NameTable;
318 PUSHORT OrdinalTable;
319 ULONG ExportSize;
320 USHORT Ordinal;
321 PULONG ExportTable;
322 ULONG_PTR FunctionAddress;
323
324 PAGED_CODE();
325
326 /* Get the export directory */
327 ExportDirectory = RtlImageDirectoryEntryToData(ImageBase,
328 TRUE,
329 IMAGE_DIRECTORY_ENTRY_EXPORT,
330 &ExportSize);
331 if (!ExportDirectory)
332 return STATUS_INVALID_PARAMETER;
333
334 /* Setup name tables */
335 NameTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfNames);
336 OrdinalTable = (PUSHORT)RVA(ImageBase, ExportDirectory->AddressOfNameOrdinals);
337
338 /* Get the ordinal */
339 Ordinal = NameToOrdinal(ExportName,
340 ImageBase,
341 ExportDirectory->NumberOfNames,
342 NameTable,
343 OrdinalTable);
344
345 /* Check if we couldn't find it */
346 if (Ordinal == -1)
347 return NotFoundStatus;
348
349 /* Validate the ordinal */
350 if (Ordinal >= ExportDirectory->NumberOfFunctions)
351 return NotFoundStatus;
352
353 /* Resolve the function's address */
354 ExportTable = (PULONG)RVA(ImageBase, ExportDirectory->AddressOfFunctions);
355 FunctionAddress = (ULONG_PTR)RVA(ImageBase, ExportTable[Ordinal]);
356
357 /* Check if the function is actually a forwarder */
358 if (IsForwarder)
359 {
360 *IsForwarder = FALSE;
361 if ((FunctionAddress > (ULONG_PTR)ExportDirectory) &&
362 (FunctionAddress < (ULONG_PTR)ExportDirectory + ExportSize))
363 {
364 /* It is, and points to the forwarder name */
365 *IsForwarder = TRUE;
366 }
367 }
368
369 /* We've found it */
370 *Function = (PVOID)FunctionAddress;
371 return STATUS_SUCCESS;
372 }
373
374 /**
375 * @brief
376 * Finds the address of a given named exported routine in a loaded image.
377 * Note that this function does not support forwarders.
378 *
379 * @param[in] ImageBase
380 * The base address of the loaded image.
381 *
382 * @param[in] ExportName
383 * The name of the export, given as an ANSI NULL-terminated string.
384 *
385 * @return
386 * The address of the named exported routine, or NULL if not found.
387 * If the export is a forwarder, this function returns NULL as well.
388 *
389 * @note
390 * This routine was originally named MiLocateExportName(), with a separate
391 * duplicated MiFindExportedRoutineByName() one (taking a PANSI_STRING)
392 * on Windows <= 2003. Both routines have been then merged and renamed
393 * to MiFindExportedRoutineByName() on Windows 8 (taking a PCSTR instead),
394 * and finally renamed and exported as RtlFindExportedRoutineByName() on
395 * Windows 10.
396 *
397 * @see https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/sysload/mmgetsystemroutineaddress.htm
398 **/
399 PVOID
400 NTAPI
RtlFindExportedRoutineByName(_In_ PVOID ImageBase,_In_ PCSTR ExportName)401 RtlFindExportedRoutineByName(
402 _In_ PVOID ImageBase,
403 _In_ PCSTR ExportName)
404 {
405 NTSTATUS Status;
406 BOOLEAN IsForwarder = FALSE;
407 PVOID Function;
408
409 PAGED_CODE();
410
411 /* Call the internal API */
412 Status = RtlpFindExportedRoutineByName(ImageBase,
413 ExportName,
414 &Function,
415 &IsForwarder,
416 STATUS_ENTRYPOINT_NOT_FOUND);
417 if (!NT_SUCCESS(Status))
418 return NULL;
419
420 /* If the export is actually a forwarder, log the error and fail */
421 if (IsForwarder)
422 {
423 DPRINT1("RtlFindExportedRoutineByName does not support forwarders!\n", FALSE);
424 return NULL;
425 }
426
427 /* We've found the export */
428 return Function;
429 }
430
431 NTSTATUS
432 NTAPI
MmCallDllInitialize(_In_ PLDR_DATA_TABLE_ENTRY LdrEntry,_In_ PLIST_ENTRY ModuleListHead)433 MmCallDllInitialize(
434 _In_ PLDR_DATA_TABLE_ENTRY LdrEntry,
435 _In_ PLIST_ENTRY ModuleListHead)
436 {
437 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
438 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
439 PMM_DLL_INITIALIZE DllInit;
440 UNICODE_STRING RegPath, ImportName;
441 PCWCH Extension;
442 NTSTATUS Status;
443
444 PAGED_CODE();
445
446 /* Try to see if the image exports a DllInitialize routine */
447 DllInit = (PMM_DLL_INITIALIZE)
448 RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllInitialize");
449 if (!DllInit)
450 return STATUS_SUCCESS;
451
452 /* Make a temporary copy of BaseDllName because we will alter its length */
453 ImportName.Length = LdrEntry->BaseDllName.Length;
454 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
455 ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
456
457 /* Obtain the path to this dll's service in the registry */
458 RegPath.MaximumLength = ServicesKeyName.Length +
459 ImportName.Length + sizeof(UNICODE_NULL);
460 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
461 RegPath.MaximumLength,
462 TAG_LDR_WSTR);
463
464 /* Check if this allocation was unsuccessful */
465 if (!RegPath.Buffer)
466 return STATUS_INSUFFICIENT_RESOURCES;
467
468 /* Build and append the service name itself */
469 RegPath.Length = ServicesKeyName.Length;
470 RtlCopyMemory(RegPath.Buffer,
471 ServicesKeyName.Buffer,
472 ServicesKeyName.Length);
473
474 /* If the filename has an extension, remove it */
475 Extension = wcschr(ImportName.Buffer, L'.');
476 if (Extension)
477 ImportName.Length = (USHORT)(Extension - ImportName.Buffer) * sizeof(WCHAR);
478
479 /* Append the service name (base name without extension) */
480 RtlAppendUnicodeStringToString(&RegPath, &ImportName);
481
482 /* Now call DllInitialize */
483 DPRINT("Calling DllInit(%wZ)\n", &RegPath);
484 Status = DllInit(&RegPath);
485
486 /* Clean up */
487 ExFreePoolWithTag(RegPath.Buffer, TAG_LDR_WSTR);
488
489 // TODO: This is for Driver Verifier support.
490 UNREFERENCED_PARAMETER(ModuleListHead);
491
492 /* Return the DllInitialize status value */
493 return Status;
494 }
495
496 BOOLEAN
MiCallDllUnloadAndUnloadDll(_In_ PLDR_DATA_TABLE_ENTRY LdrEntry)497 MiCallDllUnloadAndUnloadDll(
498 _In_ PLDR_DATA_TABLE_ENTRY LdrEntry)
499 {
500 NTSTATUS Status;
501 PMM_DLL_UNLOAD DllUnload;
502
503 PAGED_CODE();
504
505 /* Retrieve the DllUnload routine */
506 DllUnload = (PMM_DLL_UNLOAD)
507 RtlFindExportedRoutineByName(LdrEntry->DllBase, "DllUnload");
508 if (!DllUnload)
509 return FALSE;
510
511 /* Call it and check for success */
512 Status = DllUnload();
513 if (!NT_SUCCESS(Status))
514 return FALSE;
515
516 /* Lie about the load count so we can unload the image */
517 ASSERT(LdrEntry->LoadCount == 0);
518 LdrEntry->LoadCount = 1;
519
520 /* Unload it */
521 MmUnloadSystemImage(LdrEntry);
522 return TRUE;
523 }
524
525 NTSTATUS
526 NTAPI
MiDereferenceImports(IN PLOAD_IMPORTS ImportList)527 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
528 {
529 SIZE_T i;
530 LOAD_IMPORTS SingleEntry;
531 PLDR_DATA_TABLE_ENTRY LdrEntry;
532 PVOID CurrentImports;
533 PAGED_CODE();
534
535 /* Check if there's no imports or if we're a boot driver */
536 if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
537 (ImportList == MM_SYSLDR_BOOT_LOADED) ||
538 (ImportList->Count == 0))
539 {
540 /* Then there's nothing to do */
541 return STATUS_SUCCESS;
542 }
543
544 /* Check for single-entry */
545 if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
546 {
547 /* Set it up */
548 SingleEntry.Count = 1;
549 SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY);
550
551 /* Use this as the import list */
552 ImportList = &SingleEntry;
553 }
554
555 /* Loop the import list */
556 for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
557 {
558 /* Get the entry */
559 LdrEntry = ImportList->Entry[i];
560 DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName);
561
562 /* Skip boot loaded images */
563 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
564
565 /* Dereference the entry */
566 ASSERT(LdrEntry->LoadCount >= 1);
567 if (!--LdrEntry->LoadCount)
568 {
569 /* Save the import data in case unload fails */
570 CurrentImports = LdrEntry->LoadedImports;
571
572 /* This is the last entry */
573 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
574 if (MiCallDllUnloadAndUnloadDll(LdrEntry))
575 {
576 /* Unloading worked, parse this DLL's imports too */
577 MiDereferenceImports(CurrentImports);
578
579 /* Check if we had valid imports */
580 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) &&
581 (CurrentImports != MM_SYSLDR_NO_IMPORTS) &&
582 !((ULONG_PTR)CurrentImports & MM_SYSLDR_SINGLE_ENTRY))
583 {
584 /* Free them */
585 ExFreePoolWithTag(CurrentImports, TAG_LDR_IMPORTS);
586 }
587 }
588 else
589 {
590 /* Unload failed, restore imports */
591 LdrEntry->LoadedImports = CurrentImports;
592 }
593 }
594 }
595
596 /* Done */
597 return STATUS_SUCCESS;
598 }
599
600 VOID
601 NTAPI
MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)602 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
603 {
604 PAGED_CODE();
605
606 /* Check if there's no imports or we're a boot driver or only one entry */
607 if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
608 (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
609 ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
610 {
611 /* Nothing to do */
612 return;
613 }
614
615 /* Otherwise, free the import list */
616 ExFreePoolWithTag(LdrEntry->LoadedImports, TAG_LDR_IMPORTS);
617 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
618 }
619
620 VOID
621 NTAPI
MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,IN BOOLEAN Insert)622 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
623 IN BOOLEAN Insert)
624 {
625 KIRQL OldIrql;
626
627 /* Acquire module list lock */
628 KeEnterCriticalRegion();
629 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
630
631 /* Acquire the spinlock too as we will insert or remove the entry */
632 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
633
634 /* Insert or remove from the list */
635 if (Insert)
636 InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks);
637 else
638 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
639
640 /* Release locks */
641 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
642 ExReleaseResourceLite(&PsLoadedModuleResource);
643 KeLeaveCriticalRegion();
644 }
645
646 CODE_SEG("INIT")
647 VOID
648 NTAPI
MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,IN PVOID OldBase,IN PVOID NewBase,IN ULONG Size)649 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
650 IN PVOID OldBase,
651 IN PVOID NewBase,
652 IN ULONG Size)
653 {
654 ULONG_PTR OldBaseTop, Delta;
655 PLDR_DATA_TABLE_ENTRY LdrEntry;
656 PLIST_ENTRY NextEntry;
657 ULONG ImportSize;
658 //
659 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
660 // since a real version of Windows would fail at this point, but they seem
661 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
662 // a feature which isn't even used by Windows. Priorities, priorities...
663 // Please note that Microsoft WDK EULA and license prohibits using
664 // the information contained within it for the generation of "non-Windows"
665 // drivers, which is precisely what LD will generate, since an LD driver
666 // will not load on Windows.
667 //
668 #ifdef _WORKING_LINKER_
669 ULONG i;
670 #endif
671 PULONG_PTR ImageThunk;
672 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
673
674 /* Calculate the top and delta */
675 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
676 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
677
678 /* Loop the loader block */
679 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
680 NextEntry != &LoaderBlock->LoadOrderListHead;
681 NextEntry = NextEntry->Flink)
682 {
683 /* Get the loader entry */
684 LdrEntry = CONTAINING_RECORD(NextEntry,
685 LDR_DATA_TABLE_ENTRY,
686 InLoadOrderLinks);
687 #ifdef _WORKING_LINKER_
688 /* Get the IAT */
689 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
690 TRUE,
691 IMAGE_DIRECTORY_ENTRY_IAT,
692 &ImportSize);
693 if (!ImageThunk) continue;
694
695 /* Make sure we have an IAT */
696 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
697 for (i = 0; i < ImportSize; i++, ImageThunk++)
698 {
699 /* Check if it's within this module */
700 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
701 {
702 /* Relocate it */
703 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
704 ImageThunk, *ImageThunk, *ImageThunk + Delta);
705 *ImageThunk += Delta;
706 }
707 }
708 #else
709 /* Get the import table */
710 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
711 TRUE,
712 IMAGE_DIRECTORY_ENTRY_IMPORT,
713 &ImportSize);
714 if (!ImportDescriptor) continue;
715
716 /* Make sure we have an IAT */
717 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
718 while ((ImportDescriptor->Name) &&
719 (ImportDescriptor->OriginalFirstThunk))
720 {
721 /* Get the image thunk */
722 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
723 ImportDescriptor->FirstThunk);
724 while (*ImageThunk)
725 {
726 /* Check if it's within this module */
727 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
728 {
729 /* Relocate it */
730 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
731 ImageThunk, *ImageThunk, *ImageThunk + Delta);
732 *ImageThunk += Delta;
733 }
734
735 /* Go to the next thunk */
736 ImageThunk++;
737 }
738
739 /* Go to the next import */
740 ImportDescriptor++;
741 }
742 #endif
743 }
744 }
745
746 NTSTATUS
747 NTAPI
MiSnapThunk(IN PVOID DllBase,IN PVOID ImageBase,IN PIMAGE_THUNK_DATA Name,IN PIMAGE_THUNK_DATA Address,IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,IN ULONG ExportSize,IN BOOLEAN SnapForwarder,OUT PCHAR * MissingApi)748 MiSnapThunk(IN PVOID DllBase,
749 IN PVOID ImageBase,
750 IN PIMAGE_THUNK_DATA Name,
751 IN PIMAGE_THUNK_DATA Address,
752 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
753 IN ULONG ExportSize,
754 IN BOOLEAN SnapForwarder,
755 OUT PCHAR *MissingApi)
756 {
757 BOOLEAN IsOrdinal;
758 USHORT Ordinal;
759 PULONG NameTable;
760 PUSHORT OrdinalTable;
761 PIMAGE_IMPORT_BY_NAME NameImport;
762 USHORT Hint;
763 NTSTATUS Status;
764 PCHAR MissingForwarder;
765 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
766 PULONG ExportTable;
767 ANSI_STRING DllName;
768 UNICODE_STRING ForwarderName;
769 PLIST_ENTRY NextEntry;
770 PLDR_DATA_TABLE_ENTRY LdrEntry;
771 ULONG ForwardExportSize;
772 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
773 PIMAGE_IMPORT_BY_NAME ForwardName;
774 SIZE_T ForwardLength;
775 IMAGE_THUNK_DATA ForwardThunk;
776
777 PAGED_CODE();
778
779 /* Check if this is an ordinal */
780 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
781 if ((IsOrdinal) && !(SnapForwarder))
782 {
783 /* Get the ordinal number and set it as missing */
784 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
785 ExportDirectory->Base);
786 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
787 }
788 else
789 {
790 /* Get the VA if we don't have to snap */
791 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
792 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
793
794 /* Copy the procedure name */
795 RtlStringCbCopyA(*MissingApi,
796 MAXIMUM_FILENAME_LENGTH,
797 (PCHAR)NameImport->Name);
798
799 /* Setup name tables */
800 DPRINT("Import name: %s\n", NameImport->Name);
801 NameTable = (PULONG)((ULONG_PTR)DllBase +
802 ExportDirectory->AddressOfNames);
803 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
804 ExportDirectory->AddressOfNameOrdinals);
805
806 /* Get the hint and check if it's valid */
807 Hint = NameImport->Hint;
808 if ((Hint < ExportDirectory->NumberOfNames) &&
809 !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
810 {
811 /* We have a match, get the ordinal number from here */
812 Ordinal = OrdinalTable[Hint];
813 }
814 else
815 {
816 /* Do a binary search */
817 Ordinal = NameToOrdinal((PCHAR)NameImport->Name,
818 DllBase,
819 ExportDirectory->NumberOfNames,
820 NameTable,
821 OrdinalTable);
822
823 /* Check if we couldn't find it */
824 if (Ordinal == -1)
825 {
826 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport->Name);
827 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
828 }
829 }
830 }
831
832 /* Check if the ordinal is valid */
833 if (Ordinal >= ExportDirectory->NumberOfFunctions)
834 {
835 /* It's not, fail */
836 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
837 }
838 else
839 {
840 /* In case the forwarder is missing */
841 MissingForwarder = NameBuffer;
842
843 /* Resolve the address and write it */
844 ExportTable = (PULONG)((ULONG_PTR)DllBase +
845 ExportDirectory->AddressOfFunctions);
846 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
847
848 /* Assume success from now on */
849 Status = STATUS_SUCCESS;
850
851 /* Check if the function is actually a forwarder */
852 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
853 (Address->u1.Function < (ULONG_PTR)ExportDirectory + ExportSize))
854 {
855 /* Now assume failure in case the forwarder doesn't exist */
856 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
857
858 /* Build the forwarder name */
859 DllName.Buffer = (PCHAR)Address->u1.Function;
860 DllName.Length = (USHORT)(strchr(DllName.Buffer, '.') -
861 DllName.Buffer) +
862 sizeof(ANSI_NULL);
863 DllName.MaximumLength = DllName.Length;
864
865 /* Convert it */
866 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
867 &DllName,
868 TRUE)))
869 {
870 /* We failed, just return an error */
871 return Status;
872 }
873
874 /* Loop the module list */
875 NextEntry = PsLoadedModuleList.Flink;
876 while (NextEntry != &PsLoadedModuleList)
877 {
878 /* Get the loader entry */
879 LdrEntry = CONTAINING_RECORD(NextEntry,
880 LDR_DATA_TABLE_ENTRY,
881 InLoadOrderLinks);
882
883 /* Check if it matches */
884 if (RtlPrefixUnicodeString(&ForwarderName,
885 &LdrEntry->BaseDllName,
886 TRUE))
887 {
888 /* Get the forwarder export directory */
889 ForwardExportDirectory =
890 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
891 TRUE,
892 IMAGE_DIRECTORY_ENTRY_EXPORT,
893 &ForwardExportSize);
894 if (!ForwardExportDirectory) break;
895
896 /* Allocate a name entry */
897 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
898 sizeof(ANSI_NULL);
899 ForwardName = ExAllocatePoolWithTag(PagedPool,
900 sizeof(*ForwardName) +
901 ForwardLength,
902 TAG_LDR_WSTR);
903 if (!ForwardName) break;
904
905 /* Copy the data */
906 RtlCopyMemory(&ForwardName->Name[0],
907 DllName.Buffer + DllName.Length,
908 ForwardLength);
909 ForwardName->Hint = 0;
910
911 /* Set the new address */
912 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
913
914 /* Snap the forwarder */
915 Status = MiSnapThunk(LdrEntry->DllBase,
916 ImageBase,
917 &ForwardThunk,
918 &ForwardThunk,
919 ForwardExportDirectory,
920 ForwardExportSize,
921 TRUE,
922 &MissingForwarder);
923
924 /* Free the forwarder name and set the thunk */
925 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
926 Address->u1 = ForwardThunk.u1;
927 break;
928 }
929
930 /* Go to the next entry */
931 NextEntry = NextEntry->Flink;
932 }
933
934 /* Free the name */
935 RtlFreeUnicodeString(&ForwarderName);
936 }
937 }
938
939 /* Return status */
940 return Status;
941 }
942
943 NTSTATUS
944 NTAPI
MmUnloadSystemImage(IN PVOID ImageHandle)945 MmUnloadSystemImage(IN PVOID ImageHandle)
946 {
947 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
948 PVOID BaseAddress = LdrEntry->DllBase;
949 NTSTATUS Status;
950 STRING TempName;
951 BOOLEAN HadEntry = FALSE;
952
953 /* Acquire the loader lock */
954 KeEnterCriticalRegion();
955 KeWaitForSingleObject(&MmSystemLoadLock,
956 WrVirtualMemory,
957 KernelMode,
958 FALSE,
959 NULL);
960
961 /* Check if this driver was loaded at boot and didn't get imports parsed */
962 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done;
963
964 /* We should still be alive */
965 ASSERT(LdrEntry->LoadCount != 0);
966 LdrEntry->LoadCount--;
967
968 /* Check if we're still loaded */
969 if (LdrEntry->LoadCount) goto Done;
970
971 /* We should cleanup... are symbols loaded */
972 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
973 {
974 /* Create the ANSI name */
975 Status = RtlUnicodeStringToAnsiString(&TempName,
976 &LdrEntry->BaseDllName,
977 TRUE);
978 if (NT_SUCCESS(Status))
979 {
980 /* Unload the symbols */
981 DbgUnLoadImageSymbols(&TempName,
982 BaseAddress,
983 (ULONG_PTR)PsGetCurrentProcessId());
984 RtlFreeAnsiString(&TempName);
985 }
986 }
987
988 /* FIXME: Free the driver */
989 DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName);
990 //MmFreeSection(LdrEntry->DllBase);
991
992 /* Check if we're linked in */
993 if (LdrEntry->InLoadOrderLinks.Flink)
994 {
995 /* Remove us */
996 MiProcessLoaderEntry(LdrEntry, FALSE);
997 HadEntry = TRUE;
998 }
999
1000 /* Dereference and clear the imports */
1001 MiDereferenceImports(LdrEntry->LoadedImports);
1002 MiClearImports(LdrEntry);
1003
1004 /* Check if the entry needs to go away */
1005 if (HadEntry)
1006 {
1007 /* Check if it had a name */
1008 if (LdrEntry->FullDllName.Buffer)
1009 {
1010 /* Free it */
1011 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
1012 }
1013
1014 /* Check if we had a section */
1015 if (LdrEntry->SectionPointer)
1016 {
1017 /* Dereference it */
1018 ObDereferenceObject(LdrEntry->SectionPointer);
1019 }
1020
1021 /* Free the entry */
1022 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
1023 }
1024
1025 /* Release the system lock and return */
1026 Done:
1027 KeReleaseMutant(&MmSystemLoadLock, MUTANT_INCREMENT, FALSE, FALSE);
1028 KeLeaveCriticalRegion();
1029 return STATUS_SUCCESS;
1030 }
1031
1032 NTSTATUS
1033 NTAPI
MiResolveImageReferences(IN PVOID ImageBase,IN PUNICODE_STRING ImageFileDirectory,IN PUNICODE_STRING NamePrefix OPTIONAL,OUT PCHAR * MissingApi,OUT PWCHAR * MissingDriver,OUT PLOAD_IMPORTS * LoadImports)1034 MiResolveImageReferences(IN PVOID ImageBase,
1035 IN PUNICODE_STRING ImageFileDirectory,
1036 IN PUNICODE_STRING NamePrefix OPTIONAL,
1037 OUT PCHAR *MissingApi,
1038 OUT PWCHAR *MissingDriver,
1039 OUT PLOAD_IMPORTS *LoadImports)
1040 {
1041 static UNICODE_STRING DriversFolderName = RTL_CONSTANT_STRING(L"drivers\\");
1042 PCHAR MissingApiBuffer = *MissingApi, ImportName;
1043 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
1044 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
1045 PLOAD_IMPORTS LoadedImports, NewImports;
1046 ULONG i;
1047 BOOLEAN GdiLink, NormalLink;
1048 BOOLEAN ReferenceNeeded, Loaded;
1049 ANSI_STRING TempString;
1050 UNICODE_STRING NameString, DllName;
1051 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
1052 PVOID ImportBase, DllBase;
1053 PLIST_ENTRY NextEntry;
1054 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
1055 NTSTATUS Status;
1056 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
1057
1058 PAGED_CODE();
1059
1060 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1061 __FUNCTION__, ImageBase, ImageFileDirectory);
1062
1063 /* No name string buffer yet */
1064 NameString.Buffer = NULL;
1065
1066 /* Assume no imports */
1067 *LoadImports = MM_SYSLDR_NO_IMPORTS;
1068
1069 /* Get the import descriptor */
1070 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
1071 TRUE,
1072 IMAGE_DIRECTORY_ENTRY_IMPORT,
1073 &ImportSize);
1074 if (!ImportDescriptor) return STATUS_SUCCESS;
1075
1076 /* Loop all imports to count them */
1077 for (CurrentImport = ImportDescriptor;
1078 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
1079 CurrentImport++)
1080 {
1081 /* One more */
1082 ImportCount++;
1083 }
1084
1085 /* Make sure we have non-zero imports */
1086 if (ImportCount)
1087 {
1088 /* Calculate and allocate the list we'll need */
1089 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1090 LoadedImports = ExAllocatePoolWithTag(PagedPool,
1091 LoadedImportsSize,
1092 TAG_LDR_IMPORTS);
1093 if (LoadedImports)
1094 {
1095 /* Zero it */
1096 RtlZeroMemory(LoadedImports, LoadedImportsSize);
1097 LoadedImports->Count = ImportCount;
1098 }
1099 }
1100 else
1101 {
1102 /* No table */
1103 LoadedImports = NULL;
1104 }
1105
1106 /* Reset the import count and loop descriptors again */
1107 GdiLink = NormalLink = FALSE;
1108 ImportCount = 0;
1109 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
1110 {
1111 /* Get the name */
1112 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
1113
1114 /* Check if this is a GDI driver */
1115 GdiLink = GdiLink ||
1116 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
1117
1118 /* We can also allow dxapi (for Windows compat, allow IRT and coverage) */
1119 NormalLink = NormalLink ||
1120 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
1121 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) &&
1122 (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) &&
1123 (_strnicmp(ImportName, "irt", sizeof("irt") - 1)));
1124
1125 /* Check if this is a valid GDI driver */
1126 if (GdiLink && NormalLink)
1127 {
1128 /* It's not, it's importing stuff it shouldn't be! */
1129 Status = STATUS_PROCEDURE_NOT_FOUND;
1130 goto Failure;
1131 }
1132
1133 /* Check for user-mode printer or video card drivers, which don't belong */
1134 if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) ||
1135 !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) ||
1136 !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) ||
1137 !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) ||
1138 !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) ||
1139 !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
1140 {
1141 /* This is not kernel code */
1142 Status = STATUS_PROCEDURE_NOT_FOUND;
1143 goto Failure;
1144 }
1145
1146 /* Check if this is a "core" import, which doesn't get referenced */
1147 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1148 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
1149 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
1150 {
1151 /* Don't reference this */
1152 ReferenceNeeded = FALSE;
1153 }
1154 else
1155 {
1156 /* Reference these modules */
1157 ReferenceNeeded = TRUE;
1158 }
1159
1160 /* Now setup a unicode string for the import */
1161 RtlInitAnsiString(&TempString, ImportName);
1162 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
1163 if (!NT_SUCCESS(Status))
1164 {
1165 /* Failed */
1166 goto Failure;
1167 }
1168
1169 /* We don't support name prefixes yet */
1170 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
1171
1172 /* Remember that we haven't loaded the import at this point */
1173 CheckDllState:
1174 Loaded = FALSE;
1175 ImportBase = NULL;
1176
1177 /* Loop the driver list */
1178 NextEntry = PsLoadedModuleList.Flink;
1179 while (NextEntry != &PsLoadedModuleList)
1180 {
1181 /* Get the loader entry and compare the name */
1182 LdrEntry = CONTAINING_RECORD(NextEntry,
1183 LDR_DATA_TABLE_ENTRY,
1184 InLoadOrderLinks);
1185 if (RtlEqualUnicodeString(&NameString,
1186 &LdrEntry->BaseDllName,
1187 TRUE))
1188 {
1189 /* Get the base address */
1190 ImportBase = LdrEntry->DllBase;
1191
1192 /* Check if we haven't loaded yet, and we need references */
1193 if (!(Loaded) && (ReferenceNeeded))
1194 {
1195 /* Make sure we're not already loading */
1196 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1197 {
1198 /* Increase the load count */
1199 LdrEntry->LoadCount++;
1200 }
1201 }
1202
1203 /* Done, break out */
1204 break;
1205 }
1206
1207 /* Go to the next entry */
1208 NextEntry = NextEntry->Flink;
1209 }
1210
1211 /* Check if we haven't loaded the import yet */
1212 if (!ImportBase)
1213 {
1214 /* Setup the import DLL name */
1215 DllName.MaximumLength = NameString.Length +
1216 ImageFileDirectory->Length +
1217 sizeof(UNICODE_NULL);
1218 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1219 DllName.MaximumLength,
1220 TAG_LDR_WSTR);
1221 if (!DllName.Buffer)
1222 {
1223 /* We're out of resources */
1224 Status = STATUS_INSUFFICIENT_RESOURCES;
1225 goto Failure;
1226 }
1227
1228 /* Add the import name to the base directory */
1229 RtlCopyUnicodeString(&DllName, ImageFileDirectory);
1230 RtlAppendUnicodeStringToString(&DllName,
1231 &NameString);
1232
1233 /* Load the image */
1234 Status = MmLoadSystemImage(&DllName,
1235 NamePrefix,
1236 NULL,
1237 FALSE,
1238 (PVOID *)&DllEntry,
1239 &DllBase);
1240
1241 /* win32k / GDI drivers can also import from system32 folder */
1242 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) &&
1243 (MI_IS_SESSION_ADDRESS(ImageBase) || 1)) // HACK
1244 {
1245 /* Free the old name buffer */
1246 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
1247
1248 /* Calculate size for a string the adds 'drivers\' */
1249 DllName.MaximumLength += DriversFolderName.Length;
1250
1251 /* Allocate the new buffer */
1252 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1253 DllName.MaximumLength,
1254 TAG_LDR_WSTR);
1255 if (!DllName.Buffer)
1256 {
1257 /* We're out of resources */
1258 Status = STATUS_INSUFFICIENT_RESOURCES;
1259 goto Failure;
1260 }
1261
1262 /* Copy image directory and append 'drivers\' folder name */
1263 RtlCopyUnicodeString(&DllName, ImageFileDirectory);
1264 RtlAppendUnicodeStringToString(&DllName, &DriversFolderName);
1265
1266 /* Now add the import name */
1267 RtlAppendUnicodeStringToString(&DllName, &NameString);
1268
1269 /* Try once again to load the image */
1270 Status = MmLoadSystemImage(&DllName,
1271 NamePrefix,
1272 NULL,
1273 FALSE,
1274 (PVOID *)&DllEntry,
1275 &DllBase);
1276 }
1277
1278 if (!NT_SUCCESS(Status))
1279 {
1280 /* Fill out the information for the error */
1281 *MissingDriver = DllName.Buffer;
1282 *(PULONG)MissingDriver |= 1;
1283 *MissingApi = NULL;
1284
1285 DPRINT1("Failed to load dependency: %wZ\n", &DllName);
1286
1287 /* Don't free the name */
1288 DllName.Buffer = NULL;
1289
1290 /* Cleanup and return */
1291 goto Failure;
1292 }
1293
1294 /* We can free the DLL Name */
1295 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
1296 DllName.Buffer = NULL;
1297
1298 /* We're now loaded */
1299 Loaded = TRUE;
1300
1301 /* Sanity check */
1302 ASSERT(DllBase == DllEntry->DllBase);
1303
1304 /* Call the initialization routines */
1305 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1306 if (!NT_SUCCESS(Status))
1307 {
1308 /* We failed, unload the image */
1309 MmUnloadSystemImage(DllEntry);
1310 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status);
1311 Loaded = FALSE;
1312 }
1313
1314 /* Loop again to make sure that everything is OK */
1315 goto CheckDllState;
1316 }
1317
1318 /* Check if we're support to reference this import */
1319 if ((ReferenceNeeded) && (LoadedImports))
1320 {
1321 /* Make sure we're not already loading */
1322 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1323 {
1324 /* Add the entry */
1325 LoadedImports->Entry[ImportCount] = LdrEntry;
1326 ImportCount++;
1327 }
1328 }
1329
1330 /* Free the import name */
1331 RtlFreeUnicodeString(&NameString);
1332
1333 /* Set the missing driver name and get the export directory */
1334 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1335 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1336 TRUE,
1337 IMAGE_DIRECTORY_ENTRY_EXPORT,
1338 &ExportSize);
1339 if (!ExportDirectory)
1340 {
1341 /* Cleanup and return */
1342 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver);
1343 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1344 goto Failure;
1345 }
1346
1347 /* Make sure we have an IAT */
1348 if (ImportDescriptor->OriginalFirstThunk)
1349 {
1350 /* Get the first thunks */
1351 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1352 ImportDescriptor->OriginalFirstThunk);
1353 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1354 ImportDescriptor->FirstThunk);
1355
1356 /* Loop the IAT */
1357 while (OrigThunk->u1.AddressOfData)
1358 {
1359 /* Snap thunk */
1360 Status = MiSnapThunk(ImportBase,
1361 ImageBase,
1362 OrigThunk++,
1363 FirstThunk++,
1364 ExportDirectory,
1365 ExportSize,
1366 FALSE,
1367 MissingApi);
1368 if (!NT_SUCCESS(Status))
1369 {
1370 /* Cleanup and return */
1371 goto Failure;
1372 }
1373
1374 /* Reset the buffer */
1375 *MissingApi = MissingApiBuffer;
1376 }
1377 }
1378
1379 /* Go to the next import */
1380 ImportDescriptor++;
1381 }
1382
1383 /* Check if we have an import list */
1384 if (LoadedImports)
1385 {
1386 /* Reset the count again, and loop entries */
1387 ImportCount = 0;
1388 for (i = 0; i < LoadedImports->Count; i++)
1389 {
1390 if (LoadedImports->Entry[i])
1391 {
1392 /* Got an entry, OR it with 1 in case it's the single entry */
1393 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] |
1394 MM_SYSLDR_SINGLE_ENTRY);
1395 ImportCount++;
1396 }
1397 }
1398
1399 /* Check if we had no imports */
1400 if (!ImportCount)
1401 {
1402 /* Free the list and set it to no imports */
1403 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1404 LoadedImports = MM_SYSLDR_NO_IMPORTS;
1405 }
1406 else if (ImportCount == 1)
1407 {
1408 /* Just one entry, we can free the table and only use our entry */
1409 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1410 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1411 }
1412 else if (ImportCount != LoadedImports->Count)
1413 {
1414 /* Allocate a new list */
1415 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1416 NewImports = ExAllocatePoolWithTag(PagedPool,
1417 LoadedImportsSize,
1418 TAG_LDR_IMPORTS);
1419 if (NewImports)
1420 {
1421 /* Set count */
1422 NewImports->Count = 0;
1423
1424 /* Loop all the imports */
1425 for (i = 0; i < LoadedImports->Count; i++)
1426 {
1427 /* Make sure it's valid */
1428 if (LoadedImports->Entry[i])
1429 {
1430 /* Copy it */
1431 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1432 NewImports->Count++;
1433 }
1434 }
1435
1436 /* Free the old copy */
1437 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1438 LoadedImports = NewImports;
1439 }
1440 }
1441
1442 /* Return the list */
1443 *LoadImports = LoadedImports;
1444 }
1445
1446 /* Return success */
1447 return STATUS_SUCCESS;
1448
1449 Failure:
1450
1451 /* Cleanup and return */
1452 RtlFreeUnicodeString(&NameString);
1453
1454 if (LoadedImports)
1455 {
1456 MiDereferenceImports(LoadedImports);
1457 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1458 }
1459
1460 return Status;
1461 }
1462
1463 VOID
1464 NTAPI
MiFreeInitializationCode(IN PVOID InitStart,IN PVOID InitEnd)1465 MiFreeInitializationCode(IN PVOID InitStart,
1466 IN PVOID InitEnd)
1467 {
1468 PMMPTE PointerPte;
1469 PFN_NUMBER PagesFreed;
1470
1471 /* Get the start PTE */
1472 PointerPte = MiAddressToPte(InitStart);
1473 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart) == FALSE);
1474
1475 /* Compute the number of pages we expect to free */
1476 PagesFreed = (PFN_NUMBER)(MiAddressToPte(InitEnd) - PointerPte);
1477
1478 /* Try to actually free them */
1479 PagesFreed = MiDeleteSystemPageableVm(PointerPte,
1480 PagesFreed,
1481 0,
1482 NULL);
1483 }
1484
1485 CODE_SEG("INIT")
1486 VOID
1487 NTAPI
MiFindInitializationCode(OUT PVOID * StartVa,OUT PVOID * EndVa)1488 MiFindInitializationCode(OUT PVOID *StartVa,
1489 OUT PVOID *EndVa)
1490 {
1491 ULONG Size, SectionCount, Alignment;
1492 PLDR_DATA_TABLE_ENTRY LdrEntry;
1493 ULONG_PTR DllBase, InitStart, InitEnd, ImageEnd, InitCode;
1494 PLIST_ENTRY NextEntry;
1495 PIMAGE_NT_HEADERS NtHeader;
1496 PIMAGE_SECTION_HEADER Section, LastSection, InitSection;
1497 BOOLEAN InitFound;
1498 DBG_UNREFERENCED_LOCAL_VARIABLE(InitSection);
1499
1500 /* So we don't free our own code yet */
1501 InitCode = (ULONG_PTR)&MiFindInitializationCode;
1502
1503 /* Assume failure */
1504 *StartVa = NULL;
1505
1506 /* Acquire the necessary locks while we loop the list */
1507 KeEnterCriticalRegion();
1508 KeWaitForSingleObject(&MmSystemLoadLock,
1509 WrVirtualMemory,
1510 KernelMode,
1511 FALSE,
1512 NULL);
1513 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1514
1515 /* Loop all loaded modules */
1516 NextEntry = PsLoadedModuleList.Flink;
1517 while (NextEntry != &PsLoadedModuleList)
1518 {
1519 /* Get the loader entry and its DLL base */
1520 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1521 DllBase = (ULONG_PTR)LdrEntry->DllBase;
1522
1523 /* Only process boot loaded images. Other drivers are processed by
1524 MmFreeDriverInitialization */
1525 if (LdrEntry->Flags & LDRP_MM_LOADED)
1526 {
1527 /* Keep going */
1528 NextEntry = NextEntry->Flink;
1529 continue;
1530 }
1531
1532 /* Get the NT header */
1533 NtHeader = RtlImageNtHeader((PVOID)DllBase);
1534 if (!NtHeader)
1535 {
1536 /* Keep going */
1537 NextEntry = NextEntry->Flink;
1538 continue;
1539 }
1540
1541 /* Get the first section, the section count, and scan them all */
1542 Section = IMAGE_FIRST_SECTION(NtHeader);
1543 SectionCount = NtHeader->FileHeader.NumberOfSections;
1544 InitStart = 0;
1545 while (SectionCount > 0)
1546 {
1547 /* Assume failure */
1548 InitFound = FALSE;
1549
1550 /* Is this the INIT section or a discardable section? */
1551 if ((strncmp((PCCH)Section->Name, "INIT", 5) == 0) ||
1552 ((Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)))
1553 {
1554 /* Remember this */
1555 InitFound = TRUE;
1556 InitSection = Section;
1557 }
1558
1559 if (InitFound)
1560 {
1561 /* Pick the biggest size -- either raw or virtual */
1562 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
1563
1564 /* Read the section alignment */
1565 Alignment = NtHeader->OptionalHeader.SectionAlignment;
1566
1567 /* Get the start and end addresses */
1568 InitStart = DllBase + Section->VirtualAddress;
1569 InitEnd = ALIGN_UP_BY(InitStart + Size, Alignment);
1570
1571 /* Align the addresses to PAGE_SIZE */
1572 InitStart = ALIGN_UP_BY(InitStart, PAGE_SIZE);
1573 InitEnd = ALIGN_DOWN_BY(InitEnd, PAGE_SIZE);
1574
1575 /* Have we reached the last section? */
1576 if (SectionCount == 1)
1577 {
1578 /* Remember this */
1579 LastSection = Section;
1580 }
1581 else
1582 {
1583 /* We have not, loop all the sections */
1584 LastSection = NULL;
1585 do
1586 {
1587 /* Keep going until we find a non-discardable section range */
1588 SectionCount--;
1589 Section++;
1590 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
1591 {
1592 /* Discardable, so record it, then keep going */
1593 LastSection = Section;
1594 }
1595 else
1596 {
1597 /* Non-contigous discard flag, or no flag, break out */
1598 break;
1599 }
1600 }
1601 while (SectionCount > 1);
1602 }
1603
1604 /* Have we found a discardable or init section? */
1605 if (LastSection)
1606 {
1607 /* Pick the biggest size -- either raw or virtual */
1608 Size = max(LastSection->SizeOfRawData, LastSection->Misc.VirtualSize);
1609
1610 /* Use this as the end of the section address */
1611 InitEnd = DllBase + LastSection->VirtualAddress + Size;
1612
1613 /* Have we reached the last section yet? */
1614 if (SectionCount != 1)
1615 {
1616 /* Then align this accross the session boundary */
1617 InitEnd = ALIGN_UP_BY(InitEnd, Alignment);
1618 InitEnd = ALIGN_DOWN_BY(InitEnd, PAGE_SIZE);
1619 }
1620 }
1621
1622 /* Make sure we don't let the init section go past the image */
1623 ImageEnd = DllBase + LdrEntry->SizeOfImage;
1624 if (InitEnd > ImageEnd) InitEnd = ALIGN_UP_BY(ImageEnd, PAGE_SIZE);
1625
1626 /* Make sure we have a valid, non-zero init section */
1627 if (InitStart < InitEnd)
1628 {
1629 /* Make sure we are not within this code itself */
1630 if ((InitCode >= InitStart) && (InitCode < InitEnd))
1631 {
1632 /* Return it, we can't free ourselves now */
1633 ASSERT(*StartVa == 0);
1634 *StartVa = (PVOID)InitStart;
1635 *EndVa = (PVOID)InitEnd;
1636 }
1637 else
1638 {
1639 /* This isn't us -- go ahead and free it */
1640 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID)InitStart) == FALSE);
1641 DPRINT("Freeing init code: %p-%p ('%wZ' @%p : '%s')\n",
1642 (PVOID)InitStart,
1643 (PVOID)InitEnd,
1644 &LdrEntry->BaseDllName,
1645 LdrEntry->DllBase,
1646 InitSection->Name);
1647 MiFreeInitializationCode((PVOID)InitStart, (PVOID)InitEnd);
1648 }
1649 }
1650 }
1651
1652 /* Move to the next section */
1653 SectionCount--;
1654 Section++;
1655 }
1656
1657 /* Move to the next module */
1658 NextEntry = NextEntry->Flink;
1659 }
1660
1661 /* Release the locks and return */
1662 ExReleaseResourceLite(&PsLoadedModuleResource);
1663 KeReleaseMutant(&MmSystemLoadLock, MUTANT_INCREMENT, FALSE, FALSE);
1664 KeLeaveCriticalRegion();
1665 }
1666
1667 /*
1668 * Note: This function assumes that all discardable sections are at the end of
1669 * the PE file. It searches backwards until it finds the non-discardable section
1670 */
1671 VOID
1672 NTAPI
MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)1673 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
1674 {
1675 PMMPTE StartPte, EndPte;
1676 PFN_NUMBER PageCount;
1677 PVOID DllBase;
1678 ULONG i;
1679 PIMAGE_NT_HEADERS NtHeader;
1680 PIMAGE_SECTION_HEADER Section, DiscardSection;
1681
1682 /* Get the base address and the page count */
1683 DllBase = LdrEntry->DllBase;
1684 PageCount = LdrEntry->SizeOfImage >> PAGE_SHIFT;
1685
1686 /* Get the last PTE in this image */
1687 EndPte = MiAddressToPte(DllBase) + PageCount;
1688
1689 /* Get the NT header */
1690 NtHeader = RtlImageNtHeader(DllBase);
1691 if (!NtHeader) return;
1692
1693 /* Get the last section and loop each section backwards */
1694 Section = IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections;
1695 DiscardSection = NULL;
1696 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
1697 {
1698 /* Go back a section and check if it's discardable */
1699 Section--;
1700 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
1701 {
1702 /* It is, select it for freeing */
1703 DiscardSection = Section;
1704 }
1705 else
1706 {
1707 /* No more discardable sections exist, bail out */
1708 break;
1709 }
1710 }
1711
1712 /* Bail out if there's nothing to free */
1713 if (!DiscardSection) return;
1714
1715 /* Push the DLL base to the first disacrable section, and get its PTE */
1716 DllBase = (PVOID)ROUND_TO_PAGES((ULONG_PTR)DllBase + DiscardSection->VirtualAddress);
1717 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase) == FALSE);
1718 StartPte = MiAddressToPte(DllBase);
1719
1720 /* Check how many pages to free total */
1721 PageCount = (PFN_NUMBER)(EndPte - StartPte);
1722 if (!PageCount) return;
1723
1724 /* Delete this many PTEs */
1725 MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
1726 }
1727
1728 CODE_SEG("INIT")
1729 VOID
1730 NTAPI
MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)1731 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1732 {
1733 PLIST_ENTRY NextEntry;
1734 ULONG i = 0;
1735 PIMAGE_NT_HEADERS NtHeader;
1736 PLDR_DATA_TABLE_ENTRY LdrEntry;
1737 PIMAGE_FILE_HEADER FileHeader;
1738 BOOLEAN ValidRelocs;
1739 PIMAGE_DATA_DIRECTORY DataDirectory;
1740 PVOID DllBase, NewImageAddress;
1741 NTSTATUS Status;
1742 PMMPTE PointerPte, StartPte, LastPte;
1743 PFN_COUNT PteCount;
1744 PMMPFN Pfn1;
1745 MMPTE TempPte, OldPte;
1746
1747 /* Loop driver list */
1748 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1749 NextEntry != &LoaderBlock->LoadOrderListHead;
1750 NextEntry = NextEntry->Flink)
1751 {
1752 /* Get the loader entry and NT header */
1753 LdrEntry = CONTAINING_RECORD(NextEntry,
1754 LDR_DATA_TABLE_ENTRY,
1755 InLoadOrderLinks);
1756 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1757
1758 /* Debug info */
1759 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1760 LdrEntry->DllBase,
1761 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1762 &LdrEntry->FullDllName);
1763
1764 /* Get the first PTE and the number of PTEs we'll need */
1765 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
1766 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
1767 LastPte = StartPte + PteCount;
1768
1769 #if MI_TRACE_PFNS
1770 /* Loop the PTEs */
1771 while (PointerPte < LastPte)
1772 {
1773 ULONG len;
1774 ASSERT(PointerPte->u.Hard.Valid == 1);
1775 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1776 len = wcslen(LdrEntry->BaseDllName.Buffer) * sizeof(WCHAR);
1777 snprintf(Pfn1->ProcessName, min(16, len), "%S", LdrEntry->BaseDllName.Buffer);
1778 PointerPte++;
1779 }
1780 #endif
1781 /* Skip kernel and HAL */
1782 /* ROS HACK: Skip BOOTVID/KDCOM too */
1783 i++;
1784 if (i <= 4) continue;
1785
1786 /* Skip non-drivers */
1787 if (!NtHeader) continue;
1788
1789 /* Get the file header and make sure we can relocate */
1790 FileHeader = &NtHeader->FileHeader;
1791 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1792 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1793 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1794
1795 /* Everything made sense until now, check the relocation section too */
1796 DataDirectory = &NtHeader->OptionalHeader.
1797 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1798 if (!DataDirectory->VirtualAddress)
1799 {
1800 /* We don't really have relocations */
1801 ValidRelocs = FALSE;
1802 }
1803 else
1804 {
1805 /* Make sure the size is valid */
1806 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1807 LdrEntry->SizeOfImage)
1808 {
1809 /* They're not, skip */
1810 continue;
1811 }
1812
1813 /* We have relocations */
1814 ValidRelocs = TRUE;
1815 }
1816
1817 /* Remember the original address */
1818 DllBase = LdrEntry->DllBase;
1819
1820 /* Loop the PTEs */
1821 PointerPte = StartPte;
1822 while (PointerPte < LastPte)
1823 {
1824 /* Mark the page modified in the PFN database */
1825 ASSERT(PointerPte->u.Hard.Valid == 1);
1826 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1827 ASSERT(Pfn1->u3.e1.Rom == 0);
1828 Pfn1->u3.e1.Modified = TRUE;
1829
1830 /* Next */
1831 PointerPte++;
1832 }
1833
1834 /* Now reserve system PTEs for the image */
1835 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
1836 if (!PointerPte)
1837 {
1838 /* Shouldn't happen */
1839 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1840 return;
1841 }
1842
1843 /* This is the new virtual address for the module */
1844 LastPte = PointerPte + PteCount;
1845 NewImageAddress = MiPteToAddress(PointerPte);
1846
1847 /* Sanity check */
1848 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1849 ASSERT(ExpInitializationPhase == 0);
1850
1851 /* Loop the new driver PTEs */
1852 TempPte = ValidKernelPte;
1853 while (PointerPte < LastPte)
1854 {
1855 /* Copy the old data */
1856 OldPte = *StartPte;
1857 ASSERT(OldPte.u.Hard.Valid == 1);
1858
1859 /* Set page number from the loader's memory */
1860 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
1861
1862 /* Write it */
1863 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1864
1865 /* Move on */
1866 PointerPte++;
1867 StartPte++;
1868 }
1869
1870 /* Update position */
1871 PointerPte -= PteCount;
1872
1873 /* Sanity check */
1874 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1875
1876 /* Set the image base to the address where the loader put it */
1877 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1878
1879 /* Check if we had relocations */
1880 if (ValidRelocs)
1881 {
1882 /* Relocate the image */
1883 Status = LdrRelocateImageWithBias(NewImageAddress,
1884 0,
1885 "SYSLDR",
1886 STATUS_SUCCESS,
1887 STATUS_CONFLICTING_ADDRESSES,
1888 STATUS_INVALID_IMAGE_FORMAT);
1889 if (!NT_SUCCESS(Status))
1890 {
1891 /* This shouldn't happen */
1892 ERROR_FATAL("Relocations failed!\n");
1893 return;
1894 }
1895 }
1896
1897 /* Update the loader entry */
1898 LdrEntry->DllBase = NewImageAddress;
1899
1900 /* Update the thunks */
1901 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1902 MiUpdateThunks(LoaderBlock,
1903 DllBase,
1904 NewImageAddress,
1905 LdrEntry->SizeOfImage);
1906
1907 /* Update the loader entry */
1908 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1909 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1910 NtHeader->OptionalHeader.AddressOfEntryPoint);
1911 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
1912
1913 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1914 }
1915 }
1916
1917 CODE_SEG("INIT")
1918 NTSTATUS
1919 NTAPI
MiBuildImportsForBootDrivers(VOID)1920 MiBuildImportsForBootDrivers(VOID)
1921 {
1922 PLIST_ENTRY NextEntry, NextEntry2;
1923 PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry;
1924 PLDR_DATA_TABLE_ENTRY* EntryArray;
1925 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
1926 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
1927 PLOAD_IMPORTS LoadedImports;
1928 ULONG LoadedImportsSize, ImportSize;
1929 PULONG_PTR ImageThunk;
1930 ULONG_PTR DllBase, DllEnd;
1931 ULONG Modules = 0, i, j = 0;
1932 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
1933
1934 /* Initialize variables */
1935 KernelEntry = HalEntry = LastEntry = NULL;
1936
1937 /* Loop the loaded module list... we are early enough that no lock is needed */
1938 NextEntry = PsLoadedModuleList.Flink;
1939 while (NextEntry != &PsLoadedModuleList)
1940 {
1941 /* Get the entry */
1942 LdrEntry = CONTAINING_RECORD(NextEntry,
1943 LDR_DATA_TABLE_ENTRY,
1944 InLoadOrderLinks);
1945
1946 /* Check if it's the kernel or HAL */
1947 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
1948 {
1949 /* Found it */
1950 KernelEntry = LdrEntry;
1951 }
1952 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
1953 {
1954 /* Found it */
1955 HalEntry = LdrEntry;
1956 }
1957
1958 /* Check if this is a driver DLL */
1959 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1960 {
1961 /* Check if this is the HAL or kernel */
1962 if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry))
1963 {
1964 /* Add a reference */
1965 LdrEntry->LoadCount = 1;
1966 }
1967 else
1968 {
1969 /* No referencing needed */
1970 LdrEntry->LoadCount = 0;
1971 }
1972 }
1973 else
1974 {
1975 /* Add a reference for all other modules as well */
1976 LdrEntry->LoadCount = 1;
1977 }
1978
1979 /* Remember this came from the loader */
1980 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
1981
1982 /* Keep looping */
1983 NextEntry = NextEntry->Flink;
1984 Modules++;
1985 }
1986
1987 /* We must have at least found the kernel and HAL */
1988 if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND;
1989
1990 /* Allocate the list */
1991 EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), TAG_LDR_IMPORTS);
1992 if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES;
1993
1994 /* Loop the loaded module list again */
1995 NextEntry = PsLoadedModuleList.Flink;
1996 while (NextEntry != &PsLoadedModuleList)
1997 {
1998 /* Get the entry */
1999 LdrEntry = CONTAINING_RECORD(NextEntry,
2000 LDR_DATA_TABLE_ENTRY,
2001 InLoadOrderLinks);
2002 #ifdef _WORKING_LOADER_
2003 /* Get its imports */
2004 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
2005 TRUE,
2006 IMAGE_DIRECTORY_ENTRY_IAT,
2007 &ImportSize);
2008 if (!ImageThunk)
2009 #else
2010 /* Get its imports */
2011 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
2012 TRUE,
2013 IMAGE_DIRECTORY_ENTRY_IMPORT,
2014 &ImportSize);
2015 if (!ImportDescriptor)
2016 #endif
2017 {
2018 /* None present */
2019 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
2020 NextEntry = NextEntry->Flink;
2021 continue;
2022 }
2023
2024 /* Clear the list and count the number of IAT thunks */
2025 RtlZeroMemory(EntryArray, Modules * sizeof(PVOID));
2026 #ifdef _WORKING_LOADER_
2027 ImportSize /= sizeof(ULONG_PTR);
2028
2029 /* Scan the thunks */
2030 for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++)
2031 #else
2032 DllBase = DllEnd = i = 0;
2033 while ((ImportDescriptor->Name) &&
2034 (ImportDescriptor->OriginalFirstThunk))
2035 {
2036 /* Get the image thunk */
2037 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
2038 ImportDescriptor->FirstThunk);
2039 while (*ImageThunk)
2040 #endif
2041 {
2042 /* Do we already have an address? */
2043 if (DllBase)
2044 {
2045 /* Is the thunk in the same address? */
2046 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
2047 {
2048 /* Skip it, we already have a reference for it */
2049 ASSERT(EntryArray[j]);
2050 ImageThunk++;
2051 continue;
2052 }
2053 }
2054
2055 /* Loop the loaded module list to locate this address owner */
2056 j = 0;
2057 NextEntry2 = PsLoadedModuleList.Flink;
2058 while (NextEntry2 != &PsLoadedModuleList)
2059 {
2060 /* Get the entry */
2061 LdrEntry2 = CONTAINING_RECORD(NextEntry2,
2062 LDR_DATA_TABLE_ENTRY,
2063 InLoadOrderLinks);
2064
2065 /* Get the address range for this module */
2066 DllBase = (ULONG_PTR)LdrEntry2->DllBase;
2067 DllEnd = DllBase + LdrEntry2->SizeOfImage;
2068
2069 /* Check if this IAT entry matches it */
2070 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
2071 {
2072 /* Save it */
2073 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
2074 EntryArray[j] = LdrEntry2;
2075 break;
2076 }
2077
2078 /* Keep searching */
2079 NextEntry2 = NextEntry2->Flink;
2080 j++;
2081 }
2082
2083 /* Do we have a thunk outside the range? */
2084 if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd))
2085 {
2086 /* Could be 0... */
2087 if (*ImageThunk)
2088 {
2089 /* Should not be happening */
2090 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2091 LdrEntry, ImageThunk, *ImageThunk);
2092 }
2093
2094 /* Reset if we hit this */
2095 DllBase = 0;
2096 }
2097 #ifndef _WORKING_LOADER_
2098 ImageThunk++;
2099 }
2100
2101 i++;
2102 ImportDescriptor++;
2103 #endif
2104 }
2105
2106 /* Now scan how many imports we really have */
2107 for (i = 0, ImportSize = 0; i < Modules; i++)
2108 {
2109 /* Skip HAL and kernel */
2110 if ((EntryArray[i]) &&
2111 (EntryArray[i] != HalEntry) &&
2112 (EntryArray[i] != KernelEntry))
2113 {
2114 /* A valid reference */
2115 LastEntry = EntryArray[i];
2116 ImportSize++;
2117 }
2118 }
2119
2120 /* Do we have any imports after all? */
2121 if (!ImportSize)
2122 {
2123 /* No */
2124 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
2125 }
2126 else if (ImportSize == 1)
2127 {
2128 /* A single entry import */
2129 LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY);
2130 LastEntry->LoadCount++;
2131 }
2132 else
2133 {
2134 /* We need an import table */
2135 LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T);
2136 LoadedImports = ExAllocatePoolWithTag(PagedPool,
2137 LoadedImportsSize,
2138 TAG_LDR_IMPORTS);
2139 ASSERT(LoadedImports);
2140
2141 /* Save the count */
2142 LoadedImports->Count = ImportSize;
2143
2144 /* Now copy all imports */
2145 for (i = 0, j = 0; i < Modules; i++)
2146 {
2147 /* Skip HAL and kernel */
2148 if ((EntryArray[i]) &&
2149 (EntryArray[i] != HalEntry) &&
2150 (EntryArray[i] != KernelEntry))
2151 {
2152 /* A valid reference */
2153 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2154 LoadedImports->Entry[j] = EntryArray[i];
2155 EntryArray[i]->LoadCount++;
2156 j++;
2157 }
2158 }
2159
2160 /* Should had as many entries as we expected */
2161 ASSERT(j == ImportSize);
2162 LdrEntry->LoadedImports = LoadedImports;
2163 }
2164
2165 /* Next */
2166 NextEntry = NextEntry->Flink;
2167 }
2168
2169 /* Free the initial array */
2170 ExFreePoolWithTag(EntryArray, TAG_LDR_IMPORTS);
2171
2172 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2173
2174 /* Kernel and HAL are loaded at boot */
2175 KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
2176 HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
2177
2178 /* All worked well */
2179 return STATUS_SUCCESS;
2180 }
2181
2182 CODE_SEG("INIT")
2183 VOID
2184 NTAPI
MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)2185 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
2186 {
2187 ULONG_PTR DllBase;
2188 PIMAGE_NT_HEADERS NtHeaders;
2189 PIMAGE_SECTION_HEADER SectionHeader;
2190 ULONG Sections, Size;
2191
2192 /* Get the kernel section header */
2193 DllBase = (ULONG_PTR)LdrEntry->DllBase;
2194 NtHeaders = RtlImageNtHeader((PVOID)DllBase);
2195 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
2196
2197 /* Loop all the sections */
2198 for (Sections = NtHeaders->FileHeader.NumberOfSections;
2199 Sections > 0; --Sections, ++SectionHeader)
2200 {
2201 /* Grab the size of the section */
2202 Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);
2203
2204 /* Check for .RSRC section */
2205 if (*(PULONG)SectionHeader->Name == 'rsr.')
2206 {
2207 /* Remember the PTEs so we can modify them later */
2208 MiKernelResourceStartPte = MiAddressToPte(DllBase +
2209 SectionHeader->VirtualAddress);
2210 MiKernelResourceEndPte = MiAddressToPte(ROUND_TO_PAGES(DllBase +
2211 SectionHeader->VirtualAddress + Size));
2212 }
2213 else if (*(PULONG)SectionHeader->Name == 'LOOP')
2214 {
2215 /* POOLCODE vs. POOLMI */
2216 if (*(PULONG)&SectionHeader->Name[4] == 'EDOC')
2217 {
2218 /* Found Ex* Pool code */
2219 ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
2220 ExPoolCodeEnd = ExPoolCodeStart + Size;
2221 }
2222 else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI')
2223 {
2224 /* Found Mm* Pool code */
2225 MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
2226 MmPoolCodeEnd = MmPoolCodeStart + Size;
2227 }
2228 }
2229 else if ((*(PULONG)SectionHeader->Name == 'YSIM') &&
2230 (*(PULONG)&SectionHeader->Name[4] == 'ETPS'))
2231 {
2232 /* Found MISYSPTE (Mm System PTE code) */
2233 MmPteCodeStart = DllBase + SectionHeader->VirtualAddress;
2234 MmPteCodeEnd = MmPteCodeStart + Size;
2235 }
2236 }
2237 }
2238
2239 CODE_SEG("INIT")
2240 BOOLEAN
2241 NTAPI
MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)2242 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
2243 {
2244 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
2245 PLIST_ENTRY ListHead, NextEntry;
2246 ULONG EntrySize;
2247
2248 /* Setup the loaded module list and locks */
2249 ExInitializeResourceLite(&PsLoadedModuleResource);
2250 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
2251 InitializeListHead(&PsLoadedModuleList);
2252
2253 /* Get loop variables and the kernel entry */
2254 ListHead = &LoaderBlock->LoadOrderListHead;
2255 NextEntry = ListHead->Flink;
2256 LdrEntry = CONTAINING_RECORD(NextEntry,
2257 LDR_DATA_TABLE_ENTRY,
2258 InLoadOrderLinks);
2259 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
2260
2261 /* Locate resource section, pool code, and system pte code */
2262 MiLocateKernelSections(LdrEntry);
2263
2264 /* Loop the loader block */
2265 while (NextEntry != ListHead)
2266 {
2267 /* Get the loader entry */
2268 LdrEntry = CONTAINING_RECORD(NextEntry,
2269 LDR_DATA_TABLE_ENTRY,
2270 InLoadOrderLinks);
2271
2272 /* FIXME: ROS HACK. Make sure this is a driver */
2273 if (!RtlImageNtHeader(LdrEntry->DllBase))
2274 {
2275 /* Skip this entry */
2276 NextEntry = NextEntry->Flink;
2277 continue;
2278 }
2279
2280 /* Calculate the size we'll need and allocate a copy */
2281 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
2282 LdrEntry->BaseDllName.MaximumLength +
2283 sizeof(UNICODE_NULL);
2284 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
2285 if (!NewEntry) return FALSE;
2286
2287 /* Copy the entry over */
2288 *NewEntry = *LdrEntry;
2289
2290 /* Allocate the name */
2291 NewEntry->FullDllName.Buffer =
2292 ExAllocatePoolWithTag(PagedPool,
2293 LdrEntry->FullDllName.MaximumLength +
2294 sizeof(UNICODE_NULL),
2295 TAG_LDR_WSTR);
2296 if (!NewEntry->FullDllName.Buffer)
2297 {
2298 ExFreePoolWithTag(NewEntry, TAG_MODULE_OBJECT);
2299 return FALSE;
2300 }
2301
2302 /* Set the base name */
2303 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
2304
2305 /* Copy the full and base name */
2306 RtlCopyMemory(NewEntry->FullDllName.Buffer,
2307 LdrEntry->FullDllName.Buffer,
2308 LdrEntry->FullDllName.MaximumLength);
2309 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
2310 LdrEntry->BaseDllName.Buffer,
2311 LdrEntry->BaseDllName.MaximumLength);
2312
2313 /* Null-terminate the base name */
2314 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
2315 sizeof(WCHAR)] = UNICODE_NULL;
2316
2317 /* Insert the entry into the list */
2318 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
2319 NextEntry = NextEntry->Flink;
2320 }
2321
2322 /* Build the import lists for the boot drivers */
2323 MiBuildImportsForBootDrivers();
2324
2325 /* We're done */
2326 return TRUE;
2327 }
2328
2329 BOOLEAN
2330 NTAPI
MmChangeKernelResourceSectionProtection(IN ULONG_PTR ProtectionMask)2331 MmChangeKernelResourceSectionProtection(IN ULONG_PTR ProtectionMask)
2332 {
2333 PMMPTE PointerPte;
2334 MMPTE TempPte;
2335
2336 /* Don't do anything if the resource section is already writable */
2337 if (MiKernelResourceStartPte == NULL || MiKernelResourceEndPte == NULL)
2338 return FALSE;
2339
2340 /* If the resource section is physical, we cannot change its protection */
2341 if (MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(MiKernelResourceStartPte)))
2342 return FALSE;
2343
2344 /* Loop the PTEs */
2345 for (PointerPte = MiKernelResourceStartPte; PointerPte < MiKernelResourceEndPte; ++PointerPte)
2346 {
2347 /* Read the PTE */
2348 TempPte = *PointerPte;
2349
2350 /* Update the protection */
2351 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte, ProtectionMask, TempPte.u.Hard.PageFrameNumber);
2352 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2353 }
2354
2355 /* Only flush the current processor's TLB */
2356 KeFlushCurrentTb();
2357 return TRUE;
2358 }
2359
2360 VOID
2361 NTAPI
MmMakeKernelResourceSectionWritable(VOID)2362 MmMakeKernelResourceSectionWritable(VOID)
2363 {
2364 /* Don't do anything if the resource section is already writable */
2365 if (MiKernelResourceStartPte == NULL || MiKernelResourceEndPte == NULL)
2366 return;
2367
2368 /* If the resource section is physical, we cannot change its protection */
2369 if (MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(MiKernelResourceStartPte)))
2370 return;
2371
2372 if (MmChangeKernelResourceSectionProtection(MM_READWRITE))
2373 {
2374 /*
2375 * Invalidate the cached resource section PTEs
2376 * so as to not change its protection again later.
2377 */
2378 MiKernelResourceStartPte = NULL;
2379 MiKernelResourceEndPte = NULL;
2380 }
2381 }
2382
2383 LOGICAL
2384 NTAPI
MiUseLargeDriverPage(IN ULONG NumberOfPtes,IN OUT PVOID * ImageBaseAddress,IN PUNICODE_STRING BaseImageName,IN BOOLEAN BootDriver)2385 MiUseLargeDriverPage(IN ULONG NumberOfPtes,
2386 IN OUT PVOID *ImageBaseAddress,
2387 IN PUNICODE_STRING BaseImageName,
2388 IN BOOLEAN BootDriver)
2389 {
2390 PLIST_ENTRY NextEntry;
2391 BOOLEAN DriverFound = FALSE;
2392 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry;
2393 ASSERT(KeGetCurrentIrql () <= APC_LEVEL);
2394 ASSERT(*ImageBaseAddress >= MmSystemRangeStart);
2395
2396 #ifdef _X86_
2397 if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE;
2398 if (!(__readcr4() & CR4_PSE)) return FALSE;
2399 #endif
2400
2401 /* Make sure there's enough system PTEs for a large page driver */
2402 if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT)))
2403 {
2404 return FALSE;
2405 }
2406
2407 /* This happens if the registry key had a "*" (wildcard) in it */
2408 if (MiLargePageAllDrivers == 0)
2409 {
2410 /* It didn't, so scan the list */
2411 NextEntry = MiLargePageDriverList.Flink;
2412 while (NextEntry != &MiLargePageDriverList)
2413 {
2414 /* Check if the driver name matches */
2415 LargePageDriverEntry = CONTAINING_RECORD(NextEntry,
2416 MI_LARGE_PAGE_DRIVER_ENTRY,
2417 Links);
2418 if (RtlEqualUnicodeString(BaseImageName,
2419 &LargePageDriverEntry->BaseName,
2420 TRUE))
2421 {
2422 /* Enable large pages for this driver */
2423 DriverFound = TRUE;
2424 break;
2425 }
2426
2427 /* Keep trying */
2428 NextEntry = NextEntry->Flink;
2429 }
2430
2431 /* If we didn't find the driver, it doesn't need large pages */
2432 if (DriverFound == FALSE) return FALSE;
2433 }
2434
2435 /* Nothing to do yet */
2436 DPRINT1("Large pages not supported!\n");
2437 return FALSE;
2438 }
2439
2440 VOID
2441 NTAPI
MiSetSystemCodeProtection(_In_ PMMPTE FirstPte,_In_ PMMPTE LastPte,_In_ ULONG Protection)2442 MiSetSystemCodeProtection(
2443 _In_ PMMPTE FirstPte,
2444 _In_ PMMPTE LastPte,
2445 _In_ ULONG Protection)
2446 {
2447 PMMPTE PointerPte;
2448 MMPTE TempPte;
2449
2450 /* Loop the PTEs */
2451 for (PointerPte = FirstPte; PointerPte <= LastPte; PointerPte++)
2452 {
2453 /* Read the PTE */
2454 TempPte = *PointerPte;
2455
2456 /* Make sure it's valid */
2457 if (TempPte.u.Hard.Valid != 1)
2458 {
2459 DPRINT1("CORE-16449: FirstPte=%p, LastPte=%p, Protection=%lx\n", FirstPte, LastPte, Protection);
2460 DPRINT1("CORE-16449: PointerPte=%p, TempPte=%lx\n", PointerPte, TempPte.u.Long);
2461 DPRINT1("CORE-16449: Please issue the 'mod' and 'bt' (KDBG) or 'lm' and 'kp' (WinDbg) commands. Then report this in Jira.\n");
2462 ASSERT(TempPte.u.Hard.Valid == 1);
2463 break;
2464 }
2465
2466 /* Update the protection */
2467 TempPte.u.Hard.Write = BooleanFlagOn(Protection, IMAGE_SCN_MEM_WRITE);
2468 #if _MI_HAS_NO_EXECUTE
2469 TempPte.u.Hard.NoExecute = !BooleanFlagOn(Protection, IMAGE_SCN_MEM_EXECUTE);
2470 #endif
2471
2472 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2473 }
2474
2475 /* Flush it all */
2476 KeFlushEntireTb(TRUE, TRUE);
2477 }
2478
2479 VOID
2480 NTAPI
MiWriteProtectSystemImage(_In_ PVOID ImageBase)2481 MiWriteProtectSystemImage(
2482 _In_ PVOID ImageBase)
2483 {
2484 PIMAGE_NT_HEADERS NtHeaders;
2485 PIMAGE_SECTION_HEADER SectionHeaders, Section;
2486 ULONG i;
2487 PVOID SectionBase, SectionEnd;
2488 ULONG SectionSize;
2489 ULONG Protection;
2490 PMMPTE FirstPte, LastPte;
2491
2492 /* Check if the registry setting is on or not */
2493 if (MmEnforceWriteProtection == FALSE)
2494 {
2495 /* Ignore section protection */
2496 return;
2497 }
2498
2499 /* Large page mapped images are not supported */
2500 NT_ASSERT(!MI_IS_PHYSICAL_ADDRESS(ImageBase));
2501
2502 /* Session images are not yet supported */
2503 NT_ASSERT(!MI_IS_SESSION_ADDRESS(ImageBase));
2504
2505 /* Get the NT headers */
2506 NtHeaders = RtlImageNtHeader(ImageBase);
2507 if (NtHeaders == NULL)
2508 {
2509 DPRINT1("Failed to get NT headers for image @ %p\n", ImageBase);
2510 return;
2511 }
2512
2513 /* Don't touch NT4 drivers */
2514 if ((NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) ||
2515 (NtHeaders->OptionalHeader.MajorSubsystemVersion < 5))
2516 {
2517 DPRINT1("Skipping NT 4 driver @ %p\n", ImageBase);
2518 return;
2519 }
2520
2521 /* Get the section headers */
2522 SectionHeaders = IMAGE_FIRST_SECTION(NtHeaders);
2523
2524 /* Get the base address of the first section */
2525 SectionBase = Add2Ptr(ImageBase, SectionHeaders[0].VirtualAddress);
2526
2527 /* Start protecting the image header as R/W */
2528 FirstPte = MiAddressToPte(ImageBase);
2529 LastPte = MiAddressToPte(SectionBase) - 1;
2530 Protection = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2531 if (LastPte >= FirstPte)
2532 {
2533 MiSetSystemCodeProtection(FirstPte, LastPte, Protection);
2534 }
2535
2536 /* Loop the sections */
2537 for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++)
2538 {
2539 /* Get the section base address and size */
2540 Section = &SectionHeaders[i];
2541 SectionBase = Add2Ptr(ImageBase, Section->VirtualAddress);
2542 SectionSize = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
2543
2544 /* Get the first PTE of this section */
2545 FirstPte = MiAddressToPte(SectionBase);
2546
2547 /* Check for overlap with the previous range */
2548 if (FirstPte == LastPte)
2549 {
2550 /* Combine the old and new protection by ORing them */
2551 Protection |= (Section->Characteristics & IMAGE_SCN_PROTECTION_MASK);
2552
2553 /* Update the protection for this PTE */
2554 MiSetSystemCodeProtection(FirstPte, FirstPte, Protection);
2555
2556 /* Skip this PTE */
2557 FirstPte++;
2558 }
2559
2560 /* There can not be gaps! */
2561 NT_ASSERT(FirstPte == (LastPte + 1));
2562
2563 /* Get the end of the section and the last PTE */
2564 SectionEnd = Add2Ptr(SectionBase, SectionSize - 1);
2565 NT_ASSERT(SectionEnd < Add2Ptr(ImageBase, NtHeaders->OptionalHeader.SizeOfImage));
2566 LastPte = MiAddressToPte(SectionEnd);
2567
2568 /* If there are no more pages (after an overlap), skip this section */
2569 if (LastPte < FirstPte)
2570 {
2571 NT_ASSERT(FirstPte == (LastPte + 1));
2572 continue;
2573 }
2574
2575 /* Get the section protection */
2576 Protection = (Section->Characteristics & IMAGE_SCN_PROTECTION_MASK);
2577
2578 /* Update the protection for this section */
2579 MiSetSystemCodeProtection(FirstPte, LastPte, Protection);
2580 }
2581
2582 /* Image should end with the last section */
2583 if (ALIGN_UP_POINTER_BY(SectionEnd, PAGE_SIZE) !=
2584 Add2Ptr(ImageBase, NtHeaders->OptionalHeader.SizeOfImage))
2585 {
2586 DPRINT1("ImageBase 0x%p ImageSize 0x%lx Section %u VA 0x%lx Raw 0x%lx virt 0x%lx\n",
2587 ImageBase,
2588 NtHeaders->OptionalHeader.SizeOfImage,
2589 i,
2590 Section->VirtualAddress,
2591 Section->SizeOfRawData,
2592 Section->Misc.VirtualSize);
2593 }
2594 }
2595
2596 VOID
2597 NTAPI
MiSetPagingOfDriver(IN PMMPTE PointerPte,IN PMMPTE LastPte)2598 MiSetPagingOfDriver(IN PMMPTE PointerPte,
2599 IN PMMPTE LastPte)
2600 {
2601 #ifdef ENABLE_MISETPAGINGOFDRIVER
2602 PVOID ImageBase;
2603 PETHREAD CurrentThread = PsGetCurrentThread();
2604 PFN_COUNT PageCount = 0;
2605 PFN_NUMBER PageFrameIndex;
2606 PMMPFN Pfn1;
2607 #endif // ENABLE_MISETPAGINGOFDRIVER
2608
2609 PAGED_CODE();
2610
2611 #ifndef ENABLE_MISETPAGINGOFDRIVER
2612 /* The page fault handler is broken and doesn't page back in! */
2613 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2614 #else // ENABLE_MISETPAGINGOFDRIVER
2615 /* Get the driver's base address */
2616 ImageBase = MiPteToAddress(PointerPte);
2617 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
2618
2619 /* If this is a large page, it's stuck in physical memory */
2620 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
2621
2622 /* Lock the working set */
2623 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
2624
2625 /* Loop the PTEs */
2626 while (PointerPte <= LastPte)
2627 {
2628 /* Check for valid PTE */
2629 if (PointerPte->u.Hard.Valid == 1)
2630 {
2631 PageFrameIndex = PFN_FROM_PTE(PointerPte);
2632 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2633 ASSERT(Pfn1->u2.ShareCount == 1);
2634
2635 /* No working sets in ReactOS yet */
2636 PageCount++;
2637 }
2638
2639 ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE);
2640 PointerPte++;
2641 }
2642
2643 /* Release the working set */
2644 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
2645
2646 /* Do we have any driver pages? */
2647 if (PageCount)
2648 {
2649 /* Update counters */
2650 InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount);
2651 }
2652 #endif // ENABLE_MISETPAGINGOFDRIVER
2653 }
2654
2655 VOID
2656 NTAPI
MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)2657 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
2658 {
2659 ULONG_PTR ImageBase;
2660 PIMAGE_NT_HEADERS NtHeaders;
2661 ULONG Sections, Alignment, Size;
2662 PIMAGE_SECTION_HEADER Section;
2663 PMMPTE PointerPte = NULL, LastPte = NULL;
2664 if (MmDisablePagingExecutive) return;
2665
2666 /* Get the driver base address and its NT header */
2667 ImageBase = (ULONG_PTR)LdrEntry->DllBase;
2668 NtHeaders = RtlImageNtHeader((PVOID)ImageBase);
2669 if (!NtHeaders) return;
2670
2671 /* Get the sections and their alignment */
2672 Sections = NtHeaders->FileHeader.NumberOfSections;
2673 Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1;
2674
2675 /* Loop each section */
2676 Section = IMAGE_FIRST_SECTION(NtHeaders);
2677 while (Sections)
2678 {
2679 /* Find PAGE or .edata */
2680 if ((*(PULONG)Section->Name == 'EGAP') ||
2681 (*(PULONG)Section->Name == 'ade.'))
2682 {
2683 /* Had we already done some work? */
2684 if (!PointerPte)
2685 {
2686 /* Nope, setup the first PTE address */
2687 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase +
2688 Section->VirtualAddress));
2689 }
2690
2691 /* Compute the size */
2692 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
2693
2694 /* Find the last PTE that maps this section */
2695 LastPte = MiAddressToPte(ImageBase +
2696 Section->VirtualAddress +
2697 Alignment + Size - PAGE_SIZE);
2698 }
2699 else
2700 {
2701 /* Had we found a section before? */
2702 if (PointerPte)
2703 {
2704 /* Mark it as pageable */
2705 MiSetPagingOfDriver(PointerPte, LastPte);
2706 PointerPte = NULL;
2707 }
2708 }
2709
2710 /* Keep searching */
2711 Sections--;
2712 Section++;
2713 }
2714
2715 /* Handle the straggler */
2716 if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte);
2717 }
2718
2719 BOOLEAN
2720 NTAPI
MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)2721 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
2722 {
2723 PIMAGE_NT_HEADERS NtHeader;
2724 PAGED_CODE();
2725
2726 /* Get NT Headers */
2727 NtHeader = RtlImageNtHeader(BaseAddress);
2728 if (NtHeader)
2729 {
2730 /* Check if this image is only safe for UP while we have 2+ CPUs */
2731 if ((KeNumberProcessors > 1) &&
2732 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
2733 {
2734 /* Fail */
2735 return FALSE;
2736 }
2737 }
2738
2739 /* Otherwise, it's safe */
2740 return TRUE;
2741 }
2742
2743 NTSTATUS
2744 NTAPI
MmCheckSystemImage(IN HANDLE ImageHandle,IN BOOLEAN PurgeSection)2745 MmCheckSystemImage(IN HANDLE ImageHandle,
2746 IN BOOLEAN PurgeSection)
2747 {
2748 NTSTATUS Status;
2749 HANDLE SectionHandle;
2750 PVOID ViewBase = NULL;
2751 SIZE_T ViewSize = 0;
2752 IO_STATUS_BLOCK IoStatusBlock;
2753 FILE_STANDARD_INFORMATION FileStandardInfo;
2754 KAPC_STATE ApcState;
2755 PIMAGE_NT_HEADERS NtHeaders;
2756 OBJECT_ATTRIBUTES ObjectAttributes;
2757 PAGED_CODE();
2758
2759 /* Setup the object attributes */
2760 InitializeObjectAttributes(&ObjectAttributes,
2761 NULL,
2762 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2763 NULL,
2764 NULL);
2765
2766 /* Create a section for the DLL */
2767 Status = ZwCreateSection(&SectionHandle,
2768 SECTION_MAP_EXECUTE,
2769 &ObjectAttributes,
2770 NULL,
2771 PAGE_EXECUTE,
2772 SEC_IMAGE,
2773 ImageHandle);
2774 if (!NT_SUCCESS(Status))
2775 {
2776 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
2777 return Status;
2778 }
2779
2780 /* Make sure we're in the system process */
2781 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
2782
2783 /* Map it */
2784 Status = ZwMapViewOfSection(SectionHandle,
2785 NtCurrentProcess(),
2786 &ViewBase,
2787 0,
2788 0,
2789 NULL,
2790 &ViewSize,
2791 ViewShare,
2792 0,
2793 PAGE_EXECUTE);
2794 if (!NT_SUCCESS(Status))
2795 {
2796 /* We failed, close the handle and return */
2797 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status);
2798 KeUnstackDetachProcess(&ApcState);
2799 ZwClose(SectionHandle);
2800 return Status;
2801 }
2802
2803 /* Now query image information */
2804 Status = ZwQueryInformationFile(ImageHandle,
2805 &IoStatusBlock,
2806 &FileStandardInfo,
2807 sizeof(FileStandardInfo),
2808 FileStandardInformation);
2809 if (NT_SUCCESS(Status))
2810 {
2811 /* First, verify the checksum */
2812 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
2813 ViewSize,
2814 FileStandardInfo.
2815 EndOfFile.LowPart))
2816 {
2817 /* Set checksum failure */
2818 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2819 goto Fail;
2820 }
2821
2822 /* Make sure it's a real image */
2823 NtHeaders = RtlImageNtHeader(ViewBase);
2824 if (!NtHeaders)
2825 {
2826 /* Set checksum failure */
2827 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2828 goto Fail;
2829 }
2830
2831 /* Make sure it's for the correct architecture */
2832 if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) ||
2833 (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC))
2834 {
2835 /* Set protection failure */
2836 Status = STATUS_INVALID_IMAGE_PROTECT;
2837 goto Fail;
2838 }
2839
2840 /* Check that it's a valid SMP image if we have more then one CPU */
2841 if (!MmVerifyImageIsOkForMpUse(ViewBase))
2842 {
2843 /* Otherwise it's not the right image */
2844 Status = STATUS_IMAGE_MP_UP_MISMATCH;
2845 }
2846 }
2847
2848 /* Unmap the section, close the handle, and return status */
2849 Fail:
2850 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2851 KeUnstackDetachProcess(&ApcState);
2852 ZwClose(SectionHandle);
2853 return Status;
2854 }
2855
2856
2857 PVOID
2858 NTAPI
LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress,ULONG SizeOfImage)2859 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
2860 {
2861 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
2862 ULONG DirSize;
2863 PULONG_PTR Cookie = NULL;
2864
2865 /* Get the pointer to the config directory */
2866 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
2867 TRUE,
2868 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
2869 &DirSize);
2870
2871 /* Check for sanity */
2872 if (!ConfigDir ||
2873 DirSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie))
2874 {
2875 /* Invalid directory*/
2876 return NULL;
2877 }
2878
2879 /* Now get the cookie */
2880 Cookie = (PULONG_PTR)ConfigDir->SecurityCookie;
2881
2882 /* Check this cookie */
2883 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
2884 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage - sizeof(*Cookie))
2885 {
2886 Cookie = NULL;
2887 }
2888
2889 /* Return validated security cookie */
2890 return Cookie;
2891 }
2892
2893 PVOID
2894 NTAPI
LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)2895 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
2896 {
2897 PULONG_PTR Cookie;
2898 ULONG_PTR NewCookie;
2899
2900 /* Fetch address of the cookie */
2901 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
2902
2903 if (!Cookie)
2904 return NULL;
2905
2906 /* Check if it's a default one */
2907 if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
2908 (*Cookie == 0))
2909 {
2910 LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL);
2911 /* The address should be unique */
2912 NewCookie = (ULONG_PTR)Cookie;
2913
2914 /* We just need a simple tick, don't care about precision and whatnot */
2915 NewCookie ^= (ULONG_PTR)Counter.LowPart;
2916 #ifdef _WIN64
2917 /* Some images expect first 16 bits to be kept clean (like in default cookie) */
2918 if (NewCookie > COOKIE_MAX)
2919 {
2920 NewCookie >>= 16;
2921 }
2922 #endif
2923 /* If the result is 0 or the same as we got, just add one to the default value */
2924 if ((NewCookie == 0) || (NewCookie == *Cookie))
2925 {
2926 NewCookie = DEFAULT_SECURITY_COOKIE + 1;
2927 }
2928
2929 /* Set the new cookie value */
2930 *Cookie = NewCookie;
2931 }
2932
2933 return Cookie;
2934 }
2935
2936 NTSTATUS
2937 NTAPI
MmLoadSystemImage(IN PUNICODE_STRING FileName,IN PUNICODE_STRING NamePrefix OPTIONAL,IN PUNICODE_STRING LoadedName OPTIONAL,IN ULONG Flags,OUT PVOID * ModuleObject,OUT PVOID * ImageBaseAddress)2938 MmLoadSystemImage(IN PUNICODE_STRING FileName,
2939 IN PUNICODE_STRING NamePrefix OPTIONAL,
2940 IN PUNICODE_STRING LoadedName OPTIONAL,
2941 IN ULONG Flags,
2942 OUT PVOID *ModuleObject,
2943 OUT PVOID *ImageBaseAddress)
2944 {
2945 PVOID ModuleLoadBase = NULL;
2946 NTSTATUS Status;
2947 HANDLE FileHandle = NULL;
2948 OBJECT_ATTRIBUTES ObjectAttributes;
2949 IO_STATUS_BLOCK IoStatusBlock;
2950 PIMAGE_NT_HEADERS NtHeader;
2951 UNICODE_STRING BaseName, BaseDirectory, PrefixName;
2952 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
2953 ULONG EntrySize, DriverSize;
2954 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
2955 PCHAR MissingApiName, Buffer;
2956 PWCHAR MissingDriverName, PrefixedBuffer = NULL;
2957 HANDLE SectionHandle;
2958 ACCESS_MASK DesiredAccess;
2959 PSECTION Section = NULL;
2960 BOOLEAN LockOwned = FALSE;
2961 PLIST_ENTRY NextEntry;
2962 IMAGE_INFO ImageInfo;
2963
2964 PAGED_CODE();
2965
2966 /* Detect session-load */
2967 if (Flags)
2968 {
2969 /* Sanity checks */
2970 ASSERT(NamePrefix == NULL);
2971 ASSERT(LoadedName == NULL);
2972
2973 /* Make sure the process is in session too */
2974 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
2975 }
2976
2977 /* Allocate a buffer we'll use for names */
2978 Buffer = ExAllocatePoolWithTag(NonPagedPool,
2979 MAXIMUM_FILENAME_LENGTH,
2980 TAG_LDR_WSTR);
2981 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2982
2983 /* Check for a separator */
2984 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2985 {
2986 PWCHAR p;
2987 ULONG BaseLength;
2988
2989 /* Loop the path until we get to the base name */
2990 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
2991 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
2992
2993 /* Get the length */
2994 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
2995 BaseLength *= sizeof(WCHAR);
2996
2997 /* Setup the string */
2998 BaseName.Length = (USHORT)BaseLength;
2999 BaseName.Buffer = p;
3000 }
3001 else
3002 {
3003 /* Otherwise, we already have a base name */
3004 BaseName.Length = FileName->Length;
3005 BaseName.Buffer = FileName->Buffer;
3006 }
3007
3008 /* Setup the maximum length */
3009 BaseName.MaximumLength = BaseName.Length;
3010
3011 /* Now compute the base directory */
3012 BaseDirectory = *FileName;
3013 BaseDirectory.Length -= BaseName.Length;
3014 BaseDirectory.MaximumLength = BaseDirectory.Length;
3015
3016 /* And the prefix, which for now is just the name itself */
3017 PrefixName = *FileName;
3018
3019 /* Check if we have a prefix */
3020 if (NamePrefix)
3021 {
3022 /* Check if "directory + prefix" is too long for the string */
3023 Status = RtlUShortAdd(BaseDirectory.Length,
3024 NamePrefix->Length,
3025 &PrefixName.MaximumLength);
3026 if (!NT_SUCCESS(Status))
3027 {
3028 Status = STATUS_INVALID_PARAMETER;
3029 goto Quickie;
3030 }
3031
3032 /* Check if "directory + prefix + basename" is too long for the string */
3033 Status = RtlUShortAdd(PrefixName.MaximumLength,
3034 BaseName.Length,
3035 &PrefixName.MaximumLength);
3036 if (!NT_SUCCESS(Status))
3037 {
3038 Status = STATUS_INVALID_PARAMETER;
3039 goto Quickie;
3040 }
3041
3042 /* Allocate the buffer exclusively used for prefixed name */
3043 PrefixedBuffer = ExAllocatePoolWithTag(PagedPool,
3044 PrefixName.MaximumLength,
3045 TAG_LDR_WSTR);
3046 if (!PrefixedBuffer)
3047 {
3048 Status = STATUS_INSUFFICIENT_RESOURCES;
3049 goto Quickie;
3050 }
3051
3052 /* Clear out the prefixed name string */
3053 PrefixName.Buffer = PrefixedBuffer;
3054 PrefixName.Length = 0;
3055
3056 /* Concatenate the strings */
3057 RtlAppendUnicodeStringToString(&PrefixName, &BaseDirectory);
3058 RtlAppendUnicodeStringToString(&PrefixName, NamePrefix);
3059 RtlAppendUnicodeStringToString(&PrefixName, &BaseName);
3060
3061 /* Now the base name of the image becomes the prefixed version */
3062 BaseName.Buffer = &(PrefixName.Buffer[BaseDirectory.Length / sizeof(WCHAR)]);
3063 BaseName.Length += NamePrefix->Length;
3064 BaseName.MaximumLength = (PrefixName.MaximumLength - BaseDirectory.Length);
3065 }
3066
3067 /* Check if we already have a name, use it instead */
3068 if (LoadedName) BaseName = *LoadedName;
3069
3070 /* Check for loader snap debugging */
3071 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
3072 {
3073 /* Print out standard string */
3074 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
3075 &PrefixName, &BaseName, Flags ? "in session space" : "");
3076 }
3077
3078 /* Acquire the load lock */
3079 LoaderScan:
3080 ASSERT(LockOwned == FALSE);
3081 LockOwned = TRUE;
3082 KeEnterCriticalRegion();
3083 KeWaitForSingleObject(&MmSystemLoadLock,
3084 WrVirtualMemory,
3085 KernelMode,
3086 FALSE,
3087 NULL);
3088
3089 /* Scan the module list */
3090 NextEntry = PsLoadedModuleList.Flink;
3091 while (NextEntry != &PsLoadedModuleList)
3092 {
3093 /* Get the entry and compare the names */
3094 LdrEntry = CONTAINING_RECORD(NextEntry,
3095 LDR_DATA_TABLE_ENTRY,
3096 InLoadOrderLinks);
3097 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
3098 {
3099 /* Found it, break out */
3100 break;
3101 }
3102
3103 /* Keep scanning */
3104 NextEntry = NextEntry->Flink;
3105 }
3106
3107 /* Check if we found the image */
3108 if (NextEntry != &PsLoadedModuleList)
3109 {
3110 /* Check if we had already mapped a section */
3111 if (Section)
3112 {
3113 /* Dereference and clear */
3114 ObDereferenceObject(Section);
3115 Section = NULL;
3116 }
3117
3118 /* Check if this was supposed to be a session load */
3119 if (!Flags)
3120 {
3121 /* It wasn't, so just return the data */
3122 *ModuleObject = LdrEntry;
3123 *ImageBaseAddress = LdrEntry->DllBase;
3124 Status = STATUS_IMAGE_ALREADY_LOADED;
3125 }
3126 else
3127 {
3128 /* We don't support session loading yet */
3129 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3130 Status = STATUS_NOT_IMPLEMENTED;
3131 }
3132
3133 /* Do cleanup */
3134 goto Quickie;
3135 }
3136 else if (!Section)
3137 {
3138 /* It wasn't loaded, and we didn't have a previous attempt */
3139 KeReleaseMutant(&MmSystemLoadLock, MUTANT_INCREMENT, FALSE, FALSE);
3140 KeLeaveCriticalRegion();
3141 LockOwned = FALSE;
3142
3143 /* Check if KD is enabled */
3144 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
3145 {
3146 /* FIXME: Attempt to get image from KD */
3147 }
3148
3149 /* We don't have a valid entry */
3150 LdrEntry = NULL;
3151
3152 /* Setup image attributes */
3153 InitializeObjectAttributes(&ObjectAttributes,
3154 FileName,
3155 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3156 NULL,
3157 NULL);
3158
3159 /* Open the image */
3160 Status = ZwOpenFile(&FileHandle,
3161 FILE_EXECUTE,
3162 &ObjectAttributes,
3163 &IoStatusBlock,
3164 FILE_SHARE_READ | FILE_SHARE_DELETE,
3165 0);
3166 if (!NT_SUCCESS(Status))
3167 {
3168 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
3169 FileName, Status);
3170 goto Quickie;
3171 }
3172
3173 /* Validate it */
3174 Status = MmCheckSystemImage(FileHandle, FALSE);
3175 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
3176 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
3177 (Status == STATUS_INVALID_IMAGE_PROTECT))
3178 {
3179 /* Fail loading */
3180 goto Quickie;
3181 }
3182
3183 /* Check if this is a session-load */
3184 if (Flags)
3185 {
3186 /* Then we only need read and execute */
3187 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
3188 }
3189 else
3190 {
3191 /* Otherwise, we can allow write access */
3192 DesiredAccess = SECTION_ALL_ACCESS;
3193 }
3194
3195 /* Initialize the attributes for the section */
3196 InitializeObjectAttributes(&ObjectAttributes,
3197 NULL,
3198 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3199 NULL,
3200 NULL);
3201
3202 /* Create the section */
3203 Status = ZwCreateSection(&SectionHandle,
3204 DesiredAccess,
3205 &ObjectAttributes,
3206 NULL,
3207 PAGE_EXECUTE,
3208 SEC_IMAGE,
3209 FileHandle);
3210 if (!NT_SUCCESS(Status))
3211 {
3212 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
3213 goto Quickie;
3214 }
3215
3216 /* Now get the section pointer */
3217 Status = ObReferenceObjectByHandle(SectionHandle,
3218 SECTION_MAP_EXECUTE,
3219 MmSectionObjectType,
3220 KernelMode,
3221 (PVOID*)&Section,
3222 NULL);
3223 ZwClose(SectionHandle);
3224 if (!NT_SUCCESS(Status)) goto Quickie;
3225
3226 /* Check if this was supposed to be a session-load */
3227 if (Flags)
3228 {
3229 /* We don't support session loading yet */
3230 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3231 goto Quickie;
3232 }
3233
3234 /* Check the loader list again, we should end up in the path below */
3235 goto LoaderScan;
3236 }
3237 else
3238 {
3239 /* We don't have a valid entry */
3240 LdrEntry = NULL;
3241 }
3242
3243 /* Load the image */
3244 Status = MiLoadImageSection(&Section,
3245 &ModuleLoadBase,
3246 FileName,
3247 FALSE,
3248 NULL);
3249 ASSERT(Status != STATUS_ALREADY_COMMITTED);
3250
3251 /* Get the size of the driver */
3252 DriverSize = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment)->ImageInformation.ImageFileSize;
3253
3254 /* Make sure we're not being loaded into session space */
3255 if (!Flags)
3256 {
3257 /* Check for success */
3258 if (NT_SUCCESS(Status))
3259 {
3260 /* Support large pages for drivers */
3261 MiUseLargeDriverPage(DriverSize / PAGE_SIZE,
3262 &ModuleLoadBase,
3263 &BaseName,
3264 TRUE);
3265 }
3266
3267 /* Dereference the section */
3268 ObDereferenceObject(Section);
3269 Section = NULL;
3270 }
3271
3272 /* Check for failure of the load earlier */
3273 if (!NT_SUCCESS(Status))
3274 {
3275 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status);
3276 goto Quickie;
3277 }
3278
3279 /* Relocate the driver */
3280 Status = LdrRelocateImageWithBias(ModuleLoadBase,
3281 0,
3282 "SYSLDR",
3283 STATUS_SUCCESS,
3284 STATUS_CONFLICTING_ADDRESSES,
3285 STATUS_INVALID_IMAGE_FORMAT);
3286 if (!NT_SUCCESS(Status))
3287 {
3288 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status);
3289 goto Quickie;
3290 }
3291
3292 /* Get the NT Header */
3293 NtHeader = RtlImageNtHeader(ModuleLoadBase);
3294
3295 /* Calculate the size we'll need for the entry and allocate it */
3296 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
3297 BaseName.Length +
3298 sizeof(UNICODE_NULL);
3299
3300 /* Allocate the entry */
3301 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
3302 if (!LdrEntry)
3303 {
3304 /* Fail */
3305 Status = STATUS_INSUFFICIENT_RESOURCES;
3306 goto Quickie;
3307 }
3308
3309 /* Setup the entry */
3310 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
3311 LdrEntry->LoadCount = 1;
3312 LdrEntry->LoadedImports = LoadedImports;
3313 LdrEntry->PatchInformation = NULL;
3314
3315 /* Check the version */
3316 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
3317 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
3318 {
3319 /* Mark this image as a native image */
3320 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
3321 }
3322
3323 /* Setup the rest of the entry */
3324 LdrEntry->DllBase = ModuleLoadBase;
3325 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
3326 NtHeader->OptionalHeader.AddressOfEntryPoint);
3327 LdrEntry->SizeOfImage = DriverSize;
3328 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
3329 LdrEntry->SectionPointer = Section;
3330
3331 /* Now write the DLL name */
3332 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
3333 LdrEntry->BaseDllName.Length = BaseName.Length;
3334 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
3335
3336 /* Copy and null-terminate it */
3337 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
3338 BaseName.Buffer,
3339 BaseName.Length);
3340 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3341
3342 /* Now allocate the full name */
3343 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
3344 PrefixName.Length +
3345 sizeof(UNICODE_NULL),
3346 TAG_LDR_WSTR);
3347 if (!LdrEntry->FullDllName.Buffer)
3348 {
3349 /* Don't fail, just set it to zero */
3350 LdrEntry->FullDllName.Length = 0;
3351 LdrEntry->FullDllName.MaximumLength = 0;
3352 }
3353 else
3354 {
3355 /* Set it up */
3356 LdrEntry->FullDllName.Length = PrefixName.Length;
3357 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
3358
3359 /* Copy and null-terminate */
3360 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
3361 PrefixName.Buffer,
3362 PrefixName.Length);
3363 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3364 }
3365
3366 /* Add the entry */
3367 MiProcessLoaderEntry(LdrEntry, TRUE);
3368
3369 /* Resolve imports */
3370 MissingApiName = Buffer;
3371 MissingDriverName = NULL;
3372 Status = MiResolveImageReferences(ModuleLoadBase,
3373 &BaseDirectory,
3374 NULL,
3375 &MissingApiName,
3376 &MissingDriverName,
3377 &LoadedImports);
3378 if (!NT_SUCCESS(Status))
3379 {
3380 BOOLEAN NeedToFreeString = FALSE;
3381
3382 /* If the lowest bit is set to 1, this is a hint that we need to free */
3383 if (*(ULONG_PTR*)&MissingDriverName & 1)
3384 {
3385 NeedToFreeString = TRUE;
3386 *(ULONG_PTR*)&MissingDriverName &= ~1;
3387 }
3388
3389 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status);
3390 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3391 MissingDriverName, MissingApiName);
3392
3393 if (NeedToFreeString)
3394 {
3395 ExFreePoolWithTag(MissingDriverName, TAG_LDR_WSTR);
3396 }
3397
3398 /* Fail */
3399 MiProcessLoaderEntry(LdrEntry, FALSE);
3400
3401 /* Check if we need to free the name */
3402 if (LdrEntry->FullDllName.Buffer)
3403 {
3404 /* Free it */
3405 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
3406 }
3407
3408 /* Free the entry itself */
3409 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
3410 LdrEntry = NULL;
3411 goto Quickie;
3412 }
3413
3414 /* Update the loader entry */
3415 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
3416 LDRP_ENTRY_PROCESSED |
3417 LDRP_MM_LOADED);
3418 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
3419 LdrEntry->LoadedImports = LoadedImports;
3420
3421 /* FIXME: Call driver verifier's loader function */
3422
3423 /* Write-protect the system image */
3424 MiWriteProtectSystemImage(LdrEntry->DllBase);
3425
3426 /* Initialize the security cookie (Win7 is not doing this yet!) */
3427 LdrpInitSecurityCookie(LdrEntry);
3428
3429 /* Check if notifications are enabled */
3430 if (PsImageNotifyEnabled)
3431 {
3432 /* Fill out the notification data */
3433 ImageInfo.Properties = 0;
3434 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
3435 ImageInfo.SystemModeImage = TRUE;
3436 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
3437 ImageInfo.ImageBase = LdrEntry->DllBase;
3438 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
3439
3440 /* Send the notification */
3441 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
3442 }
3443
3444 #ifdef __ROS_ROSSYM__
3445 /* MiCacheImageSymbols doesn't detect rossym */
3446 if (TRUE)
3447 #else
3448 /* Check if there's symbols */
3449 if (MiCacheImageSymbols(LdrEntry->DllBase))
3450 #endif
3451 {
3452 UNICODE_STRING UnicodeTemp;
3453 STRING AnsiTemp;
3454
3455 /* Check if the system root is present */
3456 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
3457 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
3458 {
3459 /* Add the system root */
3460 UnicodeTemp = PrefixName;
3461 UnicodeTemp.Buffer += 11;
3462 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
3463 RtlStringCbPrintfA(Buffer,
3464 MAXIMUM_FILENAME_LENGTH,
3465 "%ws%wZ",
3466 &SharedUserData->NtSystemRoot[2],
3467 &UnicodeTemp);
3468 }
3469 else
3470 {
3471 /* Build the name */
3472 RtlStringCbPrintfA(Buffer, MAXIMUM_FILENAME_LENGTH,
3473 "%wZ", &BaseName);
3474 }
3475
3476 /* Setup the ANSI string */
3477 RtlInitString(&AnsiTemp, Buffer);
3478
3479 /* Notify the debugger */
3480 DbgLoadImageSymbols(&AnsiTemp,
3481 LdrEntry->DllBase,
3482 (ULONG_PTR)PsGetCurrentProcessId());
3483 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
3484 }
3485
3486 /* Page the driver */
3487 ASSERT(Section == NULL);
3488 MiEnablePagingOfDriver(LdrEntry);
3489
3490 /* Return pointers */
3491 *ModuleObject = LdrEntry;
3492 *ImageBaseAddress = LdrEntry->DllBase;
3493
3494 Quickie:
3495 /* Check if we have the lock acquired */
3496 if (LockOwned)
3497 {
3498 /* Release the lock */
3499 KeReleaseMutant(&MmSystemLoadLock, MUTANT_INCREMENT, FALSE, FALSE);
3500 KeLeaveCriticalRegion();
3501 LockOwned = FALSE;
3502 }
3503
3504 /* If we have a file handle, close it */
3505 if (FileHandle) ZwClose(FileHandle);
3506
3507 /* If we have allocated a prefixed name buffer, free it */
3508 if (PrefixedBuffer) ExFreePoolWithTag(PrefixedBuffer, TAG_LDR_WSTR);
3509
3510 /* Free the name buffer and return status */
3511 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
3512 return Status;
3513 }
3514
3515 PLDR_DATA_TABLE_ENTRY
3516 NTAPI
MiLookupDataTableEntry(IN PVOID Address)3517 MiLookupDataTableEntry(IN PVOID Address)
3518 {
3519 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
3520 PLIST_ENTRY NextEntry;
3521 PAGED_CODE();
3522
3523 /* Loop entries */
3524 NextEntry = PsLoadedModuleList.Flink;
3525 do
3526 {
3527 /* Get the loader entry */
3528 LdrEntry = CONTAINING_RECORD(NextEntry,
3529 LDR_DATA_TABLE_ENTRY,
3530 InLoadOrderLinks);
3531
3532 /* Check if the address matches */
3533 if ((Address >= LdrEntry->DllBase) &&
3534 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
3535 LdrEntry->SizeOfImage)))
3536 {
3537 /* Found a match */
3538 FoundEntry = LdrEntry;
3539 break;
3540 }
3541
3542 /* Move on */
3543 NextEntry = NextEntry->Flink;
3544 } while(NextEntry != &PsLoadedModuleList);
3545
3546 /* Return the entry */
3547 return FoundEntry;
3548 }
3549
3550 /* PUBLIC FUNCTIONS ***********************************************************/
3551
3552 /*
3553 * @implemented
3554 */
3555 PVOID
3556 NTAPI
MmPageEntireDriver(IN PVOID AddressWithinSection)3557 MmPageEntireDriver(IN PVOID AddressWithinSection)
3558 {
3559 PMMPTE StartPte, EndPte;
3560 PLDR_DATA_TABLE_ENTRY LdrEntry;
3561 PAGED_CODE();
3562
3563 /* Get the loader entry */
3564 LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
3565 if (!LdrEntry) return NULL;
3566
3567 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3568 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
3569 {
3570 /* Don't do anything, just return the base address */
3571 return LdrEntry->DllBase;
3572 }
3573
3574 /* Wait for active DPCs to finish before we page out the driver */
3575 KeFlushQueuedDpcs();
3576
3577 /* Get the PTE range for the whole driver image */
3578 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
3579 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
3580
3581 /* Enable paging for the PTE range */
3582 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
3583 MiSetPagingOfDriver(StartPte, EndPte);
3584
3585 /* Return the base address */
3586 return LdrEntry->DllBase;
3587 }
3588
3589 /*
3590 * @unimplemented
3591 */
3592 VOID
3593 NTAPI
MmResetDriverPaging(IN PVOID AddressWithinSection)3594 MmResetDriverPaging(IN PVOID AddressWithinSection)
3595 {
3596 UNIMPLEMENTED;
3597 }
3598
3599 /*
3600 * @implemented
3601 */
3602 PVOID
3603 NTAPI
MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)3604 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
3605 {
3606 PVOID ProcAddress = NULL;
3607 ANSI_STRING AnsiRoutineName;
3608 NTSTATUS Status;
3609 PLIST_ENTRY NextEntry;
3610 PLDR_DATA_TABLE_ENTRY LdrEntry;
3611 BOOLEAN Found = FALSE;
3612 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
3613 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
3614 ULONG Modules = 0;
3615
3616 /* Convert routine to ANSI name */
3617 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
3618 SystemRoutineName,
3619 TRUE);
3620 if (!NT_SUCCESS(Status)) return NULL;
3621
3622 /* Lock the list */
3623 KeEnterCriticalRegion();
3624 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
3625
3626 /* Loop the loaded module list */
3627 NextEntry = PsLoadedModuleList.Flink;
3628 while (NextEntry != &PsLoadedModuleList)
3629 {
3630 /* Get the entry */
3631 LdrEntry = CONTAINING_RECORD(NextEntry,
3632 LDR_DATA_TABLE_ENTRY,
3633 InLoadOrderLinks);
3634
3635 /* Check if it's the kernel or HAL */
3636 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
3637 {
3638 /* Found it */
3639 Found = TRUE;
3640 Modules++;
3641 }
3642 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
3643 {
3644 /* Found it */
3645 Found = TRUE;
3646 Modules++;
3647 }
3648
3649 /* Check if we found a valid binary */
3650 if (Found)
3651 {
3652 /* Find the procedure name */
3653 ProcAddress = RtlFindExportedRoutineByName(LdrEntry->DllBase,
3654 AnsiRoutineName.Buffer);
3655
3656 /* Break out if we found it or if we already tried both modules */
3657 if (ProcAddress) break;
3658 if (Modules == 2) break;
3659 }
3660
3661 /* Keep looping */
3662 NextEntry = NextEntry->Flink;
3663 }
3664
3665 /* Release the lock */
3666 ExReleaseResourceLite(&PsLoadedModuleResource);
3667 KeLeaveCriticalRegion();
3668
3669 /* Free the string and return */
3670 RtlFreeAnsiString(&AnsiRoutineName);
3671 return ProcAddress;
3672 }
3673
3674 /* EOF */
3675