Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

sysload.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 sysload.c 00008 00009 Abstract: 00010 00011 This module contains the code to load DLLs into the system portion of 00012 the address space and calls the DLL at its initialization entry point. 00013 00014 Author: 00015 00016 Lou Perazzoli 21-May-1991 00017 Landy Wang 02-June-1997 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include "mi.h" 00024 00025 // 00026 // The LDR_DATA_TABLE_ENTRY->LoadedImports is used as a list of imported DLLs. 00027 // 00028 // This field is zero if the module was loaded at boot time and the 00029 // import information was never filled in. 00030 // 00031 // This field is -1 if no imports are defined by the module. 00032 // 00033 // This field contains a valid paged pool PLDR_DATA_TABLE_ENTRY pointer 00034 // with a low-order (bit 0) tag of 1 if there is only 1 usable import needed 00035 // by this driver. 00036 // 00037 // This field will contain a valid paged pool PLOAD_IMPORTS pointer in all 00038 // other cases (ie: where at least 2 imports exist). 00039 // 00040 00041 typedef struct _LOAD_IMPORTS { 00042 SIZE_T Count; 00043 PLDR_DATA_TABLE_ENTRY Entry[1]; 00044 } LOAD_IMPORTS, *PLOAD_IMPORTS; 00045 00046 #define LOADED_AT_BOOT ((PLOAD_IMPORTS)0) 00047 #define NO_IMPORTS_USED ((PLOAD_IMPORTS)-2) 00048 00049 #define SINGLE_ENTRY(ImportVoid) ((ULONG)((ULONG_PTR)(ImportVoid) & 0x1)) 00050 00051 #define SINGLE_ENTRY_TO_POINTER(ImportVoid) ((PLDR_DATA_TABLE_ENTRY)((ULONG_PTR)(ImportVoid) & ~0x1)) 00052 00053 #define POINTER_TO_SINGLE_ENTRY(Pointer) ((PLDR_DATA_TABLE_ENTRY)((ULONG_PTR)(Pointer) | 0x1)) 00054 00055 KMUTANT MmSystemLoadLock; 00056 00057 ULONG MmTotalSystemDriverPages; 00058 00059 ULONG MmDriverCommit; 00060 00061 BOOLEAN MiFirstDriverLoadEver = TRUE; 00062 00063 // 00064 // This key is set to TRUE to make more memory below 16mb available for drivers. 00065 // It can be cleared via the registry. 00066 // 00067 00068 LOGICAL MmMakeLowMemory = TRUE; 00069 00070 // 00071 // Enabled via the registry to identify drivers which unload without releasing 00072 // resources or still have active timers, etc. 00073 // 00074 00075 PUNLOADED_DRIVERS MiUnloadedDrivers; 00076 00077 ULONG MiLastUnloadedDriver; 00078 ULONG MiTotalUnloads; 00079 ULONG MiUnloadsSkipped; 00080 00081 // 00082 // This can be set by the registry. 00083 // 00084 00085 ULONG MmEnforceWriteProtection = 1; 00086 00087 // 00088 // Referenced by ke\bugcheck.c. 00089 // 00090 00091 PVOID ExPoolCodeStart; 00092 PVOID ExPoolCodeEnd; 00093 PVOID MmPoolCodeStart; 00094 PVOID MmPoolCodeEnd; 00095 PVOID MmPteCodeStart; 00096 PVOID MmPteCodeEnd; 00097 00098 // 00099 // ****** temporary ****** 00100 // 00101 // Define reference to external spin lock. 00102 // 00103 // ****** temporary ****** 00104 // 00105 00106 extern KSPIN_LOCK PsLoadedModuleSpinLock; 00107 00108 ULONG 00109 LdrDoubleRelocateImage ( 00110 IN PVOID NewBase, 00111 IN PVOID CurrentBase, 00112 IN PUCHAR LoaderName, 00113 IN ULONG Success, 00114 IN ULONG Conflict, 00115 IN ULONG Invalid 00116 ); 00117 00118 #if DBG 00119 PFN_NUMBER MiPagesConsumed; 00120 #endif 00121 00122 ULONG 00123 CacheImageSymbols( 00124 IN PVOID ImageBase 00125 ); 00126 00127 NTSTATUS 00128 MiResolveImageReferences( 00129 PVOID ImageBase, 00130 IN PUNICODE_STRING ImageFileDirectory, 00131 IN PUNICODE_STRING NamePrefix OPTIONAL, 00132 IN BOOLEAN LoadInSessionSpace, 00133 OUT PCHAR *MissingProcedureName, 00134 OUT PWSTR *MissingDriverName, 00135 OUT PLOAD_IMPORTS *LoadedImports 00136 ); 00137 00138 NTSTATUS 00139 MiSnapThunk( 00140 IN PVOID DllBase, 00141 IN PVOID ImageBase, 00142 IN PIMAGE_THUNK_DATA NameThunk, 00143 OUT PIMAGE_THUNK_DATA AddrThunk, 00144 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 00145 IN ULONG ExportSize, 00146 IN BOOLEAN SnapForwarder, 00147 OUT PCHAR *MissingProcedureName 00148 ); 00149 00150 NTSTATUS 00151 MiLoadImageSection ( 00152 IN PSECTION SectionPointer, 00153 OUT PVOID *ImageBase, 00154 IN PUNICODE_STRING ImageFileName, 00155 IN BOOLEAN LoadInSessionSpace 00156 ); 00157 00158 VOID 00159 MiEnablePagingOfDriver ( 00160 IN PVOID ImageHandle 00161 ); 00162 00163 VOID 00164 MiSetPagingOfDriver ( 00165 IN PMMPTE PointerPte, 00166 IN PMMPTE LastPte, 00167 IN BOOLEAN SessionSpace 00168 ); 00169 00170 PVOID 00171 MiLookupImageSectionByName ( 00172 IN PVOID Base, 00173 IN BOOLEAN MappedAsImage, 00174 IN PCHAR SectionName, 00175 OUT PULONG SectionSize 00176 ); 00177 00178 VOID 00179 MiClearImports( 00180 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 00181 ); 00182 00183 NTSTATUS 00184 MiBuildImportsForBootDrivers( 00185 VOID 00186 ); 00187 00188 NTSTATUS 00189 MmCheckSystemImage( 00190 IN HANDLE ImageFileHandle 00191 ); 00192 00193 LONG 00194 MiMapCacheExceptionFilter ( 00195 OUT PNTSTATUS Status, 00196 IN PEXCEPTION_POINTERS ExceptionPointer 00197 ); 00198 00199 ULONG 00200 MiSetProtectionOnTransitionPte ( 00201 IN PMMPTE PointerPte, 00202 IN ULONG ProtectionMask 00203 ); 00204 00205 NTSTATUS 00206 MiDereferenceImports ( 00207 IN PLOAD_IMPORTS ImportList 00208 ); 00209 00210 LOGICAL 00211 MiCallDllUnloadAndUnloadDll( 00212 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 00213 ); 00214 00215 PVOID 00216 MiLocateExportName ( 00217 IN PVOID DllBase, 00218 IN PCHAR FunctionName 00219 ); 00220 00221 NTSTATUS 00222 MiLoadSystemImage ( 00223 IN PUNICODE_STRING ImageFileName, 00224 IN PUNICODE_STRING NamePrefix OPTIONAL, 00225 IN PUNICODE_STRING LoadedBaseName OPTIONAL, 00226 IN BOOLEAN LoadInSessionSpace, 00227 OUT PVOID *ImageHandle, 00228 OUT PVOID *ImageBaseAddress, 00229 IN BOOLEAN LockDownPages 00230 ); 00231 00232 VOID 00233 MiRememberUnloadedDriver ( 00234 IN PUNICODE_STRING DriverName, 00235 IN PVOID Address, 00236 IN ULONG Length 00237 ); 00238 00239 VOID 00240 MiWriteProtectSystemImage ( 00241 IN PVOID DllBase 00242 ); 00243 00244 VOID 00245 MiLocateKernelSections ( 00246 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 00247 ); 00248 00249 VOID 00250 MiUpdateThunks ( 00251 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 00252 IN PVOID OldAddress, 00253 IN PVOID NewAddress, 00254 IN ULONG NumberOfBytes 00255 ); 00256 00257 NTSTATUS 00258 MiCheckPageFilePath ( 00259 PFILE_OBJECT FileObject 00260 ); 00261 00262 PVOID 00263 MiFindExportedRoutineByName( 00264 IN PLDR_DATA_TABLE_ENTRY DataTableEntry, 00265 IN PANSI_STRING AnsiImageRoutineName 00266 ); 00267 00268 extern LOGICAL MiNoLowMemory; 00269 00270 VOID 00271 MiRemoveLowPages ( 00272 VOID 00273 ); 00274 00275 #ifdef ALLOC_PRAGMA 00276 #pragma alloc_text(PAGE,MmCheckSystemImage) 00277 #pragma alloc_text(PAGE,MmLoadSystemImage) 00278 #pragma alloc_text(PAGE,MmLoadAndLockSystemImage) 00279 #pragma alloc_text(PAGE,MiLoadSystemImage) 00280 #pragma alloc_text(PAGE,MiResolveImageReferences) 00281 #pragma alloc_text(PAGE,MiSnapThunk) 00282 #pragma alloc_text(PAGE,MiEnablePagingOfDriver) 00283 #pragma alloc_text(PAGE,MmPageEntireDriver) 00284 #pragma alloc_text(PAGE,MiSetImageProtect) 00285 #pragma alloc_text(PAGE,MiDereferenceImports) 00286 #pragma alloc_text(PAGE,MiCallDllUnloadAndUnloadDll) 00287 #pragma alloc_text(PAGE,MiLocateExportName) 00288 #pragma alloc_text(PAGE,MiClearImports) 00289 #pragma alloc_text(PAGE,MiWriteProtectSystemImage) 00290 #pragma alloc_text(PAGE,MmGetSystemRoutineAddress) 00291 #pragma alloc_text(PAGE,MiFindExportedRoutineByName) 00292 #pragma alloc_text(INIT,MiBuildImportsForBootDrivers) 00293 #pragma alloc_text(INIT,MiReloadBootLoadedDrivers) 00294 #pragma alloc_text(INIT,MiUpdateThunks) 00295 #pragma alloc_text(INIT,MiInitializeLoadedModuleList) 00296 #pragma alloc_text(INIT,MiLocateKernelSections) 00297 #pragma alloc_text(INIT,MmCallDllInitialize) 00298 00299 #if !defined(NT_UP) 00300 #pragma alloc_text(PAGE,MmVerifyImageIsOkForMpUse) 00301 #endif // NT_UP 00302 00303 #pragma alloc_text(PAGELK,MiLoadImageSection) 00304 #pragma alloc_text(PAGELK,MmFreeDriverInitialization) 00305 #pragma alloc_text(PAGELK,MmUnloadSystemImage) 00306 #pragma alloc_text(PAGELK,MiRememberUnloadedDriver) 00307 #pragma alloc_text(PAGELK,MiSetPagingOfDriver) 00308 #pragma alloc_text(PAGELK,MmResetDriverPaging) 00309 #endif 00310 00311 CHAR MiPteStr[] = "\0"; 00312 00313 00314 NTSTATUS 00315 MmLoadSystemImage ( 00316 IN PUNICODE_STRING ImageFileName, 00317 IN PUNICODE_STRING NamePrefix OPTIONAL, 00318 IN PUNICODE_STRING LoadedBaseName OPTIONAL, 00319 IN BOOLEAN LoadInSessionSpace, 00320 OUT PVOID *ImageHandle, 00321 OUT PVOID *ImageBaseAddress 00322 ) 00323 00324 /*++ 00325 00326 Routine Description: 00327 00328 This routine reads the image pages from the specified section into 00329 the system and returns the address of the DLL's header. 00330 00331 At successful completion, the Section is referenced so it remains 00332 until the system image is unloaded. 00333 00334 Arguments: 00335 00336 ImageName - Supplies the Unicode name of the image to load. 00337 00338 ImageFileName - Supplies the full path name (including the image name) 00339 of the image to load. 00340 00341 NamePrefix - Supplies the prefix to use with the image name on load 00342 operations. This is used to load the same image multiple 00343 times, by using different prefixes 00344 00345 LoadedBaseName - If present, supplies the base name to use on the 00346 loaded image instead of the base name found on the 00347 image name. 00348 00349 LoadInSessionSpace - Supplies whether to load this image in session space - 00350 ie: each session will have a different copy of this driver 00351 with pages shared as much as possible via copy on write. 00352 00353 ImageHandle - Returns an opaque pointer to the referenced section object 00354 of the image that was loaded. 00355 00356 ImageBaseAddress - Returns the image base within the system. 00357 00358 Return Value: 00359 00360 Status of the load operation. 00361 00362 --*/ 00363 00364 { 00365 PAGED_CODE(); 00366 00367 return MiLoadSystemImage ( 00368 ImageFileName, 00369 NamePrefix, 00370 LoadedBaseName, 00371 LoadInSessionSpace, 00372 ImageHandle, 00373 ImageBaseAddress, 00374 FALSE 00375 ); 00376 } 00377 00378 NTSTATUS 00379 MmLoadAndLockSystemImage ( 00380 IN PUNICODE_STRING ImageFileName, 00381 IN PUNICODE_STRING NamePrefix OPTIONAL, 00382 IN PUNICODE_STRING LoadedBaseName OPTIONAL, 00383 OUT PVOID *ImageHandle, 00384 OUT PVOID *ImageBaseAddress 00385 ) 00386 00387 /*++ 00388 00389 Routine Description: 00390 00391 This routine reads the image pages from the specified section into 00392 the system and returns the address of the DLL's header. Very similar 00393 to MmLoadSystemImage, except that it also locks down the driver pages. 00394 This is needed for things like the dump driver because we cannot page it 00395 back in after the system has crashed (when we want to write the system 00396 dump to the pagefile). 00397 00398 At successful completion, the Section is referenced so it remains 00399 until the system image is unloaded. 00400 00401 Arguments: 00402 00403 ImageName - Supplies the Unicode name of the image to load. 00404 00405 ImageFileName - Supplies the full path name (including the image name) 00406 of the image to load. 00407 00408 NamePrefix - Supplies the prefix to use with the image name on load 00409 operations. This is used to load the same image multiple 00410 times, by using different prefixes 00411 00412 LoadedBaseName - If present, supplies the base name to use on the 00413 loaded image instead of the base name found on the 00414 image name. 00415 00416 ImageHandle - Returns an opaque pointer to the referenced section object 00417 of the image that was loaded. 00418 00419 ImageBaseAddress - Returns the image base within the system. 00420 00421 Return Value: 00422 00423 Status of the load operation. 00424 00425 --*/ 00426 00427 { 00428 PAGED_CODE(); 00429 00430 return MiLoadSystemImage ( 00431 ImageFileName, 00432 NamePrefix, 00433 LoadedBaseName, 00434 FALSE, 00435 ImageHandle, 00436 ImageBaseAddress, 00437 TRUE 00438 ); 00439 } 00440 00441 00442 NTSTATUS 00443 MiLoadSystemImage ( 00444 IN PUNICODE_STRING ImageFileName, 00445 IN PUNICODE_STRING NamePrefix OPTIONAL, 00446 IN PUNICODE_STRING LoadedBaseName OPTIONAL, 00447 IN BOOLEAN LoadInSessionSpace, 00448 OUT PVOID *ImageHandle, 00449 OUT PVOID *ImageBaseAddress, 00450 IN BOOLEAN LockDownPages 00451 ) 00452 00453 /*++ 00454 00455 Routine Description: 00456 00457 This routine reads the image pages from the specified section into 00458 the system and returns the address of the DLL's header. 00459 00460 At successful completion, the Section is referenced so it remains 00461 until the system image is unloaded. 00462 00463 Arguments: 00464 00465 ImageFileName - Supplies the full path name (including the image name) 00466 of the image to load. 00467 00468 NamePrefix - If present, supplies the prefix to use with the image name on 00469 load operations. This is used to load the same image multiple 00470 times, by using different prefixes. 00471 00472 LoadedBaseName - If present, supplies the base name to use on the 00473 loaded image instead of the base name found on the 00474 image name. 00475 00476 LoadInSessionSpace - Supplies whether to load this image in session space. 00477 Each session gets a different copy of this driver with 00478 pages shared as much as possible via copy on write. 00479 00480 ImageHandle - Returns an opaque pointer to the referenced section object 00481 of the image that was loaded. 00482 00483 ImageBaseAddress - Returns the image base within the system. 00484 00485 LockDownPages - Supplies TRUE if the image pages should be made nonpagable. 00486 00487 Return Value: 00488 00489 Status of the load operation. 00490 00491 --*/ 00492 00493 { 00494 KIRQL OldIrql; 00495 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00496 LDR_DATA_TABLE_ENTRY TempDataTableEntry; 00497 NTSTATUS Status; 00498 PSECTION SectionPointer; 00499 PIMAGE_NT_HEADERS NtHeaders; 00500 UNICODE_STRING PrefixedImageName; 00501 UNICODE_STRING BaseName; 00502 UNICODE_STRING BaseDirectory; 00503 OBJECT_ATTRIBUTES ObjectAttributes; 00504 HANDLE FileHandle; 00505 HANDLE SectionHandle; 00506 IO_STATUS_BLOCK IoStatus; 00507 CHAR NameBuffer[ MAXIMUM_FILENAME_LENGTH ]; 00508 PLIST_ENTRY NextEntry; 00509 ULONG NumberOfPtes; 00510 ULONG_PTR ViewSize; 00511 PCHAR MissingProcedureName; 00512 PWSTR MissingDriverName; 00513 PLOAD_IMPORTS LoadedImports; 00514 PMMSESSION Session; 00515 BOOLEAN AlreadyOpen; 00516 BOOLEAN IssueUnloadOnFailure; 00517 ULONG SectionAccess; 00518 volatile PMMPTE PointerPpe; 00519 MMPTE PpeContents; 00520 00521 PAGED_CODE(); 00522 00523 LoadedImports = (PLOAD_IMPORTS)NO_IMPORTS_USED; 00524 SectionPointer = (PVOID)-1; 00525 FileHandle = (HANDLE)0; 00526 MissingProcedureName = NULL; 00527 MissingDriverName = NULL; 00528 IssueUnloadOnFailure = FALSE; 00529 00530 if (LoadInSessionSpace == TRUE) { 00531 00532 ASSERT (NamePrefix == NULL); 00533 ASSERT (LoadedBaseName == NULL); 00534 00535 if (MiHydra == TRUE) { 00536 00537 if (PsGetCurrentProcess()->Vm.u.Flags.ProcessInSession == 0) { 00538 #if DBG 00539 DbgPrint ("MiLoadSystemImage: no session space!\n"); 00540 #endif 00541 return STATUS_NO_MEMORY; 00542 } 00543 00544 ASSERT (MmIsAddressValid (MmSessionSpace) == TRUE); 00545 00546 Session = &MmSessionSpace->Session; 00547 } 00548 else { 00549 Session = &MmSession; 00550 LoadInSessionSpace = FALSE; 00551 } 00552 } 00553 else { 00554 Session = &MmSession; 00555 } 00556 00557 // 00558 // Get name roots 00559 // 00560 00561 if (ImageFileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { 00562 PWCHAR p; 00563 ULONG l; 00564 00565 p = &ImageFileName->Buffer[ImageFileName->Length>>1]; 00566 while (*(p-1) != OBJ_NAME_PATH_SEPARATOR) { 00567 p--; 00568 } 00569 l = (ULONG)(&ImageFileName->Buffer[ImageFileName->Length>>1] - p); 00570 l *= sizeof(WCHAR); 00571 BaseName.Length = (USHORT)l; 00572 BaseName.Buffer = p; 00573 } else { 00574 BaseName.Length = ImageFileName->Length; 00575 BaseName.Buffer = ImageFileName->Buffer; 00576 } 00577 00578 BaseName.MaximumLength = BaseName.Length; 00579 BaseDirectory = *ImageFileName; 00580 BaseDirectory.Length -= BaseName.Length; 00581 BaseDirectory.MaximumLength = BaseDirectory.Length; 00582 PrefixedImageName = *ImageFileName; 00583 00584 // 00585 // If there's a name prefix, add it to the PrefixedImageName. 00586 // 00587 00588 if (NamePrefix) { 00589 PrefixedImageName.MaximumLength = 00590 BaseDirectory.Length + NamePrefix->Length + BaseName.Length; 00591 00592 PrefixedImageName.Buffer = ExAllocatePoolWithTag ( 00593 NonPagedPool, 00594 PrefixedImageName.MaximumLength, 00595 'dLmM' 00596 ); 00597 00598 if (!PrefixedImageName.Buffer) { 00599 return STATUS_INSUFFICIENT_RESOURCES; 00600 } 00601 00602 PrefixedImageName.Length = 0; 00603 RtlAppendUnicodeStringToString(&PrefixedImageName, &BaseDirectory); 00604 RtlAppendUnicodeStringToString(&PrefixedImageName, NamePrefix); 00605 RtlAppendUnicodeStringToString(&PrefixedImageName, &BaseName); 00606 00607 // 00608 // Alter the basename to match 00609 // 00610 00611 BaseName.Buffer = PrefixedImageName.Buffer + BaseDirectory.Length / sizeof(WCHAR); 00612 BaseName.Length += NamePrefix->Length; 00613 BaseName.MaximumLength += NamePrefix->Length; 00614 } 00615 00616 // 00617 // If there's a loaded base name, use it instead of the base name. 00618 // 00619 00620 if (LoadedBaseName) { 00621 BaseName = *LoadedBaseName; 00622 } 00623 00624 #if DBG 00625 if ( NtGlobalFlag & FLG_SHOW_LDR_SNAPS ) { 00626 DbgPrint( "MM:SYSLDR Loading %wZ (%wZ) %s\n", 00627 &PrefixedImageName, 00628 &BaseName, 00629 LoadInSessionSpace ? "in session space" : " "); 00630 } 00631 #endif 00632 00633 AlreadyOpen = FALSE; 00634 00635 // 00636 // Arbitrary process context so prevent suspend APCs now. 00637 // 00638 00639 KeEnterCriticalRegion(); 00640 00641 KeWaitForSingleObject (&MmSystemLoadLock, 00642 WrVirtualMemory, 00643 KernelMode, 00644 FALSE, 00645 (PLARGE_INTEGER)NULL); 00646 00647 // 00648 // Check to see if this name already exists in the loader database. 00649 // 00650 00651 NextEntry = PsLoadedModuleList.Flink; 00652 while (NextEntry != &PsLoadedModuleList) { 00653 00654 DataTableEntry = CONTAINING_RECORD(NextEntry, 00655 LDR_DATA_TABLE_ENTRY, 00656 InLoadOrderLinks); 00657 00658 if (RtlEqualUnicodeString (&PrefixedImageName, 00659 &DataTableEntry->FullDllName, 00660 TRUE)) { 00661 00662 if (LoadInSessionSpace == TRUE) { 00663 00664 if (MI_IS_SESSION_ADDRESS (DataTableEntry->DllBase) == FALSE) { 00665 00666 // 00667 // The caller is trying to load a driver in session space 00668 // that has already been loaded in system space. This is 00669 // not allowed. 00670 // 00671 00672 Status = STATUS_CONFLICTING_ADDRESSES; 00673 goto return2; 00674 } 00675 00676 AlreadyOpen = TRUE; 00677 00678 // 00679 // The LoadCount should generally not be 0 here, but it is 00680 // possible in the case where an attempt has been made to 00681 // unload a DLL on last dereference, but the DLL refused to 00682 // unload. 00683 // 00684 00685 DataTableEntry->LoadCount += 1; 00686 SectionPointer = DataTableEntry->SectionPointer; 00687 break; 00688 } 00689 else { 00690 if (MI_IS_SESSION_ADDRESS (DataTableEntry->DllBase) == TRUE) { 00691 00692 // 00693 // The caller is trying to load a driver in systemwide space 00694 // that has already been loaded in session space. This is 00695 // not allowed. 00696 // 00697 00698 Status = STATUS_CONFLICTING_ADDRESSES; 00699 goto return2; 00700 } 00701 } 00702 00703 *ImageHandle = DataTableEntry; 00704 *ImageBaseAddress = DataTableEntry->DllBase; 00705 Status = STATUS_IMAGE_ALREADY_LOADED; 00706 goto return2; 00707 } 00708 00709 NextEntry = NextEntry->Flink; 00710 } 00711 00712 ASSERT (AlreadyOpen == TRUE || NextEntry == &PsLoadedModuleList); 00713 00714 if (AlreadyOpen == FALSE) { 00715 00716 DataTableEntry = NULL; 00717 00718 // 00719 // Attempt to open the driver image itself. If this fails, then the 00720 // driver image cannot be located, so nothing else matters. 00721 // 00722 00723 InitializeObjectAttributes (&ObjectAttributes, 00724 ImageFileName, 00725 OBJ_CASE_INSENSITIVE, 00726 NULL, 00727 NULL ); 00728 00729 Status = ZwOpenFile (&FileHandle, 00730 FILE_EXECUTE, 00731 &ObjectAttributes, 00732 &IoStatus, 00733 FILE_SHARE_READ | FILE_SHARE_DELETE, 00734 0 ); 00735 00736 if (!NT_SUCCESS(Status)) { 00737 00738 #if DBG 00739 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 00740 DbgPrint ("MiLoadImageSection: cannot open %wZ\n", 00741 ImageFileName); 00742 } 00743 #endif 00744 // 00745 // Don't raise hard error status for file not found. 00746 // 00747 00748 goto return2; 00749 } 00750 00751 Status = MmCheckSystemImage(FileHandle); 00752 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) || 00753 (Status == STATUS_IMAGE_MP_UP_MISMATCH) || 00754 (Status == STATUS_INVALID_IMAGE_PROTECT)) { 00755 goto return1; 00756 } 00757 00758 // 00759 // Now attempt to create an image section for the file. If this fails, 00760 // then the driver file is not an image. Session space drivers are 00761 // shared text with copy on write data, so don't allow writes here. 00762 // 00763 00764 if (LoadInSessionSpace == TRUE) { 00765 SectionAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE; 00766 } 00767 else { 00768 SectionAccess = SECTION_ALL_ACCESS; 00769 } 00770 00771 Status = ZwCreateSection (&SectionHandle, 00772 SectionAccess, 00773 (POBJECT_ATTRIBUTES) NULL, 00774 (PLARGE_INTEGER) NULL, 00775 PAGE_EXECUTE, 00776 SEC_IMAGE, 00777 FileHandle ); 00778 00779 if (!NT_SUCCESS(Status)) { 00780 goto return1; 00781 } 00782 00783 // 00784 // Now reference the section handle. 00785 // 00786 00787 Status = ObReferenceObjectByHandle (SectionHandle, 00788 SECTION_MAP_EXECUTE, 00789 MmSectionObjectType, 00790 KernelMode, 00791 (PVOID *) &SectionPointer, 00792 (POBJECT_HANDLE_INFORMATION) NULL ); 00793 00794 ZwClose (SectionHandle); 00795 if (!NT_SUCCESS (Status)) { 00796 goto return1; 00797 } 00798 00799 if (SectionPointer->Segment->ControlArea->NumberOfSubsections == 1) { 00800 if ((LoadInSessionSpace == FALSE) && 00801 (SectionPointer->Segment->BasedAddress != (PVOID)Session->SystemSpaceViewStart)) { 00802 00803 PSECTION SectionPointer2; 00804 00805 // 00806 // The driver was linked with subsection alignment such that 00807 // it is mapped with one subsection. Since the CreateSection 00808 // above guarantees that the driver image is indeed a 00809 // satisfactory executable, map it directly now to reuse the 00810 // cache from the MmCheckSystemImage call above. 00811 // 00812 00813 Status = ZwCreateSection (&SectionHandle, 00814 SectionAccess, 00815 (POBJECT_ATTRIBUTES) NULL, 00816 (PLARGE_INTEGER) NULL, 00817 PAGE_EXECUTE, 00818 SEC_COMMIT, 00819 FileHandle ); 00820 00821 if (NT_SUCCESS(Status)) { 00822 00823 Status = ObReferenceObjectByHandle ( 00824 SectionHandle, 00825 SECTION_MAP_EXECUTE, 00826 MmSectionObjectType, 00827 KernelMode, 00828 (PVOID *) &SectionPointer2, 00829 (POBJECT_HANDLE_INFORMATION) NULL ); 00830 00831 ZwClose (SectionHandle); 00832 00833 if (NT_SUCCESS (Status)) { 00834 00835 // 00836 // The number of PTEs won't match if the image is 00837 // stripped and the debug directory crosses the last 00838 // sector boundary of the file. We could still use the 00839 // new section, but these cases are under 2% of all the 00840 // drivers loaded so don't bother. 00841 // 00842 00843 if (SectionPointer->Segment->TotalNumberOfPtes == SectionPointer2->Segment->TotalNumberOfPtes) { 00844 ObDereferenceObject (SectionPointer); 00845 SectionPointer = SectionPointer2; 00846 } 00847 else { 00848 ObDereferenceObject (SectionPointer2); 00849 } 00850 } 00851 } 00852 } 00853 } 00854 00855 } 00856 00857 if ((LoadInSessionSpace == FALSE) && 00858 (SectionPointer->Segment->BasedAddress == (PVOID)Session->SystemSpaceViewStart) && 00859 (SectionPointer->Segment->ControlArea->NumberOfMappedViews == 0)) { 00860 NumberOfPtes = 0; 00861 ViewSize = 0; 00862 00863 Status = MmMapViewInSystemSpace (SectionPointer, 00864 ImageBaseAddress, 00865 &ViewSize); 00866 if ((NT_SUCCESS( Status ) && 00867 (*ImageBaseAddress == SectionPointer->Segment->BasedAddress))) { 00868 00869 SectionPointer->Segment->SystemImageBase = *ImageBaseAddress; 00870 SectionPointer->Segment->ControlArea->u.Flags.ImageMappedInSystemSpace = 1; 00871 NumberOfPtes = (ULONG)((ViewSize + 1) >> PAGE_SHIFT); 00872 MiSetImageProtect(SectionPointer->Segment, MM_EXECUTE_READWRITE); 00873 00874 #if defined (_AXP64_) 00875 00876 // 00877 // This is needed because win32k calls are made from the system 00878 // process on non-Hydra systems. On Hydra systems, these calls 00879 // are always made from the relevant session's csrss process. 00880 // If these were the same, this PPE duplication could be removed. 00881 // 00882 00883 PointerPpe = MiGetPpeAddress (*ImageBaseAddress); 00884 ASSERT (PointerPpe->u.Long != 0); 00885 PpeContents = *PointerPpe; 00886 KeAttachProcess (&PsInitialSystemProcess->Pcb); 00887 ASSERT (PointerPpe->u.Long == 0); 00888 *PointerPpe = PpeContents; 00889 KeDetachProcess(); 00890 #endif 00891 goto BindImage; 00892 } 00893 } 00894 00895 MmLockPagableSectionByHandle (ExPageLockHandle); 00896 00897 // 00898 // Load the driver from the filesystem and pick a virtual address for it. 00899 // For Hydra, this means also allocating session virtual space, and 00900 // after mapping a view of the image, either copying or sharing the 00901 // driver's code and data in the session virtual space. 00902 // 00903 // If it is a share map because the image was loaded at its based address, 00904 // the disk image will remain busy. 00905 // 00906 00907 Status = MiLoadImageSection (SectionPointer, 00908 ImageBaseAddress, 00909 ImageFileName, 00910 LoadInSessionSpace); 00911 00912 MmUnlockPagableImageSection (ExPageLockHandle); 00913 00914 NumberOfPtes = SectionPointer->Segment->TotalNumberOfPtes; 00915 00916 if (Status == STATUS_ALREADY_COMMITTED) { 00917 00918 // 00919 // This is a driver that was relocated that is being loaded into 00920 // the same session space twice. Don't increment the overall load 00921 // count - just the image count in the session which has already been 00922 // done. 00923 // 00924 00925 ASSERT (MiHydra == TRUE); 00926 ASSERT (AlreadyOpen == TRUE); 00927 ASSERT (LoadInSessionSpace == TRUE); 00928 ASSERT (DataTableEntry != NULL); 00929 ASSERT (DataTableEntry->LoadCount > 1); 00930 00931 *ImageHandle = DataTableEntry; 00932 *ImageBaseAddress = DataTableEntry->DllBase; 00933 00934 DataTableEntry->LoadCount -= 1; 00935 Status = STATUS_SUCCESS; 00936 goto return1; 00937 } 00938 00939 if (MiFirstDriverLoadEver == TRUE) { 00940 00941 NTSTATUS PagingPathStatus; 00942 00943 // 00944 // Check with all of the drivers along the path to win32k.sys to 00945 // ensure that they are willing to follow the rules required 00946 // of them and to give them a chance to lock down code and data 00947 // that needs to be locked. If any of the drivers along the path 00948 // refuses to participate, fail the win32k.sys load. 00949 // 00950 00951 // 00952 // It is assumed that all drivers live on the same physical drive, so 00953 // when the very first driver is loaded, this check can be made. 00954 // This eliminates the need to check for things like relocated win32ks, 00955 // Terminal Server systems, etc. 00956 // 00957 00958 PagingPathStatus = MiCheckPageFilePath (SectionPointer->Segment->ControlArea->FilePointer); 00959 00960 if (!NT_SUCCESS(PagingPathStatus)) { 00961 00962 KdPrint(( "MiCheckPageFilePath FAILED for win32k.sys: %x\n", 00963 PagingPathStatus )); 00964 00965 // 00966 // BUGBUG: Failing the insertion of win32k.sys' device in the 00967 // pagefile path is commented out until the storage drivers have 00968 // been modified to correctly handle this request. Add code 00969 // here to release relevant resources for the error path. 00970 // 00971 } 00972 00973 MiFirstDriverLoadEver = FALSE; 00974 } 00975 00976 // 00977 // Normal drivers are dereferenced here and their images can then be 00978 // overwritten. This is ok because we've already read the whole thing 00979 // into memory and from here until reboot (or unload), we back them 00980 // with the pagefile. 00981 // 00982 // win32k.sys and session space drivers are the exception - these images 00983 // are inpaged from the filesystem and we need to keep our reference to 00984 // the file so that it doesn't get overwritten. 00985 // 00986 00987 if (LoadInSessionSpace == FALSE) { 00988 ObDereferenceObject (SectionPointer); 00989 SectionPointer = (PVOID)-1; 00990 } 00991 00992 // 00993 // The module LoadCount will be 1 here if the module was just loaded. 00994 // The LoadCount will be >1 if it was attached to by a session (as opposed 00995 // to just loaded). 00996 // 00997 00998 if (!NT_SUCCESS(Status)) { 00999 if (AlreadyOpen == TRUE) { 01000 01001 // 01002 // We're failing and we were just attaching to an already loaded 01003 // driver. We don't want to go through the forced unload path 01004 // because we've already deleted the address space. Simply 01005 // decrement our reference and null the DataTableEntry 01006 // so we don't go through the forced unload path. 01007 // 01008 01009 ASSERT (DataTableEntry != NULL); 01010 DataTableEntry->LoadCount -= 1; 01011 DataTableEntry = NULL; 01012 } 01013 goto return1; 01014 } 01015 01016 // 01017 // Error recovery from this point out for sessions works as follows: 01018 // 01019 // For sessions, we may or may not have a DataTableEntry at this point. 01020 // If we do, it's because we're attaching to a driver that has already 01021 // been loaded - and the DataTableEntry->LoadCount has been bumped - so 01022 // the error recovery from here on out is to just call 01023 // MmUnloadSystemImage with the DataTableEntry. 01024 // 01025 // If this is the first load of a given driver into a session space, we 01026 // have no DataTableEntry at this point. The view has already been mapped 01027 // and committed and the group/session addresses reserved for this DLL. 01028 // The error recovery path handles all this because 01029 // MmUnloadSystemImage will zero the relevant fields in the 01030 // LDR_DATA_TABLE_ENTRY so that MmUnloadSystemImage will work properly. 01031 // 01032 01033 IssueUnloadOnFailure = TRUE; 01034 01035 if (LoadInSessionSpace == FALSE || *ImageBaseAddress != SectionPointer->Segment->BasedAddress) { 01036 01037 #if DBG 01038 01039 // 01040 // Warn users about session images that cannot be shared 01041 // because they were linked at a bad address. 01042 // 01043 01044 if (LoadInSessionSpace == TRUE && MmSessionSpace->SessionId) { 01045 DbgPrint ("MM: Session %d image %wZ is linked at a nonsharable address (%p)\n", 01046 MmSessionSpace->SessionId, 01047 ImageFileName, 01048 SectionPointer->Segment->BasedAddress); 01049 DbgPrint ("MM: Image %wZ has been moved to address (%p) by the system so it can run,\n", 01050 ImageFileName, 01051 *ImageBaseAddress); 01052 DbgPrint (" but this needs to be fixed in the image for sharing to occur.\n"); 01053 } 01054 #endif 01055 01056 // 01057 // Apply the fixups to the section and resolve its image references. 01058 // 01059 01060 try { 01061 Status = (NTSTATUS)LdrRelocateImage(*ImageBaseAddress, 01062 "SYSLDR", 01063 (ULONG)STATUS_SUCCESS, 01064 (ULONG)STATUS_CONFLICTING_ADDRESSES, 01065 (ULONG)STATUS_INVALID_IMAGE_FORMAT 01066 ); 01067 } except (EXCEPTION_EXECUTE_HANDLER) { 01068 Status = GetExceptionCode(); 01069 KdPrint(("MM:sysload - LdrRelocateImage failed status %lx\n", 01070 Status)); 01071 } 01072 01073 if (!NT_SUCCESS(Status)) { 01074 01075 // 01076 // Unload the system image and dereference the section. 01077 // 01078 01079 goto return1; 01080 } 01081 } 01082 01083 BindImage: 01084 01085 try { 01086 MissingProcedureName = NameBuffer; 01087 01088 // 01089 // Resolving the image references results in other DLLs being 01090 // loaded if they are referenced by the module that was just loaded. 01091 // An example is when an OEM printer or FAX driver links with 01092 // other general libraries. This is not a problem for session space 01093 // because the general libraries do not have the global data issues 01094 // that win32k.sys and the video drivers do. So we just call the 01095 // standard kernel reference resolver and any referenced libraries 01096 // get loaded into system global space. Code in the routine 01097 // restricts which libraries can be referenced by a driver. 01098 // 01099 01100 Status = MiResolveImageReferences(*ImageBaseAddress, 01101 &BaseDirectory, 01102 NamePrefix, 01103 FALSE, 01104 &MissingProcedureName, 01105 &MissingDriverName, 01106 &LoadedImports 01107 ); 01108 } except (EXCEPTION_EXECUTE_HANDLER) { 01109 Status = GetExceptionCode(); 01110 KdPrint(("MM:sysload - ResolveImageReferences failed status %x\n", 01111 Status)); 01112 } 01113 01114 if (!NT_SUCCESS(Status)) { 01115 #if DBG 01116 if (Status == STATUS_DRIVER_ORDINAL_NOT_FOUND || 01117 Status == STATUS_DRIVER_ENTRYPOINT_NOT_FOUND) { 01118 01119 if ((ULONG_PTR)MissingProcedureName & ~((ULONG_PTR) (X64K-1))) { 01120 // 01121 // If not an ordinal, print string 01122 // 01123 DbgPrint("MissingProcedureName %s\n", MissingProcedureName); 01124 } 01125 else { 01126 DbgPrint("MissingProcedureName 0x%p\n", MissingProcedureName); 01127 } 01128 01129 if (MissingDriverName) { 01130 DbgPrint("MissingDriverName %ws\n", MissingDriverName); 01131 } 01132 } 01133 #endif 01134 goto return1; 01135 } 01136 01137 #if DBG 01138 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01139 KdPrint (("MM:loaded driver - consumed %ld. pages\n",MiPagesConsumed)); 01140 } 01141 #endif 01142 01143 if (AlreadyOpen == FALSE) { 01144 01145 // 01146 // Since there was no loaded module list entry for this driver, create 01147 // one now. 01148 // 01149 01150 #if DBG 01151 NextEntry = PsLoadedModuleList.Flink; 01152 while (NextEntry != &PsLoadedModuleList) { 01153 DataTableEntry = CONTAINING_RECORD(NextEntry, 01154 LDR_DATA_TABLE_ENTRY, 01155 InLoadOrderLinks); 01156 01157 if (RtlEqualUnicodeString (ImageFileName, 01158 &DataTableEntry->FullDllName, 01159 TRUE)) { 01160 01161 DbgPrint("MM SYSLDR: Image already loaded! RefCount %x\n", 01162 DataTableEntry->LoadCount); 01163 DbgBreakPoint(); 01164 } 01165 01166 NextEntry = NextEntry->Flink; 01167 } 01168 #endif 01169 01170 // 01171 // Allocate a data table entry for structured exception handling. 01172 // 01173 01174 DataTableEntry = ExAllocatePoolWithTag (NonPagedPool, 01175 sizeof(LDR_DATA_TABLE_ENTRY), 01176 'dLmM'); 01177 01178 if (DataTableEntry == NULL) { 01179 Status = STATUS_INSUFFICIENT_RESOURCES; 01180 goto return1; 01181 } 01182 01183 DataTableEntry->BaseDllName.Buffer = ExAllocatePoolWithTag ( 01184 NonPagedPool, 01185 BaseName.Length + sizeof(UNICODE_NULL), 01186 'dLmM'); 01187 01188 if (DataTableEntry->BaseDllName.Buffer == NULL) { 01189 ExFreePool (DataTableEntry); 01190 DataTableEntry = NULL; 01191 Status = STATUS_INSUFFICIENT_RESOURCES; 01192 goto return1; 01193 } 01194 01195 // 01196 // Initialize the address of the DLL image file header and the entry 01197 // point address. 01198 // 01199 01200 NtHeaders = RtlImageNtHeader(*ImageBaseAddress); 01201 01202 DataTableEntry->DllBase = *ImageBaseAddress; 01203 DataTableEntry->EntryPoint = 01204 ((PCHAR)*ImageBaseAddress + NtHeaders->OptionalHeader.AddressOfEntryPoint); 01205 DataTableEntry->SizeOfImage = NumberOfPtes << PAGE_SHIFT; 01206 DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum; 01207 DataTableEntry->SectionPointer = (PVOID)SectionPointer; 01208 01209 // 01210 // Store the DLL name. 01211 // 01212 01213 DataTableEntry->BaseDllName.Length = BaseName.Length; 01214 DataTableEntry->BaseDllName.MaximumLength = BaseName.Length; 01215 RtlMoveMemory (DataTableEntry->BaseDllName.Buffer, 01216 BaseName.Buffer, 01217 BaseName.Length ); 01218 DataTableEntry->BaseDllName.Buffer[BaseName.Length/sizeof(WCHAR)] = UNICODE_NULL; 01219 01220 DataTableEntry->FullDllName.Buffer = ExAllocatePoolWithTag (PagedPool, 01221 PrefixedImageName.Length + sizeof(UNICODE_NULL), 01222 'TDmM'); 01223 if (DataTableEntry->FullDllName.Buffer == NULL) { 01224 01225 // 01226 // Pool could not be allocated, just set the length to 0. 01227 // 01228 01229 DataTableEntry->FullDllName.Length = 0; 01230 DataTableEntry->FullDllName.MaximumLength = 0; 01231 } else { 01232 DataTableEntry->FullDllName.Length = PrefixedImageName.Length; 01233 DataTableEntry->FullDllName.MaximumLength = PrefixedImageName.Length; 01234 RtlMoveMemory (DataTableEntry->FullDllName.Buffer, 01235 PrefixedImageName.Buffer, 01236 PrefixedImageName.Length); 01237 DataTableEntry->FullDllName.Buffer[PrefixedImageName.Length/sizeof(WCHAR)] = UNICODE_NULL; 01238 } 01239 01240 PERFINFO_IMAGE_LOAD(DataTableEntry); 01241 01242 // 01243 // Initialize the flags, load count, and insert the data table entry 01244 // in the loaded module list. 01245 // 01246 01247 DataTableEntry->Flags = LDRP_ENTRY_PROCESSED | LDRP_SYSTEM_MAPPED; 01248 DataTableEntry->LoadCount = 1; 01249 DataTableEntry->LoadedImports = (PVOID)LoadedImports; 01250 01251 if ((NtHeaders->OptionalHeader.MajorOperatingSystemVersion >= 5) && 01252 (NtHeaders->OptionalHeader.MajorImageVersion >= 5)) { 01253 DataTableEntry->Flags |= LDRP_ENTRY_NATIVE; 01254 } 01255 01256 MiApplyDriverVerifier (DataTableEntry, NULL); 01257 01258 MiWriteProtectSystemImage (DataTableEntry->DllBase); 01259 01260 if (PsImageNotifyEnabled) { 01261 IMAGE_INFO ImageInfo; 01262 01263 ImageInfo.Properties = 0; 01264 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; 01265 ImageInfo.SystemModeImage = TRUE; 01266 ImageInfo.ImageSize = DataTableEntry->SizeOfImage; 01267 ImageInfo.ImageBase = *ImageBaseAddress; 01268 ImageInfo.ImageSelector = 0; 01269 ImageInfo.ImageSectionNumber = 0; 01270 01271 PsCallImageNotifyRoutines(ImageFileName, (HANDLE)NULL, &ImageInfo); 01272 } 01273 01274 // 01275 // Acquire the loaded module list resource and insert this entry 01276 // into the list. 01277 // 01278 01279 KeEnterCriticalRegion(); 01280 ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE); 01281 01282 ExAcquireSpinLock (&PsLoadedModuleSpinLock, &OldIrql); 01283 01284 InsertTailList(&PsLoadedModuleList, &DataTableEntry->InLoadOrderLinks); 01285 01286 ExReleaseSpinLock (&PsLoadedModuleSpinLock, OldIrql); 01287 01288 ExReleaseResource (&PsLoadedModuleResource); 01289 KeLeaveCriticalRegion(); 01290 01291 if (CacheImageSymbols (*ImageBaseAddress)) { 01292 01293 // 01294 // TEMP TEMP TEMP rip out when debugger converted 01295 // 01296 01297 ANSI_STRING AnsiName; 01298 UNICODE_STRING UnicodeName; 01299 01300 // 01301 // \SystemRoot is 11 characters in length 01302 // 01303 if (PrefixedImageName.Length > (11 * sizeof( WCHAR )) && 01304 !_wcsnicmp( PrefixedImageName.Buffer, L"\\SystemRoot", 11 ) 01305 ) { 01306 UnicodeName = PrefixedImageName; 01307 UnicodeName.Buffer += 11; 01308 UnicodeName.Length -= (11 * sizeof( WCHAR )); 01309 sprintf (NameBuffer, "%ws%wZ", &SharedUserData->NtSystemRoot[2], &UnicodeName); 01310 } else { 01311 sprintf (NameBuffer, "%wZ", &BaseName); 01312 } 01313 RtlInitString (&AnsiName, NameBuffer); 01314 DbgLoadImageSymbols (&AnsiName, 01315 *ImageBaseAddress, 01316 (ULONG_PTR) -1 01317 ); 01318 DataTableEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED; 01319 } 01320 } 01321 01322 // 01323 // Flush the instruction cache on all systems in the configuration. 01324 // 01325 01326 KeSweepIcache (TRUE); 01327 *ImageHandle = DataTableEntry; 01328 Status = STATUS_SUCCESS; 01329 01330 if (LoadInSessionSpace == TRUE) { 01331 MmPageEntireDriver (DataTableEntry->EntryPoint); 01332 } 01333 else if (SectionPointer == (PVOID)-1 && LockDownPages == FALSE) { 01334 MiEnablePagingOfDriver (DataTableEntry); 01335 } 01336 01337 return1: 01338 01339 if (!NT_SUCCESS(Status)) { 01340 01341 #if DBG 01342 01343 // 01344 // Only way we should fail after we get a valid DataTableEntry is if 01345 // we're Hydra loading a 2nd instance of a driver. 01346 // 01347 01348 if (DataTableEntry) { 01349 ASSERT (MiHydra == TRUE && AlreadyOpen == TRUE && DataTableEntry->LoadCount > 1); 01350 } 01351 #endif 01352 01353 if (AlreadyOpen == FALSE && SectionPointer != (PVOID)-1) { 01354 01355 // 01356 // This is needed for failed win32k.sys loads or any Hydra session's 01357 // load of the first instance of a driver. 01358 // 01359 01360 ObDereferenceObject (SectionPointer); 01361 } 01362 01363 if (IssueUnloadOnFailure == TRUE) { 01364 01365 if (DataTableEntry == NULL) { 01366 RtlZeroMemory (&TempDataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY)); 01367 01368 DataTableEntry = &TempDataTableEntry; 01369 01370 DataTableEntry->DllBase = *ImageBaseAddress; 01371 DataTableEntry->SizeOfImage = NumberOfPtes << PAGE_SHIFT; 01372 DataTableEntry->LoadCount = 1; 01373 DataTableEntry->LoadedImports = LoadedImports; 01374 } 01375 #if DBG 01376 else { 01377 01378 // 01379 // If DataTableEntry is NULL, then we are unloading before one 01380 // got created. Once a LDR_DATA_TABLE_ENTRY is created, the 01381 // load cannot fail, so if exists here, at least one other 01382 // session contains this image as well. 01383 // 01384 01385 ASSERT (MiHydra == TRUE); 01386 ASSERT (DataTableEntry->LoadCount > 1); 01387 } 01388 #endif 01389 01390 MmUnloadSystemImage ((PVOID)DataTableEntry); 01391 } 01392 } 01393 01394 if (FileHandle) { 01395 ZwClose (FileHandle); 01396 } 01397 if (!NT_SUCCESS(Status)) { 01398 01399 ULONG_PTR ErrorParameters[ 3 ]; 01400 ULONG NumberOfParameters; 01401 ULONG UnicodeStringParameterMask; 01402 ULONG ErrorResponse; 01403 ANSI_STRING AnsiString; 01404 UNICODE_STRING ProcedureName; 01405 UNICODE_STRING DriverName; 01406 01407 // 01408 // Hard error time. A driver could not be loaded. 01409 // 01410 01411 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 01412 KeLeaveCriticalRegion(); 01413 ErrorParameters[ 0 ] = (ULONG_PTR)ImageFileName; 01414 NumberOfParameters = 1; 01415 UnicodeStringParameterMask = 1; 01416 01417 RtlInitUnicodeString( &ProcedureName, NULL ); 01418 if (Status == STATUS_DRIVER_ORDINAL_NOT_FOUND || 01419 Status == STATUS_DRIVER_ENTRYPOINT_NOT_FOUND || 01420 Status == STATUS_PROCEDURE_NOT_FOUND 01421 ) { 01422 NumberOfParameters = 3; 01423 UnicodeStringParameterMask = 0x5; 01424 RtlInitUnicodeString( &DriverName, MissingDriverName ); 01425 ErrorParameters[ 2 ] = (ULONG_PTR)&DriverName; 01426 01427 if ((ULONG_PTR)MissingProcedureName & ~((ULONG_PTR) (X64K-1))) { 01428 // 01429 // If not an ordinal, pass as a Unicode string 01430 // 01431 01432 RtlInitAnsiString( &AnsiString, MissingProcedureName ); 01433 RtlAnsiStringToUnicodeString( &ProcedureName, &AnsiString, TRUE ); 01434 ErrorParameters[ 1 ] = (ULONG_PTR)&ProcedureName; 01435 UnicodeStringParameterMask |= 0x2; 01436 } else { 01437 // 01438 // Just pass ordinal values as is. 01439 // 01440 01441 ErrorParameters[ 1 ] = (ULONG_PTR)MissingProcedureName; 01442 } 01443 } else { 01444 NumberOfParameters = 2; 01445 ErrorParameters[ 1 ] = (ULONG)Status; 01446 Status = STATUS_DRIVER_UNABLE_TO_LOAD; 01447 } 01448 01449 ZwRaiseHardError (Status, 01450 NumberOfParameters, 01451 UnicodeStringParameterMask, 01452 ErrorParameters, 01453 OptionOkNoWait, 01454 &ErrorResponse); 01455 01456 if (ProcedureName.Buffer != NULL) { 01457 RtlFreeUnicodeString( &ProcedureName ); 01458 } 01459 return Status; 01460 } 01461 01462 return2: 01463 if (NamePrefix) { 01464 ExFreePool (PrefixedImageName.Buffer); 01465 } 01466 01467 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 01468 KeLeaveCriticalRegion(); 01469 return Status; 01470 } 01471 01472 01473 NTSTATUS 01474 MiLoadImageSection ( 01475 IN PSECTION SectionPointer, 01476 OUT PVOID *ImageBaseAddress, 01477 IN PUNICODE_STRING ImageFileName, 01478 IN BOOLEAN LoadInSessionSpace 01479 ) 01480 01481 /*++ 01482 01483 Routine Description: 01484 01485 This routine loads the specified image into the kernel part of the 01486 address space. 01487 01488 Arguments: 01489 01490 SectionPointer - Supplies the section object for the image. 01491 01492 ImageBaseAddress - Returns the address that the image header is at. 01493 01494 ImageFileName - Supplies the full path name (including the image name) 01495 of the image to load. 01496 01497 LoadInSessionSpace - Supplies whether to load this image in session space. 01498 Each session gets a different copy of this driver with 01499 pages shared as much as possible via copy on write. 01500 01501 Return Value: 01502 01503 Status of the operation. 01504 01505 --*/ 01506 01507 { 01508 PFN_NUMBER PagesRequired; 01509 PMMPTE ProtoPte; 01510 PMMPTE FirstPte; 01511 PMMPTE LastPte; 01512 PMMPTE PointerPte; 01513 PEPROCESS Process; 01514 PEPROCESS TargetProcess; 01515 ULONG NumberOfPtes; 01516 MMPTE PteContents; 01517 MMPTE TempPte; 01518 PMMPFN Pfn1; 01519 PFN_NUMBER PageFrameIndex; 01520 KIRQL OldIrql; 01521 PVOID UserVa; 01522 PVOID SystemVa; 01523 NTSTATUS Status; 01524 NTSTATUS ExceptionStatus; 01525 PVOID Base; 01526 ULONG_PTR ViewSize; 01527 LARGE_INTEGER SectionOffset; 01528 BOOLEAN LoadSymbols; 01529 PVOID BaseAddress; 01530 PFN_NUMBER CommittedPages; 01531 SIZE_T SectionSize; 01532 BOOLEAN AlreadyLoaded; 01533 PMM_SESSION_SPACE SessionGlobal; 01534 LOGICAL ProcessReferenced; 01535 PLIST_ENTRY NextProcessEntry; 01536 01537 PAGED_CODE(); 01538 01539 PagesRequired = 0; 01540 01541 // 01542 // Calculate the number of pages required to load this image. 01543 // 01544 01545 ProtoPte = SectionPointer->Segment->PrototypePte; 01546 NumberOfPtes = SectionPointer->Segment->TotalNumberOfPtes; 01547 01548 while (NumberOfPtes != 0) { 01549 PteContents = *ProtoPte; 01550 01551 if ((PteContents.u.Hard.Valid == 1) || 01552 (PteContents.u.Soft.Protection != MM_NOACCESS)) { 01553 PagesRequired += 1; 01554 } 01555 NumberOfPtes -= 1; 01556 ProtoPte += 1; 01557 } 01558 01559 if (LoadInSessionSpace == TRUE) { 01560 01561 ASSERT (MiHydra == TRUE); 01562 01563 SectionSize = (ULONG_PTR)SectionPointer->Segment->TotalNumberOfPtes * PAGE_SIZE; 01564 01565 // 01566 // Allocate a unique systemwide session space virtual address for 01567 // the driver. 01568 // 01569 01570 Status = MiSessionWideReserveImageAddress (ImageFileName, 01571 SectionPointer, 01572 PAGE_SIZE, 01573 &BaseAddress, 01574 &AlreadyLoaded); 01575 01576 if (!NT_SUCCESS(Status)) { 01577 #if DBG 01578 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01579 DbgPrint ("MiLoadImageSection: Error 0x%x Allocating session space %p Bytes\n",Status,SectionSize); 01580 } 01581 #endif 01582 return Status; 01583 } 01584 01585 // 01586 // This is a request to load an existing driver. This can 01587 // occur with printer drivers for example. 01588 // 01589 01590 if (AlreadyLoaded == TRUE) { 01591 *ImageBaseAddress = BaseAddress; 01592 return STATUS_ALREADY_COMMITTED; 01593 } 01594 01595 #if DBG 01596 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01597 if (ImageFileName) { 01598 DbgPrint ("MM: MiLoadImageSection: Image %wZ, BasedAddress 0x%p, SegmentBaseAddress 0x%p, Allocated Session BaseAddress 0x%p\n", 01599 ImageFileName, 01600 SectionPointer->Segment->BasedAddress, 01601 SectionPointer->Segment->SegmentBaseAddress, 01602 BaseAddress); 01603 } 01604 else { 01605 DbgPrint ("MM: MiLoadImageSection: Image <NULL> BasedAddress 0x%p, SegmentBaseAddress 0x%p, Allocated Session BaseAddress 0x%p\n", 01606 SectionPointer->Segment->BasedAddress, 01607 SectionPointer->Segment->SegmentBaseAddress, 01608 BaseAddress); 01609 } 01610 } 01611 #endif 01612 01613 if (BaseAddress == SectionPointer->Segment->BasedAddress) { 01614 01615 // 01616 // We were able to load the image at its based address, so 01617 // map its image segments as backed directly by the file image. 01618 // All pristine pages of the image will be shared across all 01619 // sessions, with each page treated as copy-on-write on first write. 01620 // 01621 // NOTE: This makes the file image "busy", a different behavior 01622 // as normal kernel drivers are backed by the paging file only. 01623 // 01624 01625 #if DBG 01626 if (SectionPointer->Segment->SystemImageBase != 0) { 01627 ASSERT (BaseAddress == SectionPointer->Segment->SystemImageBase); 01628 } 01629 #endif 01630 01631 // 01632 // Map the image into session space. 01633 // 01634 01635 Status = MiShareSessionImage (SectionPointer, &SectionSize); 01636 01637 if (!NT_SUCCESS(Status)) { 01638 #if DBG 01639 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01640 DbgPrint ("MM: MiLoadImageSection: Error 0x%x Allocating session space %p Bytes\n", Status, SectionSize); 01641 } 01642 #endif 01643 MiRemoveImageSessionWide (BaseAddress); 01644 return Status; 01645 } 01646 01647 ASSERT (BaseAddress == SectionPointer->Segment->BasedAddress); 01648 01649 *ImageBaseAddress = BaseAddress; 01650 01651 // 01652 // Indicate that this section has been loaded into the system. 01653 // 01654 01655 SectionPointer->Segment->SystemImageBase = BaseAddress; 01656 01657 #if DBG 01658 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01659 if (ImageFileName) { 01660 DbgPrint ("MM: MiLoadImageSection: Mapped image %wZ at requested session address 0x%p\n", 01661 ImageFileName, 01662 BaseAddress); 01663 } 01664 else { 01665 DbgPrint ("MM: MiLoadImageSection: Mapped a session image at requested address 0x%p\n", 01666 BaseAddress); 01667 } 01668 } 01669 #endif 01670 01671 return Status; 01672 } 01673 01674 // 01675 // The image could not be loaded at its based address. It must be 01676 // copied to its new address using private page file backed pages. 01677 // Our caller will relocate the internal references and then bind the 01678 // image. Allocate the pages and page tables for the image now. 01679 // 01680 01681 Status = MiSessionCommitImagePages (BaseAddress, SectionSize); 01682 01683 if (!NT_SUCCESS(Status)) { 01684 #if DBG 01685 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01686 DbgPrint ("MM: MiLoadImageSection: Error 0x%x Allocating session space %p Bytes\n", Status, SectionSize); 01687 } 01688 #endif 01689 MiRemoveImageSessionWide (BaseAddress); 01690 return Status; 01691 } 01692 SystemVa = BaseAddress; 01693 } 01694 else { 01695 01696 // 01697 // See if ample pages exist to load this image. 01698 // 01699 01700 #if DBG 01701 MiPagesConsumed = PagesRequired; 01702 #endif 01703 01704 LOCK_PFN (OldIrql); 01705 01706 if (MmResidentAvailablePages <= (SPFN_NUMBER)PagesRequired) { 01707 UNLOCK_PFN (OldIrql); 01708 return STATUS_INSUFFICIENT_RESOURCES; 01709 } 01710 MmResidentAvailablePages -= PagesRequired; 01711 MM_BUMP_COUNTER(14, PagesRequired); 01712 UNLOCK_PFN (OldIrql); 01713 01714 // 01715 // Reserve the necessary system address space. 01716 // 01717 01718 FirstPte = MiReserveSystemPtes (SectionPointer->Segment->TotalNumberOfPtes, 01719 SystemPteSpace, 01720 0, 01721 0, 01722 FALSE ); 01723 01724 if (FirstPte == NULL) { 01725 LOCK_PFN (OldIrql); 01726 MmResidentAvailablePages += PagesRequired; 01727 MM_BUMP_COUNTER(15, PagesRequired); 01728 UNLOCK_PFN (OldIrql); 01729 return STATUS_INSUFFICIENT_RESOURCES; 01730 } 01731 PointerPte = FirstPte; 01732 SystemVa = MiGetVirtualAddressMappedByPte (PointerPte); 01733 } 01734 01735 // 01736 // Map a view into the user portion of the address space. 01737 // 01738 01739 Process = PsGetCurrentProcess(); 01740 01741 // 01742 // Since callees are not always in the context of the system process, 01743 // attach here when necessary to guarantee the driver load occurs in a 01744 // known safe address space to prevent security holes. 01745 // 01746 01747 ProcessReferenced = FALSE; 01748 TargetProcess = Process; 01749 if (Process->Peb && Process->Vm.u.Flags.SessionLeader == 0) { 01750 if (MiHydra == FALSE) { 01751 if (ExpDefaultErrorPortProcess && (Process != ExpDefaultErrorPortProcess)) { 01752 TargetProcess = ExpDefaultErrorPortProcess; 01753 KeAttachProcess (&TargetProcess->Pcb); 01754 } 01755 } 01756 else { 01757 01758 SessionGlobal = SESSION_GLOBAL(MmSessionSpace); 01759 LOCK_EXPANSION (OldIrql); 01760 NextProcessEntry = SessionGlobal->ProcessList.Flink; 01761 01762 if ((SessionGlobal->u.Flags.DeletePending == 0) && 01763 (NextProcessEntry != &SessionGlobal->ProcessList)) { 01764 01765 TargetProcess = CONTAINING_RECORD (NextProcessEntry, 01766 EPROCESS, 01767 SessionProcessLinks); 01768 01769 if (Process != TargetProcess) { 01770 ObReferenceObject (TargetProcess); 01771 ProcessReferenced = TRUE; 01772 } 01773 } 01774 else { 01775 UNLOCK_EXPANSION (OldIrql); 01776 01777 LOCK_PFN (OldIrql); 01778 MmResidentAvailablePages += PagesRequired; 01779 MM_BUMP_COUNTER(15, PagesRequired); 01780 UNLOCK_PFN (OldIrql); 01781 01782 CommittedPages = MiDeleteSystemPagableVm ( 01783 MiGetPteAddress (BaseAddress), 01784 BYTES_TO_PAGES (SectionSize), 01785 ZeroKernelPte, 01786 TRUE, 01787 NULL); 01788 01789 LOCK_SESSION_SPACE_WS (OldIrql); 01790 MmSessionSpace->CommittedPages -= CommittedPages; 01791 01792 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_COMMIT_IMAGELOAD_FAILED1, 01793 CommittedPages); 01794 01795 UNLOCK_SESSION_SPACE_WS (OldIrql); 01796 01797 // 01798 // Return the commitment we took out on the pagefile when 01799 // the page was allocated. This is needed for collided images 01800 // since all the pages get committed regardless of writability. 01801 // 01802 01803 MiRemoveImageSessionWide (BaseAddress); 01804 01805 return STATUS_PROCESS_IS_TERMINATING; 01806 } 01807 01808 UNLOCK_EXPANSION (OldIrql); 01809 01810 if (Process != TargetProcess) { 01811 KeAttachProcess (&TargetProcess->Pcb); 01812 } 01813 } 01814 } 01815 01816 ZERO_LARGE (SectionOffset); 01817 Base = NULL; 01818 ViewSize = 0; 01819 01820 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD) { 01821 LoadSymbols = TRUE; 01822 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 01823 } 01824 else { 01825 LoadSymbols = FALSE; 01826 } 01827 01828 Status = MmMapViewOfSection ( SectionPointer, 01829 TargetProcess, 01830 &Base, 01831 0, 01832 0, 01833 &SectionOffset, 01834 &ViewSize, 01835 ViewUnmap, 01836 0, 01837 PAGE_EXECUTE); 01838 01839 if (LoadSymbols) { 01840 NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 01841 } 01842 01843 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) { 01844 Status = STATUS_INVALID_IMAGE_FORMAT; 01845 } 01846 01847 if (!NT_SUCCESS(Status)) { 01848 if (TargetProcess != Process) { 01849 KeDetachProcess(); 01850 if (ProcessReferenced == TRUE) { 01851 ObDereferenceObject (TargetProcess); 01852 } 01853 } 01854 01855 if (LoadInSessionSpace == TRUE) { 01856 01857 #if DBG 01858 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) { 01859 DbgPrint ("MiLoadImageSection: Error 0x%x in session space mapping via MmMapViewOfSection\n", Status); 01860 } 01861 #endif 01862 01863 CommittedPages = MiDeleteSystemPagableVm ( 01864 MiGetPteAddress (BaseAddress), 01865 BYTES_TO_PAGES (SectionSize), 01866 ZeroKernelPte, 01867 TRUE, 01868 NULL); 01869 01870 LOCK_SESSION_SPACE_WS (OldIrql); 01871 MmSessionSpace->CommittedPages -= CommittedPages; 01872 01873 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_COMMIT_IMAGELOAD_FAILED1, 01874 CommittedPages); 01875 01876 UNLOCK_SESSION_SPACE_WS (OldIrql); 01877 01878 // 01879 // Return the commitment we took out on the pagefile when 01880 // the page was allocated. This is needed for collided images 01881 // since all the pages get committed regardless of writability. 01882 // 01883 01884 MiRemoveImageSessionWide (BaseAddress); 01885 } 01886 else { 01887 LOCK_PFN (OldIrql); 01888 MmResidentAvailablePages += PagesRequired; 01889 MM_BUMP_COUNTER(16, PagesRequired); 01890 UNLOCK_PFN (OldIrql); 01891 MiReleaseSystemPtes (FirstPte, 01892 SectionPointer->Segment->TotalNumberOfPtes, 01893 SystemPteSpace); 01894 } 01895 01896 return Status; 01897 } 01898 01899 // 01900 // Allocate a physical page(s) and copy the image data. 01901 // Note Hydra has already allocated the physical pages and just does 01902 // data copying here. 01903 // 01904 01905 ProtoPte = SectionPointer->Segment->PrototypePte; 01906 NumberOfPtes = SectionPointer->Segment->TotalNumberOfPtes; 01907 01908 *ImageBaseAddress = SystemVa; 01909 01910 UserVa = Base; 01911 TempPte = ValidKernelPte; 01912 #if defined(_IA64_) 01913 TempPte.u.Long |= MM_PTE_EXECUTE; 01914 #endif 01915 01916 while (NumberOfPtes != 0) { 01917 PteContents = *ProtoPte; 01918 if ((PteContents.u.Hard.Valid == 1) || 01919 (PteContents.u.Soft.Protection != MM_NOACCESS)) { 01920 01921 if (LoadInSessionSpace == FALSE) { 01922 LOCK_PFN (OldIrql); 01923 MiEnsureAvailablePageOrWait (NULL, NULL); 01924 PageFrameIndex = MiRemoveAnyPage( 01925 MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); 01926 PointerPte->u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 01927 #if defined(_IA64_) 01928 01929 // 01930 // EM needs execute permission. 01931 // 01932 01933 PointerPte->u.Soft.Protection |= MM_EXECUTE; 01934 01935 #endif 01936 MiInitializePfn (PageFrameIndex, PointerPte, 1); 01937 01938 UNLOCK_PFN (OldIrql); 01939 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 01940 MI_WRITE_VALID_PTE (PointerPte, TempPte); 01941 LastPte = PointerPte; 01942 01943 ASSERT (MI_PFN_ELEMENT (PageFrameIndex)->u1.WsIndex == 0); 01944 } 01945 01946 try { 01947 01948 RtlMoveMemory (SystemVa, UserVa, PAGE_SIZE); 01949 01950 } except (MiMapCacheExceptionFilter (&ExceptionStatus, 01951 GetExceptionInformation())) { 01952 01953 // 01954 // An exception occurred, unmap the view and 01955 // return the error to the caller. 01956 // 01957 01958 #if DBG 01959 DbgPrint("MiLoadImageSection: Exception 0x%x copying driver SystemVa 0x%p, UserVa 0x%p\n",ExceptionStatus,SystemVa,UserVa); 01960 #endif 01961 01962 if (LoadInSessionSpace == TRUE) { 01963 ASSERT (MiHydra == TRUE); 01964 CommittedPages = MiDeleteSystemPagableVm ( 01965 MiGetPteAddress (BaseAddress), 01966 BYTES_TO_PAGES (SectionSize), 01967 ZeroKernelPte, 01968 TRUE, 01969 NULL); 01970 01971 LOCK_SESSION_SPACE_WS (OldIrql); 01972 MmSessionSpace->CommittedPages -= CommittedPages; 01973 01974 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_COMMIT_IMAGELOAD_FAILED2, 01975 CommittedPages); 01976 01977 UNLOCK_SESSION_SPACE_WS (OldIrql); 01978 01979 // 01980 // Return the commitment we took out on the pagefile when 01981 // the page was allocated. This is needed for collided 01982 // images since all the pages get committed regardless 01983 // of writability. 01984 // 01985 01986 MiReturnCommitment (CommittedPages); 01987 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_SESSION_DRIVER_LOAD_FAILURE1, CommittedPages); 01988 } 01989 else { 01990 ProtoPte = FirstPte; 01991 LOCK_PFN (OldIrql); 01992 while (ProtoPte <= PointerPte) { 01993 if (ProtoPte->u.Hard.Valid == 1) { 01994 01995 // 01996 // Delete the page. 01997 // 01998 01999 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (ProtoPte); 02000 02001 // 02002 // Set the pointer to PTE as empty so the page 02003 // is deleted when the reference count goes to zero. 02004 // 02005 02006 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 02007 MiDecrementShareAndValidCount (Pfn1->PteFrame); 02008 MI_SET_PFN_DELETED (Pfn1); 02009 MiDecrementShareCountOnly (PageFrameIndex); 02010 02011 MI_WRITE_INVALID_PTE (ProtoPte, ZeroPte); 02012 } 02013 ProtoPte += 1; 02014 } 02015 02016 MmResidentAvailablePages += PagesRequired; 02017 MM_BUMP_COUNTER(17, PagesRequired); 02018 UNLOCK_PFN (OldIrql); 02019 MiReleaseSystemPtes (FirstPte, 02020 SectionPointer->Segment->TotalNumberOfPtes, 02021 SystemPteSpace); 02022 } 02023 02024 Status = MmUnmapViewOfSection (TargetProcess, Base); 02025 02026 ASSERT (NT_SUCCESS (Status)); 02027 02028 if (TargetProcess != Process) { 02029 KeDetachProcess(); 02030 if (ProcessReferenced == TRUE) { 02031 ObDereferenceObject (TargetProcess); 02032 } 02033 } 02034 02035 if (LoadInSessionSpace == TRUE) { 02036 MiRemoveImageSessionWide (BaseAddress); 02037 } 02038 02039 return ExceptionStatus; 02040 } 02041 02042 } 02043 else { 02044 02045 // 02046 // The PTE is no access - if this driver is being loaded in session 02047 // space we already preloaded the page so free it now. The 02048 // commitment is returned when the whole image is unmapped. 02049 // 02050 02051 if (LoadInSessionSpace == TRUE) { 02052 ASSERT (MiHydra == TRUE); 02053 CommittedPages = MiDeleteSystemPagableVm ( 02054 MiGetPteAddress (SystemVa), 02055 1, 02056 ZeroKernelPte, 02057 TRUE, 02058 NULL); 02059 02060 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_COMMIT_IMAGELOAD_NOACCESS, 02061 1); 02062 } 02063 else { 02064 MI_WRITE_INVALID_PTE (PointerPte, ZeroKernelPte); 02065 } 02066 } 02067 02068 NumberOfPtes -= 1; 02069 ProtoPte += 1; 02070 PointerPte += 1; 02071 SystemVa = ((PCHAR)SystemVa + PAGE_SIZE); 02072 UserVa = ((PCHAR)UserVa + PAGE_SIZE); 02073 } 02074 02075 Status = MmUnmapViewOfSection (TargetProcess, Base); 02076 ASSERT (NT_SUCCESS (Status)); 02077 02078 if (TargetProcess != Process) { 02079 KeDetachProcess(); 02080 if (ProcessReferenced == TRUE) { 02081 ObDereferenceObject (TargetProcess); 02082 } 02083 } 02084 02085 // 02086 // Indicate that this section has been loaded into the system. 02087 // 02088 02089 SectionPointer->Segment->SystemImageBase = *ImageBaseAddress; 02090 02091 // 02092 // Charge commitment for the number of pages that were used by 02093 // the driver. 02094 // 02095 02096 if (LoadInSessionSpace == FALSE) { 02097 MiChargeCommitmentCantExpand (PagesRequired, TRUE); 02098 MM_TRACK_COMMIT (MM_DBG_COMMIT_DRIVER_PAGES, PagesRequired); 02099 MmDriverCommit += (ULONG)PagesRequired; 02100 } 02101 02102 return Status; 02103 } 02104 02105 VOID 02106 MmFreeDriverInitialization ( 02107 IN PVOID ImageHandle 02108 ) 02109 02110 /*++ 02111 02112 Routine Description: 02113 02114 This routine removes the pages that relocate and debug information from 02115 the address space of the driver. 02116 02117 NOTE: This routine looks at the last sections defined in the image 02118 header and if that section is marked as DISCARDABLE in the 02119 characteristics, it is removed from the image. This means 02120 that all discardable sections at the end of the driver are 02121 deleted. 02122 02123 Arguments: 02124 02125 SectionObject - Supplies the section object for the image. 02126 02127 Return Value: 02128 02129 None. 02130 02131 --*/ 02132 02133 { 02134 PLDR_DATA_TABLE_ENTRY DataTableEntry; 02135 PMMPTE PointerPte; 02136 PMMPTE LastPte; 02137 PFN_NUMBER NumberOfPtes; 02138 PVOID Base; 02139 ULONG i; 02140 PIMAGE_NT_HEADERS NtHeaders; 02141 PIMAGE_SECTION_HEADER NtSection; 02142 PIMAGE_SECTION_HEADER FoundSection; 02143 PFN_NUMBER PagesDeleted; 02144 02145 MmLockPagableSectionByHandle(ExPageLockHandle); 02146 DataTableEntry = (PLDR_DATA_TABLE_ENTRY)ImageHandle; 02147 Base = DataTableEntry->DllBase; 02148 02149 ASSERT (MI_IS_SESSION_ADDRESS (Base) == FALSE); 02150 02151 NumberOfPtes = DataTableEntry->SizeOfImage >> PAGE_SHIFT; 02152 LastPte = MiGetPteAddress (Base) + NumberOfPtes; 02153 02154 NtHeaders = (PIMAGE_NT_HEADERS)RtlImageNtHeader(Base); 02155 02156 NtSection = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeaders + 02157 sizeof(ULONG) + 02158 sizeof(IMAGE_FILE_HEADER) + 02159 NtHeaders->FileHeader.SizeOfOptionalHeader 02160 ); 02161 02162 NtSection += NtHeaders->FileHeader.NumberOfSections; 02163 02164 FoundSection = NULL; 02165 for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i += 1) { 02166 NtSection -= 1; 02167 if ((NtSection->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) { 02168 FoundSection = NtSection; 02169 } else { 02170 02171 // 02172 // There was a non discardable section between the this 02173 // section and the last non discardable section, don't 02174 // discard this section and don't look any more. 02175 // 02176 02177 break; 02178 } 02179 } 02180 02181 if (FoundSection != NULL) { 02182 02183 PointerPte = MiGetPteAddress (ROUND_TO_PAGES ( 02184 (PCHAR)Base + FoundSection->VirtualAddress)); 02185 NumberOfPtes = (PFN_NUMBER)(LastPte - PointerPte); 02186 02187 PagesDeleted = MiDeleteSystemPagableVm (PointerPte, 02188 NumberOfPtes, 02189 ZeroKernelPte, 02190 FALSE, 02191 NULL); 02192 02193 MmResidentAvailablePages += PagesDeleted; 02194 MM_BUMP_COUNTER(18, PagesDeleted); 02195 MiReturnCommitment (PagesDeleted); 02196 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_DRIVER_INIT_CODE, PagesDeleted); 02197 MmDriverCommit -= (ULONG)PagesDeleted; 02198 #if DBG 02199 MiPagesConsumed -= PagesDeleted; 02200 #endif 02201 } 02202 02203 MmUnlockPagableImageSection(ExPageLockHandle); 02204 return; 02205 } 02206 02207 VOID 02208 MiEnablePagingOfDriver ( 02209 IN PVOID ImageHandle 02210 ) 02211 02212 { 02213 PLDR_DATA_TABLE_ENTRY DataTableEntry; 02214 PMMPTE LastPte; 02215 PMMPTE PointerPte; 02216 PVOID Base; 02217 ULONG i; 02218 PIMAGE_NT_HEADERS NtHeaders; 02219 PIMAGE_SECTION_HEADER FoundSection; 02220 PIMAGE_OPTIONAL_HEADER OptionalHeader; 02221 02222 // 02223 // Don't page kernel mode code if customer does not want it paged. 02224 // 02225 02226 if (MmDisablePagingExecutive) { 02227 return; 02228 } 02229 02230 // 02231 // If the driver has pagable code, make it paged. 02232 // 02233 02234 DataTableEntry = (PLDR_DATA_TABLE_ENTRY)ImageHandle; 02235 Base = DataTableEntry->DllBase; 02236 02237 NtHeaders = (PIMAGE_NT_HEADERS)RtlImageNtHeader(Base); 02238 02239 OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PCHAR)NtHeaders + 02240 #if defined (_WIN64) 02241 FIELD_OFFSET (IMAGE_NT_HEADERS64, OptionalHeader)); 02242 #else 02243 FIELD_OFFSET (IMAGE_NT_HEADERS32, OptionalHeader)); 02244 #endif 02245 02246 FoundSection = IMAGE_FIRST_SECTION (NtHeaders); 02247 02248 i = NtHeaders->FileHeader.NumberOfSections; 02249 02250 PointerPte = NULL; 02251 02252 while (i > 0) { 02253 #if DBG 02254 if ((*(PULONG)FoundSection->Name == 'tini') || 02255 (*(PULONG)FoundSection->Name == 'egap')) { 02256 DbgPrint("driver %wZ has lower case sections (init or pagexxx)\n", 02257 &DataTableEntry->FullDllName); 02258 } 02259 #endif //DBG 02260 02261 // 02262 // Mark as pagable any section which starts with the 02263 // first 4 characters PAGE or .eda (for the .edata section). 02264 // 02265 02266 if ((*(PULONG)FoundSection->Name == 'EGAP') || 02267 (*(PULONG)FoundSection->Name == 'ade.')) { 02268 02269 // 02270 // This section is pagable, save away the start and end. 02271 // 02272 02273 if (PointerPte == NULL) { 02274 02275 // 02276 // Previous section was NOT pagable, get the start address. 02277 // 02278 02279 PointerPte = MiGetPteAddress (ROUND_TO_PAGES ( 02280 (PCHAR)Base + FoundSection->VirtualAddress)); 02281 } 02282 LastPte = MiGetPteAddress ((PCHAR)Base + 02283 FoundSection->VirtualAddress + 02284 (OptionalHeader->SectionAlignment - 1) + 02285 FoundSection->SizeOfRawData - PAGE_SIZE); 02286 02287 } else { 02288 02289 // 02290 // This section is not pagable, if the previous section was 02291 // pagable, enable it. 02292 // 02293 02294 if (PointerPte != NULL) { 02295 MiSetPagingOfDriver (PointerPte, LastPte, FALSE); 02296 PointerPte = NULL; 02297 } 02298 } 02299 i -= 1; 02300 FoundSection += 1; 02301 } 02302 if (PointerPte != NULL) { 02303 MiSetPagingOfDriver (PointerPte, LastPte, FALSE); 02304 } 02305 } 02306 02307 02308 VOID 02309 MiSetPagingOfDriver ( 02310 IN PMMPTE PointerPte, 02311 IN PMMPTE LastPte, 02312 IN BOOLEAN SessionSpace 02313 ) 02314 02315 /*++ 02316 02317 Routine Description: 02318 02319 This routine marks the specified range of PTEs as pagable. 02320 02321 Arguments: 02322 02323 PointerPte - Supplies the starting PTE. 02324 02325 LastPte - Supplies the ending PTE. 02326 02327 Return Value: 02328 02329 None. 02330 02331 --*/ 02332 02333 { 02334 PVOID Base; 02335 PFN_NUMBER PageCount; 02336 PFN_NUMBER PageFrameIndex; 02337 PMMPFN Pfn; 02338 MMPTE TempPte; 02339 MMPTE PreviousPte; 02340 KIRQL OldIrql1; 02341 KIRQL OldIrql; 02342 02343 PAGED_CODE (); 02344 02345 ASSERT ((SessionSpace == FALSE) || 02346 (MmIsAddressValid(MmSessionSpace) == TRUE)); 02347 02348 if (MI_IS_PHYSICAL_ADDRESS(MiGetVirtualAddressMappedByPte(PointerPte))) { 02349 02350 // 02351 // No need to lock physical addresses. 02352 // 02353 02354 return; 02355 } 02356 02357 PageCount = 0; 02358 02359 // 02360 // Lock this routine into memory. 02361 // 02362 02363 MmLockPagableSectionByHandle(ExPageLockHandle); 02364 02365 if (SessionSpace == TRUE) { 02366 LOCK_SESSION_SPACE_WS (OldIrql1); 02367 } 02368 else { 02369 LOCK_SYSTEM_WS (OldIrql1); 02370 } 02371 02372 LOCK_PFN (OldIrql); 02373 02374 Base = MiGetVirtualAddressMappedByPte (PointerPte); 02375 02376 while (PointerPte <= LastPte) { 02377 02378 // 02379 // Check to make sure this PTE has not already been 02380 // made pagable (or deleted). It is pagable if it 02381 // is not valid, or if the PFN database wsindex element 02382 // is non zero. 02383 // 02384 02385 if (PointerPte->u.Hard.Valid == 1) { 02386 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 02387 Pfn = MI_PFN_ELEMENT (PageFrameIndex); 02388 ASSERT (Pfn->u2.ShareCount == 1); 02389 02390 if (Pfn->u1.WsIndex == 0) { 02391 02392 // 02393 // Original PTE may need to be set for drivers loaded 02394 // via ntldr. 02395 // 02396 02397 if (Pfn->OriginalPte.u.Long == 0) { 02398 Pfn->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 02399 #if defined(_IA64_) 02400 Pfn->OriginalPte.u.Soft.Protection |= MM_EXECUTE; 02401 #endif 02402 } 02403 02404 TempPte = *PointerPte; 02405 02406 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 02407 Pfn->OriginalPte.u.Soft.Protection); 02408 02409 PreviousPte.u.Flush = KeFlushSingleTb (Base, 02410 TRUE, 02411 TRUE, 02412 (PHARDWARE_PTE)PointerPte, 02413 TempPte.u.Flush); 02414 02415 MI_CAPTURE_DIRTY_BIT_TO_PFN (&PreviousPte, Pfn); 02416 02417 // 02418 // Flush the translation buffer and decrement the number of valid 02419 // PTEs within the containing page table page. Note that for a 02420 // private page, the page table page is still needed because the 02421 // page is in transition. 02422 // 02423 02424 MiDecrementShareCount (PageFrameIndex); 02425 MmResidentAvailablePages += 1; 02426 MM_BUMP_COUNTER(19, 1); 02427 MmTotalSystemDriverPages += 1; 02428 PageCount += 1; 02429 } 02430 else { 02431 // 02432 // This page is already pagable and has a WSLE entry. 02433 // Ignore it here and let the trimmer take it if memory 02434 // comes under pressure. 02435 // 02436 } 02437 } 02438 Base = (PVOID)((PCHAR)Base + PAGE_SIZE); 02439 PointerPte += 1; 02440 } 02441 02442 if (SessionSpace == TRUE) { 02443 02444 // 02445 // Session space has no ASN - flush the entire TB. 02446 // 02447 02448 MI_FLUSH_ENTIRE_SESSION_TB (TRUE, TRUE); 02449 } 02450 02451 UNLOCK_PFN (OldIrql); 02452 02453 if (SessionSpace == TRUE) { 02454 02455 // 02456 // These pages are no longer locked down. 02457 // 02458 02459 MmSessionSpace->NonPagablePages -= PageCount; 02460 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_DRIVER_PAGES_UNLOCKED, PageCount); 02461 02462 UNLOCK_SESSION_SPACE_WS (OldIrql1); 02463 } 02464 else { 02465 UNLOCK_SYSTEM_WS (OldIrql1); 02466 } 02467 MmUnlockPagableImageSection(ExPageLockHandle); 02468 } 02469 02470 02471 PVOID 02472 MmPageEntireDriver ( 02473 IN PVOID AddressWithinSection 02474 ) 02475 02476 /*++ 02477 02478 Routine Description: 02479 02480 This routine allows a driver to page out all of its code and 02481 data regardless of the attributes of the various image sections. 02482 02483 Note, this routine can be called multiple times with no 02484 intervening calls to MmResetDriverPaging. 02485 02486 Arguments: 02487 02488 AddressWithinSection - Supplies an address within the driver, e.g. 02489 DriverEntry. 02490 02491 Return Value: 02492 02493 Base address of driver. 02494 02495 Environment: 02496 02497 Kernel mode, APC_LEVEL or below. 02498 02499 --*/ 02500 02501 { 02502 PLDR_DATA_TABLE_ENTRY DataTableEntry; 02503 PMMPTE FirstPte; 02504 PMMPTE LastPte; 02505 PVOID BaseAddress; 02506 PSECTION SectionPointer; 02507 BOOLEAN SessionSpace; 02508 02509 PAGED_CODE(); 02510 02511 // 02512 // Don't page kernel mode code if disabled via registry. 02513 // 02514 02515 DataTableEntry = MiLookupDataTableEntry (AddressWithinSection, FALSE); 02516 02517 if (DataTableEntry == NULL) { 02518 return NULL; 02519 } 02520 02521 SectionPointer = (PSECTION)DataTableEntry->SectionPointer; 02522 02523 if (MmDisablePagingExecutive) { 02524 return DataTableEntry->DllBase; 02525 } 02526 02527 SessionSpace = MI_IS_SESSION_IMAGE_ADDRESS (AddressWithinSection); 02528 02529 if ((SectionPointer != NULL) && (SectionPointer != (PVOID)-1)) { 02530 02531 // 02532 // Driver is mapped as an image (ie: win32k), this is always pagable. 02533 // For session space, an image that has been loaded at its desired 02534 // address is also always pagable. If there was an address collision, 02535 // then we fall through because we have to explicitly page it. 02536 // 02537 02538 if (SessionSpace == TRUE) { 02539 if (SectionPointer->Segment && 02540 SectionPointer->Segment->BasedAddress == SectionPointer->Segment->SystemImageBase) { 02541 return DataTableEntry->DllBase; 02542 } 02543 } 02544 else { 02545 return DataTableEntry->DllBase; 02546 } 02547 } 02548 02549 BaseAddress = DataTableEntry->DllBase; 02550 FirstPte = MiGetPteAddress (BaseAddress); 02551 LastPte = (FirstPte - 1) + (DataTableEntry->SizeOfImage >> PAGE_SHIFT); 02552 02553 MiSetPagingOfDriver (FirstPte, LastPte, SessionSpace); 02554 02555 return BaseAddress; 02556 } 02557 02558 02559 VOID 02560 MmResetDriverPaging ( 02561 IN PVOID AddressWithinSection 02562 ) 02563 02564 /*++ 02565 02566 Routine Description: 02567 02568 This routines resets the driver paging to what the image specified. 02569 Hence image sections such as the IAT, .text, .data will be locked 02570 down in memory. 02571 02572 Note, there is no requirement that MmPageEntireDriver was called. 02573 02574 Arguments: 02575 02576 AddressWithinSection - Supplies an address within the driver, e.g. 02577 DriverEntry. 02578 02579 Return Value: 02580 02581 None. 02582 02583 Environment: 02584 02585 Kernel mode, APC_LEVEL or below. 02586 02587 --*/ 02588 02589 { 02590 PLDR_DATA_TABLE_ENTRY DataTableEntry; 02591 PMMPTE LastPte; 02592 PMMPTE PointerPte; 02593 PVOID Base; 02594 ULONG i; 02595 PIMAGE_NT_HEADERS NtHeaders; 02596 PIMAGE_SECTION_HEADER FoundSection; 02597 KIRQL OldIrql; 02598 KIRQL OldIrqlWs; 02599 02600 PAGED_CODE(); 02601 02602 // 02603 // Don't page kernel mode code if disabled via registry. 02604 // 02605 02606 if (MmDisablePagingExecutive) { 02607 return; 02608 } 02609 02610 if (MI_IS_PHYSICAL_ADDRESS(AddressWithinSection)) { 02611 return; 02612 } 02613 02614 // 02615 // If the driver has pagable code, make it paged. 02616 // 02617 02618 DataTableEntry = MiLookupDataTableEntry (AddressWithinSection, FALSE); 02619 02620 if ((DataTableEntry->SectionPointer != NULL) && 02621 (DataTableEntry->SectionPointer != (PVOID)-1)) { 02622 02623 // 02624 // Driver is mapped by image hence already paged. 02625 // 02626 02627 return; 02628 } 02629 02630 Base = DataTableEntry->DllBase; 02631 02632 NtHeaders = (PIMAGE_NT_HEADERS)RtlImageNtHeader(Base); 02633 02634 FoundSection = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeaders + 02635 sizeof(ULONG) + 02636 sizeof(IMAGE_FILE_HEADER) + 02637 NtHeaders->FileHeader.SizeOfOptionalHeader 02638 ); 02639 02640 i = NtHeaders->FileHeader.NumberOfSections; 02641 PointerPte = NULL; 02642 02643 while (i > 0) { 02644 #if DBG 02645 if ((*(PULONG)FoundSection->Name == 'tini') || 02646 (*(PULONG)FoundSection->Name == 'egap')) { 02647 DbgPrint("driver %wZ has lower case sections (init or pagexxx)\n", 02648 &DataTableEntry->FullDllName); 02649 } 02650 #endif 02651 02652 // 02653 // Don't lock down code for sections marked as discardable or 02654 // sections marked with the first 4 characters PAGE or .eda 02655 // (for the .edata section) or INIT. 02656 // 02657 02658 if (((FoundSection->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) || 02659 (*(PULONG)FoundSection->Name == 'EGAP') || 02660 (*(PULONG)FoundSection->Name == 'ade.') || 02661 (*(PULONG)FoundSection->Name == 'TINI')) { 02662 02663 NOTHING; 02664 02665 } else { 02666 02667 // 02668 // This section is nonpagable. 02669 // 02670 02671 PointerPte = MiGetPteAddress ( 02672 (PCHAR)Base + FoundSection->VirtualAddress); 02673 LastPte = MiGetPteAddress ((PCHAR)Base + 02674 FoundSection->VirtualAddress + 02675 (FoundSection->SizeOfRawData - 1)); 02676 ASSERT (PointerPte <= LastPte); 02677 MmLockPagableSectionByHandle(ExPageLockHandle); 02678 LOCK_SYSTEM_WS (OldIrqlWs); 02679 LOCK_PFN (OldIrql); 02680 MiLockCode (PointerPte, LastPte, MM_LOCK_BY_NONPAGE); 02681 UNLOCK_PFN (OldIrql); 02682 UNLOCK_SYSTEM_WS (OldIrqlWs); 02683 MmUnlockPagableImageSection(ExPageLockHandle); 02684 } 02685 i -= 1; 02686 FoundSection += 1; 02687 } 02688 return; 02689 } 02690 02691 02692 VOID 02693 MiClearImports( 02694 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 02695 ) 02696 /*++ 02697 02698 Routine Description: 02699 02700 Free up the import list and clear the pointer. This stops the 02701 recursion performed in MiDereferenceImports(). 02702 02703 Arguments: 02704 02705 DataTableEntry - provided for the driver. 02706 02707 Return Value: 02708 02709 Status of the import list construction operation. 02710 02711 --*/ 02712 02713 { 02714 PAGED_CODE(); 02715 02716 if (DataTableEntry->LoadedImports == (PVOID)LOADED_AT_BOOT) { 02717 return; 02718 } 02719 02720 if (DataTableEntry->LoadedImports == (PVOID)NO_IMPORTS_USED) { 02721 NOTHING; 02722 } 02723 else if (SINGLE_ENTRY(DataTableEntry->LoadedImports)) { 02724 NOTHING; 02725 } 02726 else { 02727 // 02728 // free the memory 02729 // 02730 ExFreePool ((PVOID)DataTableEntry->LoadedImports); 02731 } 02732 02733 // 02734 // stop the recursion 02735 // 02736 DataTableEntry->LoadedImports = (PVOID)LOADED_AT_BOOT; 02737 } 02738 02739 VOID 02740 MiRememberUnloadedDriver ( 02741 IN PUNICODE_STRING DriverName, 02742 IN PVOID Address, 02743 IN ULONG Length 02744 ) 02745 02746 /*++ 02747 02748 Routine Description: 02749 02750 This routine saves information about unloaded drivers so that ones that 02751 forget to delete lookaside lists or queues can be caught. 02752 02753 Arguments: 02754 02755 DriverName - Supplies a Unicode string containing the driver's name. 02756 02757 Address - Supplies the address the driver was loaded at. 02758 02759 Length - Supplies the number of bytes the driver load spanned. 02760 02761 Return Value: 02762 02763 None. 02764 02765 --*/ 02766 02767 { 02768 PUNLOADED_DRIVERS Entry; 02769 ULONG NumberOfBytes; 02770 02771 if (DriverName->Length == 0) { 02772 02773 // 02774 // This is an aborted load and the driver name hasn't been filled 02775 // in yet. No need to save it. 02776 // 02777 02778 return; 02779 } 02780 02781 // 02782 // Serialization is provided by the caller, so just update the list now. 02783 // Note the allocations are nonpaged so they can be searched at bugcheck 02784 // time. 02785 // 02786 02787 if (MiUnloadedDrivers == NULL) { 02788 NumberOfBytes = MI_UNLOADED_DRIVERS * sizeof (UNLOADED_DRIVERS); 02789 02790 MiUnloadedDrivers = (PUNLOADED_DRIVERS)ExAllocatePoolWithTag (NonPagedPool, 02791 NumberOfBytes, 02792 'TDmM'); 02793 if (MiUnloadedDrivers == NULL) { 02794 return; 02795 } 02796 RtlZeroMemory (MiUnloadedDrivers, NumberOfBytes); 02797 MiLastUnloadedDriver = 0; 02798 } 02799 else if (MiLastUnloadedDriver >= MI_UNLOADED_DRIVERS) { 02800 MiLastUnloadedDriver = 0; 02801 } 02802 02803 Entry = &MiUnloadedDrivers[MiLastUnloadedDriver]; 02804 02805 // 02806 // Free the old entry as we recycle into the new. 02807 // 02808 02809 RtlFreeUnicodeString (&Entry->Name); 02810 02811 Entry->Name.Buffer = ExAllocatePoolWithTag (NonPagedPool, 02812 DriverName->Length, 02813 'TDmM'); 02814 02815 if (Entry->Name.Buffer == NULL) { 02816 Entry->Name.MaximumLength = 0; 02817 Entry->Name.Length = 0; 02818 MiUnloadsSkipped += 1; 02819 return; 02820 } 02821 02822 RtlMoveMemory(Entry->Name.Buffer, DriverName->Buffer, DriverName->Length); 02823 Entry->Name.Length = DriverName->Length; 02824 Entry->Name.MaximumLength = DriverName->MaximumLength; 02825 02826 Entry->StartAddress = Address; 02827 Entry->EndAddress = (PVOID)((PCHAR)Address + Length); 02828 02829 KeQuerySystemTime (&Entry->CurrentTime); 02830 02831 MiTotalUnloads += 1; 02832 MiLastUnloadedDriver += 1; 02833 } 02834 02835 PUNICODE_STRING 02836 MmLocateUnloadedDriver ( 02837 IN PVOID VirtualAddress 02838 ) 02839 02840 /*++ 02841 02842 Routine Description: 02843 02844 This routine attempts to find the specified virtual address in the 02845 unloaded driver list. 02846 02847 Arguments: 02848 02849 VirtualAddress - Supplies a virtual address that might be within a driver 02850 that has already unloaded. 02851 02852 Return Value: 02853 02854 A pointer to a Unicode string containing the unloaded driver's name. 02855 02856 Environment: 02857 02858 Kernel mode, bugcheck time. 02859 02860 --*/ 02861 02862 { 02863 PUNLOADED_DRIVERS Entry; 02864 ULONG i; 02865 ULONG Index; 02866 02867 // 02868 // No serialization is needed because we've crashed. 02869 // 02870 02871 if (MiUnloadedDrivers == NULL) { 02872 return NULL; 02873 } 02874 02875 Index = MiLastUnloadedDriver - 1; 02876 02877 for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) { 02878 if (Index >= MI_UNLOADED_DRIVERS) { 02879 Index = MI_UNLOADED_DRIVERS - 1; 02880 } 02881 Entry = &MiUnloadedDrivers[Index]; 02882 if (Entry->Name.Buffer != NULL) { 02883 if ((VirtualAddress >= Entry->StartAddress) && 02884 (VirtualAddress < Entry->EndAddress)) { 02885 return &Entry->Name; 02886 } 02887 } 02888 Index -= 1; 02889 } 02890 02891 return NULL; 02892 } 02893 02894 02895 NTSTATUS 02896 MmUnloadSystemImage ( 02897 IN PVOID ImageHandle 02898 ) 02899 02900 /*++ 02901 02902 Routine Description: 02903 02904 This routine unloads a previously loaded system image and returns 02905 the allocated resources. 02906 02907 Arguments: 02908 02909 ImageHandle - Supplies a pointer to the section object of the 02910 image to unload. 02911 02912 Return Value: 02913 02914 Various NTSTATUS codes. 02915 02916 --*/ 02917 02918 { 02919 PLDR_DATA_TABLE_ENTRY DataTableEntry; 02920 PMMPTE LastPte; 02921 PFN_NUMBER PagesRequired; 02922 PFN_NUMBER ResidentPages; 02923 PMMPTE PointerPte; 02924 PFN_NUMBER NumberOfPtes; 02925 KIRQL OldIrql; 02926 PVOID BasedAddress; 02927 SIZE_T NumberOfBytes; 02928 BOOLEAN MustFree; 02929 SIZE_T CommittedPages; 02930 BOOLEAN ViewDeleted; 02931 PIMAGE_ENTRY_IN_SESSION DriverImage; 02932 NTSTATUS Status; 02933 PVOID StillQueued; 02934 PSECTION SectionPointer; 02935 02936 // 02937 // Arbitrary process context so prevent suspend APCs now. 02938 // 02939 02940 KeEnterCriticalRegion(); 02941 02942 KeWaitForSingleObject (&MmSystemLoadLock, 02943 WrVirtualMemory, 02944 KernelMode, 02945 FALSE, 02946 (PLARGE_INTEGER)NULL); 02947 02948 MmLockPagableSectionByHandle(ExPageLockHandle); 02949 02950 ViewDeleted = FALSE; 02951 DataTableEntry = (PLDR_DATA_TABLE_ENTRY)ImageHandle; 02952 BasedAddress = DataTableEntry->DllBase; 02953 02954 #if DBGXX 02955 // 02956 // MiUnloadSystemImageByForce violates this check so remove it for now. 02957 // 02958 02959 if (PsLoadedModuleList.Flink) { 02960 LOGICAL Found; 02961 PLIST_ENTRY NextEntry; 02962 PLDR_DATA_TABLE_ENTRY DataTableEntry2; 02963 02964 Found = FALSE; 02965 NextEntry = PsLoadedModuleList.Flink; 02966 while (NextEntry != &PsLoadedModuleList) { 02967 02968 DataTableEntry2 = CONTAINING_RECORD(NextEntry, 02969 LDR_DATA_TABLE_ENTRY, 02970 InLoadOrderLinks); 02971 if (DataTableEntry == DataTableEntry2) { 02972 Found = TRUE; 02973 break; 02974 } 02975 NextEntry = NextEntry->Flink; 02976 } 02977 ASSERT (Found == TRUE); 02978 } 02979 #endif 02980 02981 #if DBG_SYSLOAD 02982 if (DataTableEntry->SectionPointer == NULL) { 02983 DbgPrint ("MM: Called to unload boot driver %wZ\n", 02984 &DataTableEntry->FullDllName); 02985 } 02986 else { 02987 DbgPrint ("MM: Called to unload non-boot driver %wZ\n", 02988 &DataTableEntry->FullDllName); 02989 } 02990 #endif 02991 02992 // 02993 // Any driver loaded at boot that did not have its import list 02994 // and LoadCount reconstructed cannot be unloaded because we don't 02995 // know how many other drivers may be linked to it. 02996 // 02997 02998 if (DataTableEntry->LoadedImports == (PVOID)LOADED_AT_BOOT) { 02999 MmUnlockPagableImageSection(ExPageLockHandle); 03000 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 03001 KeLeaveCriticalRegion(); 03002 return STATUS_SUCCESS; 03003 } 03004 03005 ASSERT (DataTableEntry->LoadCount != 0); 03006 03007 if (MI_IS_SESSION_IMAGE_ADDRESS (BasedAddress)) { 03008 03009 // 03010 // A printer driver may be referenced multiple times for the 03011 // same session space. Only unload the last reference. 03012 // 03013 03014 DriverImage = MiSessionLookupImage (BasedAddress); 03015 03016 ASSERT (DriverImage); 03017 03018 ASSERT (DriverImage->ImageCountInThisSession); 03019 03020 if (DriverImage->ImageCountInThisSession > 1) { 03021 03022 DriverImage->ImageCountInThisSession -= 1; 03023 MmUnlockPagableImageSection(ExPageLockHandle); 03024 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 03025 KeLeaveCriticalRegion(); 03026 03027 return STATUS_SUCCESS; 03028 } 03029 03030 // 03031 // The reference count for this image has dropped to zero in this 03032 // session, so we can delete this session's view of the image. 03033 // 03034 03035 Status = MiSessionWideGetImageSize (BasedAddress, 03036 &NumberOfBytes, 03037 &CommittedPages); 03038 03039 if (!NT_SUCCESS(Status)) { 03040 03041 KeBugCheckEx (MEMORY_MANAGEMENT, 03042 0x41286, 03043 (ULONG_PTR)MmSessionSpace->SessionId, 03044 (ULONG_PTR)BasedAddress, 03045 0); 03046 } 03047 03048 // 03049 // Free the session space taken up by the image, unmapping it from 03050 // the current VA space - note this does not remove page table pages 03051 // from the session PageTables[]. Each data page is only freed 03052 // if there are no other references to it (ie: from any other 03053 // sessions). 03054 // 03055 03056 PointerPte = MiGetPteAddress (BasedAddress); 03057 LastPte = MiGetPteAddress ((ULONG_PTR)BasedAddress + NumberOfBytes); 03058 03059 PagesRequired = MiDeleteSystemPagableVm (PointerPte, 03060 (PFN_NUMBER)(LastPte - PointerPte), 03061 ZeroKernelPte, 03062 TRUE, 03063 &ResidentPages); 03064 03065 if (MmDisablePagingExecutive == 0) { 03066 03067 SectionPointer = (PSECTION)DataTableEntry->SectionPointer; 03068 03069 if ((SectionPointer == NULL) || 03070 (SectionPointer == (PVOID)-1) || 03071 (SectionPointer->Segment == NULL) || 03072 (SectionPointer->Segment->BasedAddress != SectionPointer->Segment->SystemImageBase)) { 03073 03074 MmTotalSystemDriverPages -= (ULONG)(PagesRequired - ResidentPages); 03075 } 03076 } 03077 03078 LOCK_SESSION_SPACE_WS (OldIrql); 03079 MmSessionSpace->CommittedPages -= CommittedPages; 03080 03081 MM_BUMP_SESS_COUNTER(MM_DBG_SESSION_COMMIT_IMAGE_UNLOAD, 03082 CommittedPages); 03083 03084 UNLOCK_SESSION_SPACE_WS (OldIrql); 03085 03086 ViewDeleted = TRUE; 03087 03088 // 03089 // Return the commitment we took out on the pagefile when the 03090 // image was allocated. 03091 // 03092 03093 MiReturnCommitment (CommittedPages); 03094 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD, CommittedPages); 03095 03096 // 03097 // Tell the session space image handler that we are releasing 03098 // our claim to the image. 03099 // 03100 03101 Status = MiRemoveImageSessionWide (BasedAddress); 03102 03103 ASSERT (NT_SUCCESS (Status)); 03104 } 03105 03106 ASSERT (DataTableEntry->LoadCount != 0); 03107 03108 DataTableEntry->LoadCount -= 1; 03109 03110 if (DataTableEntry->LoadCount != 0) { 03111 MmUnlockPagableImageSection(ExPageLockHandle); 03112 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 03113 KeLeaveCriticalRegion(); 03114 return STATUS_SUCCESS; 03115 } 03116 03117 #if DBG 03118 if (MI_IS_SESSION_IMAGE_ADDRESS (BasedAddress)) { 03119 ASSERT (MiSessionLookupImage (BasedAddress) == NULL); 03120 } 03121 #endif 03122 03123 if (MmSnapUnloads) { 03124 #if 0 03125 StillQueued = KeCheckForTimer (DataTableEntry->DllBase, 03126 DataTableEntry->SizeOfImage); 03127 03128 if (StillQueued != NULL) { 03129 KeBugCheckEx (DRIVER_VERIFIER_DETECTED_VIOLATION, 03130 0x18, 03131 (ULONG_PTR)StillQueued, 03132 (ULONG_PTR)-1, 03133 (ULONG_PTR)DataTableEntry->DllBase); 03134 } 03135 03136 StillQueued = ExpCheckForResource (DataTableEntry->DllBase, 03137 DataTableEntry->SizeOfImage); 03138 03139 if (StillQueued != NULL) { 03140 KeBugCheckEx (DRIVER_VERIFIER_DETECTED_VIOLATION, 03141 0x19, 03142 (ULONG_PTR)StillQueued, 03143 (ULONG_PTR)-1, 03144 (ULONG_PTR)DataTableEntry->DllBase); 03145 } 03146 #endif 03147 } 03148 03149 if (DataTableEntry->Flags & LDRP_IMAGE_VERIFYING) { 03150 MiVerifyingDriverUnloading (DataTableEntry); 03151 } 03152 03153 if (MiActiveVerifierThunks != 0) { 03154 MiVerifierCheckThunks (DataTableEntry); 03155 } 03156 03157 // 03158 // Unload symbols from debugger. 03159 // 03160 03161 if (DataTableEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED) { 03162 03163 // 03164 // TEMP TEMP TEMP rip out when debugger converted 03165 // 03166 03167 ANSI_STRING AnsiName; 03168 NTSTATUS Status; 03169 03170 Status = RtlUnicodeStringToAnsiString( &AnsiName, 03171 &DataTableEntry->BaseDllName, 03172 TRUE ); 03173 03174 if (NT_SUCCESS( Status)) { 03175 DbgUnLoadImageSymbols( &AnsiName, 03176 BasedAddress, 03177 (ULONG)-1); 03178 RtlFreeAnsiString( &AnsiName ); 03179 } 03180 } 03181 03182 // 03183 // No unload can happen till after Mm has finished Phase 1 initialization. 03184 // Therefore, large pages are already in effect (if this platform supports 03185 // it). 03186 // 03187 03188 if (ViewDeleted == FALSE) { 03189 03190 NumberOfPtes = DataTableEntry->SizeOfImage >> PAGE_SHIFT; 03191 03192 if (MmSnapUnloads) { 03193 MiRememberUnloadedDriver (&DataTableEntry->BaseDllName, 03194 BasedAddress, 03195 (ULONG)(NumberOfPtes << PAGE_SHIFT)); 03196 } 03197 03198 if (DataTableEntry->Flags & LDRP_SYSTEM_MAPPED) { 03199 03200 PointerPte = MiGetPteAddress (BasedAddress); 03201 03202 PagesRequired = MiDeleteSystemPagableVm (PointerPte, 03203 NumberOfPtes, 03204 ZeroKernelPte, 03205 FALSE, 03206 &ResidentPages); 03207 03208 MmTotalSystemDriverPages -= (ULONG)(PagesRequired - ResidentPages); 03209 03210 // 03211 // Note that drivers loaded at boot that have not been relocated 03212 // have no system PTEs or commit charged. 03213 // 03214 03215 MiReleaseSystemPtes (PointerPte, 03216 (ULONG)NumberOfPtes, 03217 SystemPteSpace); 03218 03219 LOCK_PFN (OldIrql); 03220 MmResidentAvailablePages += ResidentPages; 03221 MM_BUMP_COUNTER(21, ResidentPages); 03222 UNLOCK_PFN (OldIrql); 03223 03224 // 03225 // Only return commitment for drivers that weren't loaded by the 03226 // boot loader. 03227 // 03228 03229 if (DataTableEntry->SectionPointer != NULL) { 03230 MiReturnCommitment (PagesRequired); 03231 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD1, PagesRequired); 03232 MmDriverCommit -= (ULONG)PagesRequired; 03233 } 03234 } 03235 else { 03236 03237 // 03238 // This must be a boot driver that was not relocated into 03239 // system PTEs. If large or super pages are enabled, the 03240 // image pages must be freed without referencing the 03241 // non-existent page table pages. If large/super pages are 03242 // not enabled, note that system PTEs were not used to map the 03243 // image and thus, cannot be freed. 03244 03245 // 03246 // This is further complicated by the fact that the INIT and/or 03247 // discardable portions of these images may have already been freed. 03248 // 03249 } 03250 } 03251 03252 // 03253 // Search the loaded module list for the data table entry that describes 03254 // the DLL that was just unloaded. It is possible an entry is not in the 03255 // list if a failure occurred at a point in loading the DLL just before 03256 // the data table entry was generated. 03257 // 03258 03259 if (DataTableEntry->InLoadOrderLinks.Flink != NULL) { 03260 KeEnterCriticalRegion(); 03261 ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE); 03262 03263 ExAcquireSpinLock (&PsLoadedModuleSpinLock, &OldIrql); 03264 03265 RemoveEntryList(&DataTableEntry->InLoadOrderLinks); 03266 ExReleaseSpinLock (&PsLoadedModuleSpinLock, OldIrql); 03267 03268 ExReleaseResource (&PsLoadedModuleResource); 03269 KeLeaveCriticalRegion(); 03270 03271 MustFree = TRUE; 03272 } 03273 else { 03274 MustFree = FALSE; 03275 } 03276 03277 // 03278 // Handle unloading of any dependent DLLs that we loaded automatically 03279 // for this image. 03280 // 03281 03282 MiDereferenceImports ((PLOAD_IMPORTS)DataTableEntry->LoadedImports); 03283 03284 MiClearImports (DataTableEntry); 03285 03286 // 03287 // Free this loader entry. 03288 // 03289 03290 if (MustFree == TRUE) { 03291 03292 if (DataTableEntry->FullDllName.Buffer != NULL) { 03293 ExFreePool (DataTableEntry->FullDllName.Buffer); 03294 } 03295 03296 if (DataTableEntry->BaseDllName.Buffer != NULL) { 03297 ExFreePool (DataTableEntry->BaseDllName.Buffer); 03298 } 03299 03300 // 03301 // Dereference the section object if there is one. 03302 // There should only be one for win32k.sys and Hydra session images. 03303 // 03304 03305 if ((DataTableEntry->SectionPointer != NULL) && 03306 (DataTableEntry->SectionPointer != (PVOID)-1)) { 03307 03308 ObDereferenceObject (DataTableEntry->SectionPointer); 03309 } 03310 03311 ExFreePool((PVOID)DataTableEntry); 03312 } 03313 03314 MmUnlockPagableImageSection(ExPageLockHandle); 03315 03316 KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE); 03317 KeLeaveCriticalRegion(); 03318 03319 PERFINFO_IMAGE_UNLOAD(BasedAddress); 03320 03321 return STATUS_SUCCESS; 03322 } 03323 03324 03325 NTSTATUS 03326 MiBuildImportsForBootDrivers( 03327 VOID 03328 ) 03329 03330 /*++ 03331 03332 Routine Description: 03333 03334 Construct an import list chain for boot-loaded drivers. 03335 If this cannot be done for an entry, its chain is set to LOADED_AT_BOOT. 03336 03337 If a chain can be successfully built, then this driver's DLLs 03338 will be automatically unloaded if this driver goes away (provided 03339 no other driver is also using them). Otherwise, on driver unload, 03340 its dependent DLLs would have to be explicitly unloaded. 03341 03342 Note that the incoming LoadCount values are not correct and thus, they 03343 are reinitialized here. 03344 03345 Arguments: 03346 03347 None. 03348 03349 Return Value: 03350 03351 Various NTSTATUS codes. 03352 03353 --*/ 03354 03355 { 03356 PLDR_DATA_TABLE_ENTRY DataTableEntry; 03357 PLIST_ENTRY NextEntry; 03358 PLDR_DATA_TABLE_ENTRY DataTableEntry2; 03359 PLIST_ENTRY NextEntry2; 03360 ULONG i; 03361 ULONG j; 03362 ULONG ImageCount; 03363 PVOID *ImageReferences; 03364 PVOID LastImageReference; 03365 PULONG_PTR ImportThunk; 03366 ULONG_PTR BaseAddress; 03367 ULONG_PTR LastAddress; 03368 ULONG ImportSize; 03369 ULONG ImportListSize; 03370 PLOAD_IMPORTS ImportList; 03371 LOGICAL UndoEverything; 03372 PLDR_DATA_TABLE_ENTRY KernelDataTableEntry; 03373 PLDR_DATA_TABLE_ENTRY HalDataTableEntry; 03374 UNICODE_STRING KernelString; 03375 UNICODE_STRING HalString; 03376 03377 PAGED_CODE(); 03378 03379 ImageCount = 0; 03380 03381 KernelDataTableEntry = NULL; 03382 HalDataTableEntry = NULL; 03383 03384 RtlInitUnicodeString (&KernelString, L"ntoskrnl.exe"); 03385 RtlInitUnicodeString (&HalString, L"hal.dll"); 03386 03387 NextEntry = PsLoadedModuleList.Flink; 03388 while (NextEntry != &PsLoadedModuleList) { 03389 03390 DataTableEntry = CONTAINING_RECORD(NextEntry, 03391 LDR_DATA_TABLE_ENTRY, 03392 InLoadOrderLinks); 03393 03394 if (RtlEqualUnicodeString (&KernelString, 03395 &DataTableEntry->BaseDllName, 03396 TRUE)) { 03397 03398 KernelDataTableEntry = CONTAINING_RECORD(NextEntry, 03399 LDR_DATA_TABLE_ENTRY, 03400 InLoadOrderLinks); 03401 } 03402 else if (RtlEqualUnicodeString (&HalString, 03403 &DataTableEntry->BaseDllName, 03404 TRUE)) { 03405 03406 HalDataTableEntry = CONTAINING_RECORD(NextEntry, 03407 LDR_DATA_TABLE_ENTRY, 03408 InLoadOrderLinks); 03409 } 03410 03411 // 03412 // Initialize these properly so error recovery is simplified. 03413 // 03414 03415 DataTableEntry->LoadCount = 1; 03416 DataTableEntry->LoadedImports = (PVOID)LOADED_AT_BOOT; 03417 03418 ImageCount += 1; 03419 NextEntry = NextEntry->Flink; 03420 } 03421 03422 if (KernelDataTableEntry == NULL || HalDataTableEntry == NULL) { 03423 return STATUS_NOT_FOUND; 03424 } 03425 03426 ImageReferences = (PVOID *) ExAllocatePoolWithTag (PagedPool, 03427 ImageCount * sizeof (PVOID), 03428 'TDmM'); 03429 03430 if (ImageReferences == NULL) { 03431 return STATUS_INSUFFICIENT_RESOURCES; 03432 } 03433 03434 UndoEverything = FALSE; 03435 03436 NextEntry = PsLoadedModuleList.Flink; 03437 03438 for ( ; NextEntry != &PsLoadedModuleList; NextEntry = NextEntry->Flink) { 03439 03440 DataTableEntry = CONTAINING_RECORD(NextEntry, 03441 LDR_DATA_TABLE_ENTRY, 03442 InLoadOrderLinks); 03443 03444 ImportThunk = (PULONG_PTR)RtlImageDirectoryEntryToData( 03445 DataTableEntry->DllBase, 03446 TRUE, 03447 IMAGE_DIRECTORY_ENTRY_IAT, 03448 &ImportSize); 03449 03450 if (ImportThunk == NULL) { 03451 DataTableEntry->LoadedImports = NO_IMPORTS_USED; 03452 continue; 03453 } 03454 03455 RtlZeroMemory (ImageReferences, ImageCount * sizeof (PVOID)); 03456 03457 ImportSize /= sizeof(PULONG_PTR); 03458 03459 BaseAddress = 0; 03460 for (i = 0; i < ImportSize; i += 1, ImportThunk += 1) { 03461 03462 // 03463 // Check the hint first. 03464 // 03465 03466 if (BaseAddress) { 03467 if (*ImportThunk >= BaseAddress && *ImportThunk < LastAddress) { 03468 ASSERT (ImageReferences[j]); 03469 continue; 03470 } 03471 } 03472 03473 j = 0; 03474 NextEntry2 = PsLoadedModuleList.Flink; 03475 03476 while (NextEntry2 != &PsLoadedModuleList) { 03477 03478 DataTableEntry2 = CONTAINING_RECORD(NextEntry2, 03479 LDR_DATA_TABLE_ENTRY, 03480 InLoadOrderLinks); 03481 03482 BaseAddress = (ULONG_PTR) DataTableEntry2->DllBase; 03483 LastAddress = BaseAddress + DataTableEntry2->SizeOfImage; 03484 03485 if (*ImportThunk >= BaseAddress && *ImportThunk < LastAddress) { 03486 ImageReferences[j] = DataTableEntry2; 03487 break; 03488 } 03489 03490 NextEntry2 = NextEntry2->Flink; 03491 j += 1; 03492 } 03493 03494 if (*ImportThunk < BaseAddress || *ImportThunk >= LastAddress) { 03495 if (*ImportThunk) { 03496 #if DBG 03497 DbgPrint ("MM: broken import linkage %p %p %p\n", 03498 DataTableEntry, 03499 ImportThunk, 03500 *ImportThunk); 03501 DbgBreakPoint (); 03502 #endif 03503 UndoEverything = TRUE; 03504 goto finished; 03505 } 03506 03507 BaseAddress = 0; 03508 } 03509 } 03510 03511 ImportSize = 0; 03512 03513 for (i = 0; i < ImageCount; i += 1) { 03514 03515 if ((ImageReferences[i] != NULL) && 03516 (ImageReferences[i] != KernelDataTableEntry) && 03517 (ImageReferences[i] != HalDataTableEntry)) { 03518 03519 LastImageReference = ImageReferences[i]; 03520 ImportSize += 1; 03521 } 03522 } 03523 03524 if (ImportSize == 0) { 03525 DataTableEntry->LoadedImports = NO_IMPORTS_USED; 03526 } 03527 else if (ImportSize == 1) { 03528 #if DBG_SYSLOAD 03529 DbgPrint("driver %wZ imports %wZ\n", 03530 &DataTableEntry->FullDllName, 03531 &((PLDR_DATA_TABLE_ENTRY)LastImageReference)->FullDllName); 03532 #endif 03533 03534 DataTableEntry->LoadedImports = POINTER_TO_SINGLE_ENTRY (LastImageReference); 03535 ((PLDR_DATA_TABLE_ENTRY)LastImageReference)->LoadCount += 1; 03536 } 03537 else { 03538 #if DBG_SYSLOAD 03539 DbgPrint("driver %wZ imports many\n", &DataTableEntry->FullDllName); 03540 #endif 03541 03542 ImportListSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T); 03543 03544 ImportList = (PLOAD_IMPORTS) ExAllocatePoolWithTag (PagedPool, 03545 ImportListSize, 03546 'TDmM'); 03547 03548 if (ImportList == NULL) { 03549 UndoEverything = TRUE; 03550 break; 03551 } 03552 03553 ImportList->Count = ImportSize; 03554 03555 j = 0; 03556 for (i = 0; i < ImageCount; i += 1) { 03557 03558 if ((ImageReferences[i] != NULL) && 03559 (ImageReferences[i] != KernelDataTableEntry) && 03560 (ImageReferences[i] != HalDataTableEntry)) { 03561 03562 #if DBG_SYSLOAD 03563 DbgPrint("driver %wZ imports %wZ\n", 03564 &DataTableEntry->FullDllName, 03565 &((PLDR_DATA_TABLE_ENTRY)ImageReferences[i])->FullDllName); 03566 #endif 03567 03568 ImportList->Entry[j] = ImageReferences[i]; 03569 ((PLDR_DATA_TABLE_ENTRY)ImageReferences[i])->LoadCount += 1; 03570 j += 1; 03571 } 03572 } 03573 03574 ASSERT (j == ImportSize); 03575 03576 DataTableEntry->LoadedImports = ImportList; 03577 } 03578 #if DBG_SYSLOAD 03579 DbgPrint("\n"); 03580 #endif 03581 } 03582 03583 finished: 03584 03585 ExFreePool ((PVOID)ImageReferences); 03586 03587 // 03588 // The kernel and HAL are never unloaded. 03589 // 03590 03591 if ((KernelDataTableEntry->LoadedImports != NO_IMPORTS_USED) && 03592 (!POINTER_TO_SINGLE_ENTRY(KernelDataTableEntry->LoadedImports))) { 03593 ExFreePool ((PVOID)KernelDataTableEntry->LoadedImports); 03594 } 03595 03596 if ((HalDataTableEntry->LoadedImports != NO_IMPORTS_USED) && 03597 (!POINTER_TO_SINGLE_ENTRY(HalDataTableEntry->LoadedImports))) { 03598 ExFreePool ((PVOID)HalDataTableEntry->LoadedImports); 03599 } 03600 03601 KernelDataTableEntry->LoadedImports = (PVOID)LOADED_AT_BOOT; 03602 HalDataTableEntry->LoadedImports = (PVOID)LOADED_AT_BOOT; 03603 03604 if (UndoEverything == TRUE) { 03605 03606 #if DBG_SYSLOAD 03607 DbgPrint("driver %wZ import rebuild failed\n", 03608 &DataTableEntry->FullDllName); 03609 DbgBreakPoint(); 03610 #endif 03611 03612 // 03613 // An error occurred and this is an all or nothing operation so 03614 // roll everything back. 03615 // 03616 03617 NextEntry = PsLoadedModuleList.Flink; 03618 while (NextEntry != &PsLoadedModuleList) { 03619 DataTableEntry = CONTAINING_RECORD(NextEntry, 03620 LDR_DATA_TABLE_ENTRY, 03621 InLoadOrderLinks); 03622 03623 ImportList = DataTableEntry->LoadedImports; 03624 if (ImportList == LOADED_AT_BOOT || ImportList == NO_IMPORTS_USED || 03625 SINGLE_ENTRY(ImportList)) { 03626 NOTHING; 03627 } 03628 else { 03629 ExFreePool (ImportList); 03630 } 03631 03632 DataTableEntry->LoadedImports = (PVOID)LOADED_AT_BOOT; 03633 DataTableEntry->LoadCount = 1; 03634 NextEntry = NextEntry->Flink; 03635 } 03636 03637 return STATUS_INSUFFICIENT_RESOURCES; 03638 } 03639 03640 return STATUS_SUCCESS; 03641 } 03642 03643 03644 LOGICAL 03645 MiCallDllUnloadAndUnloadDll( 03646 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 03647 ) 03648 03649 /*++ 03650 03651 Routine Description: 03652 03653 All the references from other drivers to this DLL have been cleared. 03654 The only remaining issue is that this DLL must support being unloaded. 03655 This means having no outstanding DPCs, allocated pool, etc. 03656 03657 If the DLL has an unload routine that returns SUCCESS, then we clean 03658 it up and free up its memory now. 03659 03660 Note this routine is NEVER called for drivers - only for DLLs that were 03661 loaded due to import references from various drivers. 03662 03663 Arguments: 03664 03665 DataTableEntry - provided for the DLL. 03666 03667 Return Value: 03668 03669 None. 03670 03671 --*/ 03672 03673 { 03674 PMM_DLL_UNLOAD Func; 03675 NTSTATUS Status; 03676 LOGICAL Unloaded; 03677 03678 PAGED_CODE(); 03679 03680 Unloaded = FALSE; 03681 03682 Func = MiLocateExportName (DataTableEntry->DllBase, "DllUnload"); 03683 03684 if (Func) { 03685 03686 // 03687 // The unload function was found in the DLL so unload it now. 03688 // 03689 03690 Status = Func(); 03691 03692 if (NT_SUCCESS(Status)) { 03693 03694 // 03695 // Set up the reference count so the import DLL looks like a regular 03696 // driver image is being unloaded. 03697 // 03698 03699 ASSERT (DataTableEntry->LoadCount == 0); 03700 DataTableEntry->LoadCount = 1; 03701 03702 MmUnloadSystemImage ((PVOID)DataTableEntry); 03703 Unloaded = TRUE; 03704 } 03705 } 03706 03707 return Unloaded; 03708 } 03709 03710 03711 PVOID 03712 MiLocateExportName ( 03713 IN PVOID DllBase, 03714 IN PCHAR FunctionName 03715 ) 03716 03717 /*++ 03718 03719 Routine Description: 03720 03721 This function is invoked to locate a function name in an export directory. 03722 03723 Arguments: 03724 03725 DllBase - Supplies the image base. 03726 03727 FunctionName - Supplies the the name to be located. 03728 03729 Return Value: 03730 03731 The address of the located function or NULL. 03732 03733 --*/ 03734 03735 { 03736 PVOID Func = NULL; 03737 PULONG NameTableBase; 03738 PUSHORT NameOrdinalTableBase; 03739 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 03740 PULONG Addr; 03741 ULONG ExportSize; 03742 ULONG Low; 03743 ULONG Middle; 03744 ULONG High; 03745 LONG Result; 03746 USHORT OrdinalNumber; 03747 03748 PAGED_CODE(); 03749 03750 // 03751 // Locate the DLL's export directory. 03752 // 03753 03754 ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( 03755 DllBase, 03756 TRUE, 03757 IMAGE_DIRECTORY_ENTRY_EXPORT, 03758 &ExportSize 03759 ); 03760 if (ExportDirectory) { 03761 03762 NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames); 03763 NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); 03764 03765 // 03766 // Look in the export name table for the specified function name. 03767 // 03768 03769 Low = 0; 03770 High = ExportDirectory->NumberOfNames - 1; 03771 03772 while (High >= Low && (LONG)High >= 0) { 03773 03774 // 03775 // Compute the next probe index and compare the export name entry 03776 // with the specified function name. 03777 // 03778 03779 Middle = (Low + High) >> 1; 03780 Result = strcmp(FunctionName, 03781 (PCHAR)((PCHAR)DllBase + NameTableBase[Middle])); 03782 03783 if (Result < 0) { 03784 High = Middle - 1; 03785 } else if (Result > 0) { 03786 Low = Middle + 1; 03787 } else { 03788 break; 03789 } 03790 } 03791 03792 // 03793 // If the high index is less than the low index, then a matching table 03794 // entry was not found. Otherwise, get the ordinal number from the 03795 // ordinal table and location the function address. 03796 // 03797 03798 if ((LONG)High >= (LONG)Low) { 03799 03800 OrdinalNumber = NameOrdinalTableBase[Middle]; 03801 Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); 03802 Func = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]); 03803 03804 // 03805 // If the function address is w/in range of the export directory, 03806 // then the function is forwarded, which is not allowed, so ignore 03807 // it. 03808 // 03809 03810 if ((ULONG_PTR)Func > (ULONG_PTR)ExportDirectory && 03811 (ULONG_PTR)Func < ((ULONG_PTR)ExportDirectory + ExportSize)) { 03812 Func = NULL; 03813 } 03814 } 03815 } 03816 03817 return Func; 03818 } 03819 03820 03821 NTSTATUS 03822 MiDereferenceImports ( 03823 IN PLOAD_IMPORTS ImportList 03824 ) 03825 03826 /*++ 03827 03828 Routine Description: 03829 03830 Decrement the reference count on each DLL specified in the image import 03831 list. If any DLL's reference count reaches zero, then free the DLL. 03832 03833 No locks may be held on entry as MmUnloadSystemImage may be called. 03834 03835 The parameter list is freed here as well. 03836 03837 Arguments: 03838 03839 ImportList - Supplies the list of DLLs to dereference. 03840 03841 Return Value: 03842 03843 Status of the dereference operation. 03844 03845 --*/ 03846 03847 { 03848 ULONG i; 03849 LOGICAL Unloaded; 03850 PVOID SavedImports; 03851 LOAD_IMPORTS SingleTableEntry; 03852 PLDR_DATA_TABLE_ENTRY ImportTableEntry; 03853 03854 PAGED_CODE(); 03855 03856 if (ImportList == LOADED_AT_BOOT || ImportList == NO_IMPORTS_USED) { 03857 return STATUS_SUCCESS; 03858 } 03859 03860 if (SINGLE_ENTRY(ImportList)) { 03861 SingleTableEntry.Count = 1; 03862 SingleTableEntry.Entry[0] = SINGLE_ENTRY_TO_POINTER(ImportList); 03863 ImportList = &SingleTableEntry; 03864 } 03865 03866 for (i = 0; i < ImportList->Count && ImportList->Entry[i]; i += 1) { 03867 ImportTableEntry = ImportList->Entry[i]; 03868 03869 if (ImportTableEntry->LoadedImports == (PVOID)LOADED_AT_BOOT) { 03870 03871 // 03872 // Skip this one - it was loaded by ntldr. 03873 // 03874 03875 continue; 03876 } 03877 03878 #if DBG 03879 { 03880 ULONG ImageCount; 03881 PLIST_ENTRY NextEntry; 03882 PLDR_DATA_TABLE_ENTRY DataTableEntry; 03883 03884 // 03885 // Assert that the first 2 entries are never dereferenced as 03886 // unloading the kernel or HAL would be fatal. 03887 // 03888 03889 NextEntry = PsLoadedModuleList.Flink; 03890 03891 ImageCount = 0; 03892 while (NextEntry != &PsLoadedModuleList && ImageCount < 2) { 03893 DataTableEntry = CONTAINING_RECORD(NextEntry, 03894 LDR_DATA_TABLE_ENTRY, 03895 InLoadOrderLinks); 03896 ASSERT (ImportTableEntry != DataTableEntry); 03897 ASSERT (DataTableEntry->LoadCount == 1); 03898 NextEntry = NextEntry->Flink; 03899 ImageCount += 1; 03900 } 03901 } 03902 #endif 03903 03904 ASSERT (ImportTableEntry->LoadCount >= 1); 03905 03906 ImportTableEntry->LoadCount -= 1; 03907 03908 if (ImportTableEntry->LoadCount == 0) { 03909 03910 // 03911 // Unload this dependent DLL - we only do this to non-referenced 03912 // non-boot-loaded drivers. Stop the import list recursion prior 03913 // to unloading - we know we're done at this point. 03914 // 03915 // Note we can continue on afterwards without restarting 03916 // regardless of which locks get released and reacquired 03917 // because this chain is private. 03918 // 03919 03920 SavedImports = ImportTableEntry->LoadedImports; 03921 03922 ImportTableEntry->LoadedImports = (PVOID)NO_IMPORTS_USED; 03923 03924 Unloaded = MiCallDllUnloadAndUnloadDll ((PVOID)ImportTableEntry); 03925 03926 if (Unloaded == TRUE) { 03927 03928 // 03929 // This DLL was unloaded so recurse through its imports and 03930 // attempt to unload all of those too. 03931 // 03932 03933 MiDereferenceImports ((PLOAD_IMPORTS)SavedImports); 03934 03935 if ((SavedImports != (PVOID)LOADED_AT_BOOT) && 03936 (SavedImports != (PVOID)NO_IMPORTS_USED) && 03937 (!SINGLE_ENTRY(SavedImports))) { 03938 03939 ExFreePool (SavedImports); 03940 } 03941 } 03942 else { 03943 ImportTableEntry->LoadedImports = SavedImports; 03944 } 03945 } 03946 } 03947 03948 return STATUS_SUCCESS; 03949 } 03950 03951 03952 NTSTATUS 03953 MiResolveImageReferences ( 03954 PVOID ImageBase, 03955 IN PUNICODE_STRING ImageFileDirectory, 03956 IN PUNICODE_STRING NamePrefix OPTIONAL, 03957 IN BOOLEAN LoadInSessionSpace, 03958 OUT PCHAR *MissingProcedureName, 03959 OUT PWSTR *MissingDriverName, 03960 OUT PLOAD_IMPORTS *LoadedImports 03961 ) 03962 03963 /*++ 03964 03965 Routine Description: 03966 03967 This routine resolves the references from the newly loaded driver 03968 to the kernel, HAL and other drivers. 03969 03970 Arguments: 03971 03972 ImageBase - Supplies the address of which the image header resides. 03973 03974 ImageFileDirectory - Supplies the directory to load referenced DLLs. 03975 03976 Return Value: 03977 03978 Status of the image reference resolution. 03979 03980 --*/ 03981 03982 { 03983 PCHAR MissingProcedureStorageArea; 03984 PVOID ImportBase; 03985 ULONG ImportSize; 03986 ULONG ImportListSize; 03987 ULONG Count; 03988 ULONG i; 03989 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 03990 PIMAGE_IMPORT_DESCRIPTOR Imp; 03991 NTSTATUS st; 03992 ULONG ExportSize; 03993 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 03994 PIMAGE_THUNK_DATA NameThunk; 03995 PIMAGE_THUNK_DATA AddrThunk; 03996 PSZ ImportName; 03997 PLIST_ENTRY NextEntry; 03998 PLDR_DATA_TABLE_ENTRY DataTableEntry; 03999 PLDR_DATA_TABLE_ENTRY SingleEntry; 04000 ANSI_STRING AnsiString; 04001 UNICODE_STRING ImportName_U; 04002 UNICODE_STRING ImportDescriptorName_U; 04003 UNICODE_STRING DllToLoad; 04004 PVOID Section; 04005 PVOID BaseAddress; 04006 BOOLEAN PrefixedNameAllocated; 04007 BOOLEAN ReferenceImport; 04008 ULONG LinkWin32k = 0; 04009 ULONG LinkNonWin32k = 0; 04010 PLOAD_IMPORTS ImportList; 04011 PLOAD_IMPORTS CompactedImportList; 04012 BOOLEAN Loaded; 04013 04014 PAGED_CODE(); 04015 04016 *LoadedImports = NO_IMPORTS_USED; 04017 04018 MissingProcedureStorageArea = *MissingProcedureName; 04019 04020 ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData( 04021 ImageBase, 04022 TRUE, 04023 IMAGE_DIRECTORY_ENTRY_IMPORT, 04024 &ImportSize); 04025 04026 if (ImportDescriptor == NULL) { 04027 return STATUS_SUCCESS; 04028 } 04029 04030 // Count the number of imports so we can allocate enough room to 04031 // store them all chained off this module's LDR_DATA_TABLE_ENTRY. 04032 // 04033 04034 Count = 0; 04035 for (Imp = ImportDescriptor; Imp->Name && Imp->OriginalFirstThunk; Imp += 1) { 04036 Count += 1; 04037 } 04038 04039 if (Count) { 04040 ImportListSize = Count * sizeof(PVOID) + sizeof(SIZE_T); 04041 04042 ImportList = (PLOAD_IMPORTS) ExAllocatePoolWithTag (PagedPool, 04043 ImportListSize, 04044 'TDmM'); 04045 04046 // 04047 // Zero it so we can recover gracefully if we fail in the middle. 04048 // If the allocation failed, just don't build the import list. 04049 // 04050 04051 if (ImportList) { 04052 RtlZeroMemory (ImportList, ImportListSize); 04053 ImportList->Count = Count; 04054 } 04055 } 04056 else { 04057 ImportList = (PLOAD_IMPORTS) 0; 04058 } 04059 04060 Count = 0; 04061 while (ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk) { 04062 04063 ImportName = (PSZ)((PCHAR)ImageBase + ImportDescriptor->Name); 04064 04065 // 04066 // A driver can link with win32k.sys if and only if it is a GDI 04067 // driver. 04068 // Also display drivers can only link to win32k.sys (and lego ...). 04069 // 04070 // So if we get a driver that links to win32k.sys and has more 04071 // than one set of imports, we will fail to load it. 04072 // 04073 04074 LinkWin32k = LinkWin32k | 04075 (!_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)); 04076 04077 // 04078 // We don't want to count coverage, win32k and irt (lego) since 04079 // display drivers CAN link against these. 04080 // 04081 04082 LinkNonWin32k = LinkNonWin32k | 04083 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) && 04084 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) && 04085 (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) && 04086 (_strnicmp(ImportName, "irt", sizeof("irt") - 1))); 04087 04088 04089 if (LinkNonWin32k && LinkWin32k) { 04090 MiDereferenceImports (ImportList); 04091 if (ImportList) { 04092 ExFreePool (ImportList); 04093 } 04094 return (STATUS_PROCEDURE_NOT_FOUND); 04095 } 04096 04097 if ((!_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) || 04098 (!_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) || 04099 (!_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) || 04100 (!_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) || 04101 (!_strnicmp(ImportName, "user32", sizeof("user32") - 1)) || 04102 (!_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)) ) { 04103 04104 MiDereferenceImports (ImportList); 04105 04106 if (ImportList) { 04107 ExFreePool (ImportList); 04108 } 04109 return (STATUS_PROCEDURE_NOT_FOUND); 04110 } 04111 04112 if ((!_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) || 04113 (!_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) || 04114 (!_strnicmp(ImportName, "hal", sizeof("hal") - 1))) { 04115 04116 // 04117 // These imports don't get refcounted because we don't 04118 // ever want to unload them. 04119 // 04120 04121 ReferenceImport = FALSE; 04122 } 04123 else { 04124 ReferenceImport = TRUE; 04125 } 04126 04127 RtlInitAnsiString(&AnsiString, ImportName); 04128 st = RtlAnsiStringToUnicodeString(&ImportName_U, &AnsiString, TRUE); 04129 if (!NT_SUCCESS(st)) { 04130 MiDereferenceImports (ImportList); 04131 if (ImportList) { 04132 ExFreePool (ImportList); 04133 } 04134 return st; 04135 } 04136 04137 if (NamePrefix && 04138 (_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1) && 04139 _strnicmp(ImportName, "hal", sizeof("hal") - 1))) { 04140 04141 ImportDescriptorName_U.MaximumLength = ImportName_U.Length + NamePrefix->Length; 04142 ImportDescriptorName_U.Buffer = ExAllocatePoolWithTag (NonPagedPool, 04143 ImportDescriptorName_U.MaximumLength, 04144 'TDmM'); 04145 if (!ImportDescriptorName_U.Buffer) { 04146 RtlFreeUnicodeString(&ImportName_U); 04147 MiDereferenceImports (ImportList); 04148 if (ImportList) { 04149 ExFreePool (ImportList); 04150 } 04151 return STATUS_INSUFFICIENT_RESOURCES; 04152 } 04153 04154 ImportDescriptorName_U.Length = 0; 04155 RtlAppendUnicodeStringToString(&ImportDescriptorName_U, NamePrefix); 04156 RtlAppendUnicodeStringToString(&ImportDescriptorName_U, &ImportName_U); 04157 PrefixedNameAllocated = TRUE; 04158 } else { 04159 ImportDescriptorName_U = ImportName_U; 04160 PrefixedNameAllocated = FALSE; 04161 } 04162 04163 Loaded = FALSE; 04164 04165 ReCheck: 04166 NextEntry = PsLoadedModuleList.Flink; 04167 ImportBase = NULL; 04168 04169 while (NextEntry != &PsLoadedModuleList) { 04170 04171 DataTableEntry = CONTAINING_RECORD(NextEntry, 04172 LDR_DATA_TABLE_ENTRY, 04173 InLoadOrderLinks); 04174 04175 if (RtlEqualUnicodeString (&ImportDescriptorName_U, 04176 &DataTableEntry->BaseDllName, 04177 TRUE 04178 )) { 04179 04180 ImportBase = DataTableEntry->DllBase; 04181 04182 // 04183 // Only bump the LoadCount if this thread did not initiate 04184 // the load below. If this thread initiated the load, then 04185 // the LoadCount has already been bumped as part of the 04186 // load - we only want to increment it here if we are 04187 // "attaching" to a previously loaded DLL. 04188 // 04189 04190 if (Loaded == FALSE && ReferenceImport == TRUE) { 04191 DataTableEntry->LoadCount += 1; 04192 } 04193 04194 break; 04195 } 04196 NextEntry = NextEntry->Flink; 04197 } 04198 04199 if (!ImportBase) { 04200 04201 // 04202 // The DLL name was not located, attempt to load this dll. 04203 // 04204 04205 DllToLoad.MaximumLength = ImportName_U.Length + 04206 ImageFileDirectory->Length + 04207 (USHORT)sizeof(WCHAR); 04208 04209 DllToLoad.Buffer = ExAllocatePoolWithTag (NonPagedPool, 04210 DllToLoad.MaximumLength, 04211 'TDmM'); 04212 04213 if (DllToLoad.Buffer) { 04214 DllToLoad.Length = ImageFileDirectory->Length; 04215 RtlMoveMemory (DllToLoad.Buffer, 04216 ImageFileDirectory->Buffer, 04217 ImageFileDirectory->Length); 04218 04219 RtlAppendStringToString ((PSTRING)&DllToLoad, 04220 (PSTRING)&ImportName_U); 04221 04222 st = MmLoadSystemImage (&DllToLoad, 04223 NamePrefix, 04224 NULL, 04225 LoadInSessionSpace, 04226 &Section, 04227 &BaseAddress); 04228 04229 ExFreePool (DllToLoad.Buffer); 04230 } else { 04231 st = STATUS_INSUFFICIENT_RESOURCES; 04232 } 04233 04234 // 04235 // Call any needed DLL initialization now. 04236 // 04237 04238 if (NT_SUCCESS(st)) { 04239 04240 PMM_DLL_INITIALIZE Func; 04241 UNICODE_STRING RegistryPath; 04242 04243 Loaded = TRUE; 04244 04245 Func = MiLocateExportName (BaseAddress, "DllInitialize"); 04246 if (Func) { 04247 04248 // 04249 // This DLL has an initialization routine. Manufacture 04250 // the service name string and invoke the function with 04251 // it. 04252 // 04253 04254 RegistryPath.MaximumLength = CmRegistryMachineSystemCurrentControlSetServices.Length + 04255 ImportName_U.Length + 04256 (USHORT)(2*sizeof(WCHAR)); 04257 RegistryPath.Buffer = ExAllocatePoolWithTag (NonPagedPool, 04258 RegistryPath.MaximumLength, 04259 'TDmM'); 04260 if (RegistryPath.Buffer) { 04261 PWCHAR Dot; 04262 04263 RegistryPath.Length = CmRegistryMachineSystemCurrentControlSetServices.Length; 04264 RtlMoveMemory (RegistryPath.Buffer, 04265 CmRegistryMachineSystemCurrentControlSetServices.Buffer, 04266 CmRegistryMachineSystemCurrentControlSetServices.Length); 04267 04268 RtlAppendUnicodeToString (&RegistryPath, L"\\"); 04269 Dot = wcschr (ImportName_U.Buffer, L'.'); 04270 if (Dot) { 04271 ImportName_U.Length = (USHORT)((Dot - ImportName_U.Buffer)*sizeof(WCHAR)); 04272 } 04273 RtlAppendUnicodeStringToString (&RegistryPath, 04274 &ImportName_U); 04275 04276 // 04277 // Now invoke the DLL's initialization routine. 04278 // 04279 04280 st = Func (&RegistryPath); 04281 ExFreePool (RegistryPath.Buffer); 04282 04283 if (!NT_SUCCESS(st)) { 04284 04285 // 04286 // Unload the DLL now as its initialization 04287 // routine failed. 04288 // 04289 04290 BOOLEAN Found; 04291 PLIST_ENTRY Entry; 04292 PLDR_DATA_TABLE_ENTRY DataTableEntry2; 04293 04294 Entry = PsLoadedModuleList.Flink; 04295 04296 Found = FALSE; 04297 while (Entry != &PsLoadedModuleList) { 04298 04299 DataTableEntry2 = CONTAINING_RECORD( 04300 Entry, 04301 LDR_DATA_TABLE_ENTRY, 04302 InLoadOrderLinks); 04303 04304 if (BaseAddress == DataTableEntry2->DllBase) { 04305 04306 Found = TRUE; 04307 break; 04308 } 04309 04310 Entry = Entry->Flink; 04311 } 04312 04313 ASSERT (Found == TRUE); 04314 MmUnloadSystemImage ((PVOID)DataTableEntry2); 04315 } 04316 } 04317 04318 } 04319 } 04320 04321 if (!NT_SUCCESS(st)) { 04322 04323 RtlFreeUnicodeString( &ImportName_U ); 04324 if (PrefixedNameAllocated) { 04325 ExFreePool( ImportDescriptorName_U.Buffer ); 04326 } 04327 MiDereferenceImports (ImportList); 04328 if (ImportList) { 04329 ExFreePool (ImportList); 04330 } 04331 return st; 04332 } 04333 04334 goto ReCheck; 04335 } 04336 04337 if (ReferenceImport == TRUE && ImportList) { 04338 ImportList->Entry[Count] = DataTableEntry; 04339 Count += 1; 04340 } 04341 04342 RtlFreeUnicodeString( &ImportName_U ); 04343 if (PrefixedNameAllocated) { 04344 ExFreePool ( ImportDescriptorName_U.Buffer ); 04345 } 04346 04347 *MissingDriverName = DataTableEntry->BaseDllName.Buffer; 04348 04349 ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( 04350 ImportBase, 04351 TRUE, 04352 IMAGE_DIRECTORY_ENTRY_EXPORT, 04353 &ExportSize 04354 ); 04355 04356 if (!ExportDirectory) { 04357 MiDereferenceImports (ImportList); 04358 if (ImportList) { 04359 ExFreePool (ImportList); 04360 } 04361 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 04362 } 04363 04364 // 04365 // Walk through the IAT and snap all the thunks. 04366 // 04367 04368 if (ImportDescriptor->OriginalFirstThunk) { 04369 04370 NameThunk = (PIMAGE_THUNK_DATA)((PCHAR)ImageBase + (ULONG)ImportDescriptor->OriginalFirstThunk); 04371 AddrThunk = (PIMAGE_THUNK_DATA)((PCHAR)ImageBase + (ULONG)ImportDescriptor->FirstThunk); 04372 04373 while (NameThunk->u1.AddressOfData) { 04374 st = MiSnapThunk(ImportBase, 04375 ImageBase, 04376 NameThunk++, 04377 AddrThunk++, 04378 ExportDirectory, 04379 ExportSize, 04380 FALSE, 04381 MissingProcedureName 04382 ); 04383 if (!NT_SUCCESS(st) ) { 04384 MiDereferenceImports (ImportList); 04385 if (ImportList) { 04386 ExFreePool (ImportList); 04387 } 04388 return st; 04389 } 04390 *MissingProcedureName = MissingProcedureStorageArea; 04391 } 04392 } 04393 04394 ImportDescriptor += 1; 04395 } 04396 04397 // 04398 // All the imports are successfully loaded so establish and compact 04399 // the import unload list. 04400 // 04401 04402 if (ImportList) { 04403 04404 // 04405 // Blank entries occur for things like the kernel, HAL & win32k.sys 04406 // that we never want to unload. Especially for things like 04407 // win32k.sys where the reference count can really hit 0. 04408 // 04409 04410 Count = 0; 04411 for (i = 0; i < ImportList->Count; i += 1) { 04412 if (ImportList->Entry[i]) { 04413 Count += 1; 04414 } 04415 } 04416 04417 if (Count == 0) { 04418 04419 ExFreePool(ImportList); 04420 ImportList = NO_IMPORTS_USED; 04421 } 04422 else if (Count == 1) { 04423 for (i = 0; i < ImportList->Count; i += 1) { 04424 if (ImportList->Entry[i]) { 04425 SingleEntry = POINTER_TO_SINGLE_ENTRY(ImportList->Entry[i]); 04426 break; 04427 } 04428 } 04429 04430 ExFreePool(ImportList); 04431 ImportList = (PLOAD_IMPORTS)SingleEntry; 04432 } 04433 else if (Count != ImportList->Count) { 04434 04435 ImportListSize = Count * sizeof(PVOID) + sizeof(SIZE_T); 04436 04437 CompactedImportList = (PLOAD_IMPORTS) 04438 ExAllocatePoolWithTag (PagedPool, 04439 ImportListSize, 04440 'TDmM'); 04441 if (CompactedImportList) { 04442 CompactedImportList->Count = Count; 04443 04444 Count = 0; 04445 for (i = 0; i < ImportList->Count; i += 1) { 04446 if (ImportList->Entry[i]) { 04447 CompactedImportList->Entry[Count] = ImportList->Entry[i]; 04448 Count += 1; 04449 } 04450 } 04451 04452 ExFreePool(ImportList); 04453 ImportList = CompactedImportList; 04454 } 04455 } 04456 04457 *LoadedImports = ImportList; 04458 } 04459 return STATUS_SUCCESS; 04460 } 04461 04462 04463 NTSTATUS 04464 MiSnapThunk( 04465 IN PVOID DllBase, 04466 IN PVOID ImageBase, 04467 IN PIMAGE_THUNK_DATA NameThunk, 04468 OUT PIMAGE_THUNK_DATA AddrThunk, 04469 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 04470 IN ULONG ExportSize, 04471 IN BOOLEAN SnapForwarder, 04472 OUT PCHAR *MissingProcedureName 04473 ) 04474 04475 /*++ 04476 04477 Routine Description: 04478 04479 This function snaps a thunk using the specified Export Section data. 04480 If the section data does not support the thunk, then the thunk is 04481 partially snapped (Dll field is still non-null, but snap address is 04482 set). 04483 04484 Arguments: 04485 04486 DllBase - Base of DLL being snapped to. 04487 04488 ImageBase - Base of image that contains the thunks to snap. 04489 04490 Thunk - On input, supplies the thunk to snap. When successfully 04491 snapped, the function field is set to point to the address in 04492 the DLL, and the DLL field is set to NULL. 04493 04494 ExportDirectory - Supplies the Export Section data from a DLL. 04495 04496 SnapForwarder - determine if the snap is for a forwarder, and therefore 04497 Address of Data is already setup. 04498 04499 Return Value: 04500 04501 04502 STATUS_SUCCESS or STATUS_DRIVER_ENTRYPOINT_NOT_FOUND or 04503 STATUS_DRIVER_ORDINAL_NOT_FOUND 04504 04505 --*/ 04506 04507 { 04508 BOOLEAN Ordinal; 04509 USHORT OrdinalNumber; 04510 PULONG NameTableBase; 04511 PUSHORT NameOrdinalTableBase; 04512 PULONG Addr; 04513 USHORT HintIndex; 04514 ULONG High; 04515 ULONG Low; 04516 ULONG Middle; 04517 LONG Result; 04518 NTSTATUS Status; 04519 PCHAR MissingProcedureName2; 04520 CHAR NameBuffer[ MAXIMUM_FILENAME_LENGTH ]; 04521 04522 PAGED_CODE(); 04523 04524 // 04525 // Determine if snap is by name, or by ordinal 04526 // 04527 04528 Ordinal = (BOOLEAN)IMAGE_SNAP_BY_ORDINAL(NameThunk->u1.Ordinal); 04529 04530 if (Ordinal && !SnapForwarder) { 04531 04532 OrdinalNumber = (USHORT)(IMAGE_ORDINAL(NameThunk->u1.Ordinal) - 04533 ExportDirectory->Base); 04534 04535 *MissingProcedureName = (PCHAR)(ULONG_PTR)OrdinalNumber; 04536 04537 } else { 04538 04539 // 04540 // Change AddressOfData from an RVA to a VA. 04541 // 04542 04543 if (!SnapForwarder) { 04544 NameThunk->u1.AddressOfData = (ULONG_PTR)ImageBase + NameThunk->u1.AddressOfData; 04545 } 04546 04547 strncpy( *MissingProcedureName, 04548 &((PIMAGE_IMPORT_BY_NAME)NameThunk->u1.AddressOfData)->Name[0], 04549 MAXIMUM_FILENAME_LENGTH - 1 04550 ); 04551 04552 // 04553 // Lookup Name in NameTable 04554 // 04555 04556 NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames); 04557 NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); 04558 04559 // 04560 // Before dropping into binary search, see if 04561 // the hint index results in a successful 04562 // match. If the hint index is zero, then 04563 // drop into binary search. 04564 // 04565 04566 HintIndex = ((PIMAGE_IMPORT_BY_NAME)NameThunk->u1.AddressOfData)->Hint; 04567 if ((ULONG)HintIndex < ExportDirectory->NumberOfNames && 04568 !strcmp((PSZ)((PIMAGE_IMPORT_BY_NAME)NameThunk->u1.AddressOfData)->Name, 04569 (PSZ)((PCHAR)DllBase + NameTableBase[HintIndex]))) { 04570 OrdinalNumber = NameOrdinalTableBase[HintIndex]; 04571 04572 } else { 04573 04574 // 04575 // Lookup the import name in the name table using a binary search. 04576 // 04577 04578 Low = 0; 04579 High = ExportDirectory->NumberOfNames - 1; 04580 04581 while (High >= Low) { 04582 04583 // 04584 // Compute the next probe index and compare the import name 04585 // with the export name entry. 04586 // 04587 04588 Middle = (Low + High) >> 1; 04589 Result = strcmp(&((PIMAGE_IMPORT_BY_NAME)NameThunk->u1.AddressOfData)->Name[0], 04590 (PCHAR)((PCHAR)DllBase + NameTableBase[Middle])); 04591 04592 if (Result < 0) { 04593 High = Middle - 1; 04594 04595 } else if (Result > 0) { 04596 Low = Middle + 1; 04597 04598 } else { 04599 break; 04600 } 04601 } 04602 04603 // 04604 // If the high index is less than the low index, then a matching 04605 // table entry was not found. Otherwise, get the ordinal number 04606 // from the ordinal table. 04607 // 04608 04609 if (High < Low) { 04610 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 04611 } else { 04612 OrdinalNumber = NameOrdinalTableBase[Middle]; 04613 } 04614 } 04615 } 04616 04617 // 04618 // If OrdinalNumber is not within the Export Address Table, 04619 // then DLL does not implement function. Snap to LDRP_BAD_DLL. 04620 // 04621 04622 if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) { 04623 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND; 04624 04625 } else { 04626 04627 MissingProcedureName2 = NameBuffer; 04628 04629 Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); 04630 (PULONG)(AddrThunk->u1.Function) = (PULONG)((PCHAR)DllBase + Addr[OrdinalNumber]); 04631 04632 // AddrThunk s/b used from here on. 04633 04634 Status = STATUS_SUCCESS; 04635 04636 if ( ((ULONG_PTR)AddrThunk->u1.Function > (ULONG_PTR)ExportDirectory) && 04637 ((ULONG_PTR)AddrThunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)) ) { 04638 04639 UNICODE_STRING UnicodeString; 04640 ANSI_STRING ForwardDllName; 04641 04642 PLIST_ENTRY NextEntry; 04643 PLDR_DATA_TABLE_ENTRY DataTableEntry; 04644 ULONG ExportSize; 04645 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 04646 04647 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 04648 04649 // 04650 // Include the dot in the length so we can do prefix later on. 04651 // 04652 04653 ForwardDllName.Buffer = (PCHAR)AddrThunk->u1.Function; 04654 ForwardDllName.Length = (USHORT)(strchr(ForwardDllName.Buffer, '.') - 04655 ForwardDllName.Buffer + 1); 04656 ForwardDllName.MaximumLength = ForwardDllName.Length; 04657 04658 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, 04659 &ForwardDllName, 04660 TRUE))) { 04661 04662 NextEntry = PsLoadedModuleList.Flink; 04663 04664 while (NextEntry != &PsLoadedModuleList) { 04665 04666 DataTableEntry = CONTAINING_RECORD(NextEntry, 04667 LDR_DATA_TABLE_ENTRY, 04668 InLoadOrderLinks); 04669 04670 // 04671 // We have to do a case INSENSITIVE comparison for 04672 // forwarder because the linker just took what is in the 04673 // def file, as opposed to looking in the exporting 04674 // image for the name. 04675 // we also use the prefix function to ignore the .exe or 04676 // .sys or .dll at the end. 04677 // 04678 04679 if (RtlPrefixString((PSTRING)&UnicodeString, 04680 (PSTRING)&DataTableEntry->BaseDllName, 04681 TRUE)) { 04682 04683 ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) 04684 RtlImageDirectoryEntryToData(DataTableEntry->DllBase, 04685 TRUE, 04686 IMAGE_DIRECTORY_ENTRY_EXPORT, 04687 &ExportSize); 04688 04689 if (ExportDirectory) { 04690 04691 IMAGE_THUNK_DATA thunkData; 04692 PIMAGE_IMPORT_BY_NAME addressOfData; 04693 ULONG length; 04694 04695 // one extra byte for NULL, 04696 04697 length = strlen(ForwardDllName.Buffer + 04698 ForwardDllName.Length) + 1; 04699 04700 addressOfData = (PIMAGE_IMPORT_BY_NAME) 04701 ExAllocatePoolWithTag (PagedPool, 04702 length + 04703 sizeof(IMAGE_IMPORT_BY_NAME), 04704 ' mM'); 04705 04706 if (addressOfData) { 04707 04708 RtlCopyMemory(&(addressOfData->Name[0]), 04709 ForwardDllName.Buffer + 04710 ForwardDllName.Length, 04711 length); 04712 04713 addressOfData->Hint = 0; 04714 04715 (PIMAGE_IMPORT_BY_NAME)(thunkData.u1.AddressOfData) = addressOfData; 04716 04717 Status = MiSnapThunk(DataTableEntry->DllBase, 04718 ImageBase, 04719 &thunkData, 04720 &thunkData, 04721 ExportDirectory, 04722 ExportSize, 04723 TRUE, 04724 &MissingProcedureName2 04725 ); 04726 04727 ExFreePool(addressOfData); 04728 04729 AddrThunk->u1 = thunkData.u1; 04730 } 04731 } 04732 04733 break; 04734 } 04735 04736 NextEntry = NextEntry->Flink; 04737 } 04738 04739 RtlFreeUnicodeString(&UnicodeString); 04740 } 04741 04742 } 04743 04744 } 04745 return Status; 04746 } 04747 #if 0 04748 PVOID 04749 MiLookupImageSectionByName ( 04750 IN PVOID Base, 04751 IN BOOLEAN MappedAsImage, 04752 IN PCHAR SectionName, 04753 OUT PULONG SectionSize 04754 ) 04755 04756 /*++ 04757 04758 Routine Description: 04759 04760 This function locates a Directory Entry within the image header 04761 and returns either the virtual address or seek address of the 04762 data the Directory describes. 04763 04764 Arguments: 04765 04766 Base - Supplies the base of the image or data file. 04767 04768 MappedAsImage - FALSE if the file is mapped as a data file. 04769 - TRUE if the file is mapped as an image. 04770 04771 SectionName - Supplies the name of the section to lookup. 04772 04773 SectionSize - Return the size of the section. 04774 04775 Return Value: 04776 04777 NULL - The file does not contain data for the specified section. 04778 04779 NON-NULL - Returns the address where the section is mapped in memory. 04780 04781 --*/ 04782 04783 { 04784 ULONG i, j, Match; 04785 PIMAGE_NT_HEADERS NtHeaders; 04786 PIMAGE_SECTION_HEADER NtSection; 04787 04788 NtHeaders = RtlImageNtHeader(Base); 04789 NtSection = IMAGE_FIRST_SECTION( NtHeaders ); 04790 for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) { 04791 Match = TRUE; 04792 for (j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++) { 04793 if (SectionName[j] != NtSection->Name[j]) { 04794 Match = FALSE; 04795 break; 04796 } 04797 if (SectionName[j] == '\0') { 04798 break; 04799 } 04800 } 04801 if (Match) { 04802 break; 04803 } 04804 NtSection += 1; 04805 } 04806 if (Match) { 04807 *SectionSize = NtSection->SizeOfRawData; 04808 if (MappedAsImage) { 04809 return( ((PCHAR)Base + NtSection->VirtualAddress)); 04810 } else { 04811 return( ((PCHAR)Base + NtSection->PointerToRawData)); 04812 } 04813 } 04814 return( NULL ); 04815 } 04816 #endif //0 04817 04818 04819 NTSTATUS 04820 MmCheckSystemImage( 04821 IN HANDLE ImageFileHandle 04822 ) 04823 04824 /*++ 04825 04826 Routine Description: 04827 04828 This function ensures the checksum for a system image is correct 04829 and matches the data in the image. 04830 04831 Arguments: 04832 04833 ImageFileHandle - Supplies the file handle of the image. 04834 04835 Return Value: 04836 04837 Status value. 04838 04839 --*/ 04840 04841 { 04842 04843 NTSTATUS Status; 04844 HANDLE Section; 04845 PVOID ViewBase; 04846 SIZE_T ViewSize; 04847 IO_STATUS_BLOCK IoStatusBlock; 04848 FILE_STANDARD_INFORMATION StandardInfo; 04849 04850 PAGED_CODE(); 04851 04852 Status = ZwCreateSection( 04853 &Section, 04854 SECTION_MAP_EXECUTE, 04855 NULL, 04856 NULL, 04857 PAGE_EXECUTE, 04858 SEC_COMMIT, 04859 ImageFileHandle 04860 ); 04861 04862 if ( !NT_SUCCESS(Status) ) { 04863 return Status; 04864 } 04865 04866 ViewBase = NULL; 04867 ViewSize = 0; 04868 04869 Status = ZwMapViewOfSection( 04870 Section, 04871 NtCurrentProcess(), 04872 (PVOID *)&ViewBase, 04873 0L, 04874 0L, 04875 NULL, 04876 &ViewSize, 04877 ViewShare, 04878 0L, 04879 PAGE_EXECUTE 04880 ); 04881 04882 if ( !NT_SUCCESS(Status) ) { 04883 ZwClose(Section); 04884 return Status; 04885 } 04886 04887 // 04888 // Now the image is mapped as a data file... Calculate its size and then 04889 // check its checksum. 04890 // 04891 04892 Status = ZwQueryInformationFile( 04893 ImageFileHandle, 04894 &IoStatusBlock, 04895 &StandardInfo, 04896 sizeof(StandardInfo), 04897 FileStandardInformation 04898 ); 04899 04900 if ( NT_SUCCESS(Status) ) { 04901 04902 try { 04903 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,StandardInfo.EndOfFile.LowPart)) { 04904 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 04905 } 04906 #if !defined(NT_UP) 04907 if ( !MmVerifyImageIsOkForMpUse(ViewBase) ) { 04908 Status = STATUS_IMAGE_MP_UP_MISMATCH; 04909 } 04910 #endif // NT_UP 04911 } except (EXCEPTION_EXECUTE_HANDLER) { 04912 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 04913 } 04914 } 04915 04916 ZwUnmapViewOfSection(NtCurrentProcess(),ViewBase); 04917 ZwClose(Section); 04918 return Status; 04919 } 04920 04921 #if !defined(NT_UP) 04922 BOOLEAN 04923 MmVerifyImageIsOkForMpUse( 04924 IN PVOID BaseAddress 04925 ) 04926 { 04927 PIMAGE_NT_HEADERS NtHeaders; 04928 04929 PAGED_CODE(); 04930 04931 // 04932 // If the file is an image file, then subtract the two checksum words 04933 // in the optional header from the computed checksum before adding 04934 // the file length, and set the value of the header checksum. 04935 // 04936 04937 NtHeaders = RtlImageNtHeader(BaseAddress); 04938 if (NtHeaders != NULL) { 04939 if ( KeNumberProcessors > 1 && 04940 (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) ) { 04941 return FALSE; 04942 } 04943 } 04944 return TRUE; 04945 } 04946 #endif // NT_UP 04947 04948 04949 PFN_NUMBER 04950 MiDeleteSystemPagableVm ( 04951 IN PMMPTE PointerPte, 04952 IN PFN_NUMBER NumberOfPtes, 04953 IN MMPTE NewPteValue, 04954 IN LOGICAL SessionAllocation, 04955 OUT PPFN_NUMBER ResidentPages 04956 ) 04957 04958 /*++ 04959 04960 Routine Description: 04961 04962 This function deletes pagable system address space (paged pool 04963 or driver pagable sections). 04964 04965 Arguments: 04966 04967 PointerPte - Supplies the start of the PTE range to delete. 04968 04969 NumberOfPtes - Supplies the number of PTEs in the range. 04970 04971 NewPteValue - Supplies the new value for the PTE. 04972 04973 SessionAllocation - Supplies TRUE if this is a range in session space. If 04974 TRUE is specified, it is assumed that the caller has 04975 already attached to the relevant session. 04976 04977 If FALSE is supplied, then it is assumed that the range 04978 is in the systemwide global space instead. 04979 04980 ResidentPages - If not NULL, the number of resident pages freed is 04981 returned here. 04982 04983 Return Value: 04984 04985 Returns the number of pages actually freed. 04986 04987 --*/ 04988 04989 { 04990 PFN_NUMBER PageFrameIndex; 04991 MMPTE PteContents; 04992 PMMPFN Pfn1; 04993 PFN_NUMBER ValidPages; 04994 PFN_NUMBER PagesRequired; 04995 MMPTE NewContents; 04996 WSLE_NUMBER WsIndex; 04997 KIRQL OldIrql; 04998 MMPTE_FLUSH_LIST PteFlushList; 04999 MMPTE JunkPte; 05000 MMWSLENTRY Locked; 05001 05002 ASSERT (KeGetCurrentIrql() <= APC_LEVEL); 05003 05004 ValidPages = 0; 05005 PagesRequired = 0; 05006 PteFlushList.Count = 0; 05007 NewContents = NewPteValue; 05008 while (NumberOfPtes != 0) { 05009 PteContents = *PointerPte; 05010 05011 if (PteContents.u.Long != ZeroKernelPte.u.Long) { 05012 05013 if (PteContents.u.Hard.Valid == 1) { 05014 05015 if (SessionAllocation == TRUE) { 05016 LOCK_SESSION_SPACE_WS (OldIrql); 05017 } 05018 else { 05019 LOCK_SYSTEM_WS (OldIrql); 05020 } 05021 05022 PteContents = *(volatile MMPTE *)PointerPte; 05023 if (PteContents.u.Hard.Valid == 0) { 05024 if (SessionAllocation == TRUE) { 05025 UNLOCK_SESSION_SPACE_WS (OldIrql); 05026 } 05027 else { 05028 UNLOCK_SYSTEM_WS (OldIrql); 05029 } 05030 05031 continue; 05032 } 05033 05034 // 05035 // Delete the page. 05036 // 05037 05038 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&PteContents); 05039 05040 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 05041 05042 // 05043 // Check to see if this is a pagable page in which 05044 // case it needs to be removed from the working set list. 05045 // 05046 05047 WsIndex = Pfn1->u1.WsIndex; 05048 if (WsIndex == 0) { 05049 ValidPages += 1; 05050 } else { 05051 if (SessionAllocation == FALSE) { 05052 MiRemoveWsle (WsIndex, 05053 MmSystemCacheWorkingSetList ); 05054 MiReleaseWsle (WsIndex, &MmSystemCacheWs); 05055 } 05056 else { 05057 WsIndex = MiLocateWsle( 05058 MiGetVirtualAddressMappedByPte(PointerPte), 05059 MmSessionSpace->Vm.VmWorkingSetList, 05060 WsIndex 05061 ); 05062 05063 ASSERT (WsIndex != WSLE_NULL_INDEX); 05064 05065 // 05066 // Check to see if this entry is locked in 05067 // the working set or locked in memory. 05068 // 05069 05070 Locked = MmSessionSpace->Wsle[WsIndex].u1.e1; 05071 05072 MiRemoveWsle (WsIndex, MmSessionSpace->Vm.VmWorkingSetList); 05073 05074 MiReleaseWsle (WsIndex, &MmSessionSpace->Vm); 05075 05076 if (Locked.LockedInWs == 1 || Locked.LockedInMemory == 1) { 05077 05078 // 05079 // This entry is locked. 05080 // 05081 #if DBG 05082 DbgPrint("MiDeleteSystemPagableVm: Session PointerPte 0x%p, Pfn 0x%p Locked in memory\n", 05083 PointerPte, 05084 Pfn1); 05085 05086 DbgBreakPoint(); 05087 #endif 05088 ASSERT (WsIndex < MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic); 05089 MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic -= 1; 05090 05091 if (WsIndex != MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic) { 05092 ULONG Entry; 05093 PVOID SwapVa; 05094 05095 Entry = MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic; 05096 ASSERT (MmSessionSpace->Wsle[Entry].u1.e1.Valid); 05097 SwapVa = MmSessionSpace->Wsle[Entry].u1.VirtualAddress; 05098 SwapVa = PAGE_ALIGN (SwapVa); 05099 05100 MiSwapWslEntries (Entry, 05101 WsIndex, 05102 &MmSessionSpace->Vm); 05103 } 05104 } 05105 else { 05106 ASSERT (WsIndex >= MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic); 05107 } 05108 } 05109 } 05110 05111 if (SessionAllocation == TRUE) { 05112 UNLOCK_SESSION_SPACE_WS (OldIrql); 05113 } 05114 else { 05115 UNLOCK_SYSTEM_WS (OldIrql); 05116 } 05117 05118 LOCK_PFN (OldIrql); 05119 #if DBG 05120 if ((Pfn1->u3.e2.ReferenceCount > 1) && 05121 (Pfn1->u3.e1.WriteInProgress == 0)) { 05122 DbgPrint ("MM:SYSLOAD - deleting pool locked for I/O pte %p, pfn %p, share=%x, refcount=%x, wsindex=%x\n", 05123 PointerPte, 05124 PageFrameIndex, 05125 Pfn1->u2.ShareCount, 05126 Pfn1->u3.e2.ReferenceCount, 05127 Pfn1->u1.WsIndex); 05128 // 05129 // This case is valid only if the page being deleted 05130 // contained a lookaside free list entry that wasn't mapped 05131 // and multiple threads faulted on it and waited together. 05132 // Some of the faulted threads are still on the ready 05133 // list but haven't run yet, and so still have references 05134 // to this page that they picked up during the fault. 05135 // But this current thread has already allocated the 05136 // lookaside entry and is now freeing the entire page. 05137 // 05138 // BUT - if it is NOT the above case, we really should 05139 // trap here. However, we don't have a good way to 05140 // distinguish between the two cases. Note 05141 // that this complication was inserted when we went to 05142 // cmpxchg8 because using locks would prevent anyone from 05143 // accessing the lookaside freelist flinks like this. 05144 // 05145 // So, the ASSERT below comes out, but we leave the print 05146 // above in (with more data added) for the case where it's 05147 // not a lookaside contender with the reference count, but 05148 // is instead a truly bad reference that needs to be 05149 // debugged. The system should crash shortly thereafter 05150 // and we'll at least have the above print to help us out. 05151 // 05152 // ASSERT (Pfn1->u3.e2.ReferenceCount == 1); 05153 } 05154 #endif //DBG 05155 // 05156 // Check if this is a prototype PTE 05157 // 05158 if (Pfn1->u3.e1.PrototypePte == 1) { 05159 05160 PMMPTE PointerPde; 05161 05162 ASSERT (SessionAllocation == TRUE); 05163 05164 // 05165 // Capture the state of the modified bit for this 05166 // PTE. 05167 // 05168 05169 MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1); 05170 05171 // 05172 // Decrement the share and valid counts of the page table 05173 // page which maps this PTE. 05174 // 05175 05176 PointerPde = MiGetPteAddress (PointerPte); 05177 if (PointerPde->u.Hard.Valid == 0) { 05178 #if !defined (_WIN64) 05179 if (!NT_SUCCESS(MiCheckPdeForPagedPool (PointerPte))) { 05180 #endif 05181 KeBugCheckEx (MEMORY_MANAGEMENT, 05182 0x61940, 05183 (ULONG_PTR)PointerPte, 05184 (ULONG_PTR)PointerPde->u.Long, 05185 (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPte)); 05186 #if !defined (_WIN64) 05187 } 05188 #endif 05189 } 05190 05191 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 05192 05193 // 05194 // Decrement the share count for the physical page. 05195 // 05196 05197 MiDecrementShareCount (PageFrameIndex); 05198 05199 // 05200 // No need to worry about fork prototype PTEs 05201 // for kernel addresses. 05202 // 05203 05204 ASSERT (PointerPte > MiHighestUserPte); 05205 05206 } else { 05207 MiDecrementShareAndValidCount (Pfn1->PteFrame); 05208 MI_SET_PFN_DELETED (Pfn1); 05209 MiDecrementShareCountOnly (PageFrameIndex); 05210 } 05211 05212 MI_WRITE_INVALID_PTE (PointerPte, NewContents); 05213 UNLOCK_PFN (OldIrql); 05214 05215 // 05216 // Flush the TB for this page. 05217 // 05218 05219 if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) { 05220 05221 // 05222 // We cannot rewrite the PTE without creating a race 05223 // condition. So don't let the TB flush do it anymore. 05224 // 05225 // PteFlushList.FlushPte[PteFlushList.Count] = PointerPte; 05226 // 05227 05228 PteFlushList.FlushPte[PteFlushList.Count] = 05229 (PMMPTE)&JunkPte; 05230 05231 PteFlushList.FlushVa[PteFlushList.Count] = 05232 MiGetVirtualAddressMappedByPte (PointerPte); 05233 PteFlushList.Count += 1; 05234 } 05235 05236 } else if (PteContents.u.Soft.Prototype) { 05237 05238 ASSERT (SessionAllocation == TRUE); 05239 05240 // 05241 // No need to worry about fork prototype PTEs 05242 // for kernel addresses. 05243 // 05244 05245 ASSERT (PointerPte >= MiHighestUserPte); 05246 05247 MI_WRITE_INVALID_PTE (PointerPte, NewContents); 05248 05249 // 05250 // We currently commit for all prototype kernel mappings since 05251 // we could copy-on-write. 05252 // 05253 05254 } else if (PteContents.u.Soft.Transition == 1) { 05255 05256 LOCK_PFN (OldIrql); 05257 05258 PteContents = *(volatile MMPTE *)PointerPte; 05259 05260 if (PteContents.u.Soft.Transition == 0) { 05261 UNLOCK_PFN (OldIrql); 05262 continue; 05263 } 05264 05265 // 05266 // Transition, release page. 05267 // 05268 05269 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (&PteContents); 05270 05271 // 05272 // Set the pointer to PTE as empty so the page 05273 // is deleted when the reference count goes to zero. 05274 // 05275 05276 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 05277 05278 MI_SET_PFN_DELETED (Pfn1); 05279 05280 MiDecrementShareCount (Pfn1->PteFrame); 05281 05282 // 05283 // Check the reference count for the page, if the reference 05284 // count is zero, move the page to the free list, if the 05285 // reference count is not zero, ignore this page. When the 05286 // reference count goes to zero, it will be placed on the 05287 // free list. 05288 // 05289 05290 if (Pfn1->u3.e2.ReferenceCount == 0) { 05291 MiUnlinkPageFromList (Pfn1); 05292 MiReleasePageFileSpace (Pfn1->OriginalPte); 05293 MiInsertPageInList (MmPageLocationList[FreePageList], 05294 PageFrameIndex); 05295 } 05296 #if DBG 05297 if ((Pfn1->u3.e2.ReferenceCount > 1) && 05298 (Pfn1->u3.e1.WriteInProgress == 0)) { 05299 DbgPrint ("MM:SYSLOAD - deleting pool locked for I/O %p\n", 05300 PageFrameIndex); 05301 DbgBreakPoint(); 05302 } 05303 #endif //DBG 05304 05305 MI_WRITE_INVALID_PTE (PointerPte, NewContents); 05306 UNLOCK_PFN (OldIrql); 05307 } else { 05308 05309 // 05310 // Demand zero, release page file space. 05311 // 05312 if (PteContents.u.Soft.PageFileHigh != 0) { 05313 LOCK_PFN (OldIrql); 05314 MiReleasePageFileSpace (PteContents); 05315 UNLOCK_PFN (OldIrql); 05316 } 05317 05318 MI_WRITE_INVALID_PTE (PointerPte, NewContents); 05319 } 05320 05321 PagesRequired += 1; 05322 } 05323 05324 NumberOfPtes -= 1; 05325 PointerPte += 1; 05326 } 05327 05328 // 05329 // There is the thorny case where one of the pages we just deleted could 05330 // get faulted back in when we released the PFN lock above within the loop. 05331 // The only time when this can happen is if a thread faulted during an 05332 // interlocked pool allocation for an address that we've just deleted. 05333 // 05334 // If this thread sees the NewContents in the PTE, it will treat it as 05335 // demand zero, and incorrectly allocate a page, PTE and WSL. It will 05336 // reference it once and realize it needs to reread the lookaside listhead 05337 // and restart the operation. But this page would live on in paged pool 05338 // as modified (but unused) until the paged pool allocator chose to give 05339 // out its virtual address again. 05340 // 05341 // The code below rewrites the PTEs which is really bad if another thread 05342 // gets a zero page between our first setting of the PTEs above and our 05343 // second setting below - because we'll reset the PTE to demand zero, but 05344 // we'll still have a WSL entry that's valid, and we spiral from there. 05345 // 05346 // We really should remove the writing of the PTE below since we've already 05347 // done it above. But for now, we're leaving it in - it's harmless because 05348 // we've chosen to fix this problem by checking for this case when we 05349 // materialize demand zero pages. Note that we have to fix this problem 05350 // by checking in the demand zero path because a thread could be coming into 05351 // that path any time before or after we flush the PTE list and any fixes 05352 // here could only address the before case, not the after. 05353 // 05354 05355 if (SessionAllocation == TRUE) { 05356 05357 // 05358 // Session space has no ASN - flush the entire TB. 05359 // 05360 05361 MI_FLUSH_ENTIRE_SESSION_TB (TRUE, TRUE); 05362 } 05363 05364 LOCK_PFN (OldIrql); 05365 MiFlushPteList (&PteFlushList, TRUE, NewContents); 05366 UNLOCK_PFN (OldIrql); 05367 05368 if (ARGUMENT_PRESENT(ResidentPages)) { 05369 *ResidentPages = ValidPages; 05370 } 05371 05372 return PagesRequired; 05373 } 05374 05375 VOID 05376 MiSetImageProtect ( 05377 IN PSEGMENT Segment, 05378 IN ULONG Protection 05379 ) 05380 05381 /*++ 05382 05383 Routine Description: 05384 05385 This function sets the protection of all prototype PTEs to the specified 05386 protection. 05387 05388 Arguments: 05389 05390 Segment - Supplies a pointer to the segment to protect. 05391 05392 Protection - Supplies the protection value to set. 05393 05394 Return Value: 05395 05396 None. 05397 05398 --*/ 05399 05400 { 05401 PMMPTE PointerPte; 05402 PMMPTE LastPte; 05403 MMPTE PteContents; 05404 PSUBSECTION SubSection; 05405 05406 // 05407 // Set the subsection protections. 05408 // 05409 05410 ASSERT (Segment->ControlArea->u.Flags.GlobalOnlyPerSession == 0); 05411 05412 if ((Protection & MM_PROTECTION_WRITE_MASK) == 0) { 05413 SubSection = (PSUBSECTION)(Segment->ControlArea + 1); 05414 SubSection->u.SubsectionFlags.Protection = Protection; 05415 SubSection->u.SubsectionFlags.ReadOnly = 1; 05416 } 05417 05418 PointerPte = Segment->PrototypePte; 05419 LastPte = PointerPte + Segment->NonExtendedPtes; 05420 05421 MmLockPagedPool (PointerPte, (LastPte - PointerPte) * sizeof (MMPTE)); 05422 05423 do { 05424 PteContents = *PointerPte; 05425 ASSERT (PteContents.u.Hard.Valid == 0); 05426 if (PteContents.u.Long != ZeroPte.u.Long) { 05427 if ((PteContents.u.Soft.Prototype == 0) && 05428 (PteContents.u.Soft.Transition == 1)) { 05429 if (MiSetProtectionOnTransitionPte (PointerPte, Protection)) { 05430 continue; 05431 } 05432 } 05433 else { 05434 PointerPte->u.Soft.Protection = Protection; 05435 } 05436 } 05437 PointerPte += 1; 05438 } while (PointerPte < LastPte); 05439 05440 PointerPte = Segment->PrototypePte; 05441 MmUnlockPagedPool (PointerPte, (LastPte - PointerPte) * sizeof (MMPTE)); 05442 05443 return; 05444 } 05445 05446 05447 VOID 05448 MiSetSystemCodeProtection ( 05449 IN PMMPTE FirstPte, 05450 IN PMMPTE LastPte 05451 ) 05452 05453 /*++ 05454 05455 Routine Description: 05456 05457 This function sets the protection of system code to read only. 05458 Note this is different from protecting section-backed code like win32k. 05459 05460 Arguments: 05461 05462 FirstPte - Supplies the starting PTE. 05463 05464 LastPte - Supplies the ending PTE. 05465 05466 Return Value: 05467 05468 None. 05469 05470 --*/ 05471 05472 { 05473 KIRQL OldIrql; 05474 MMPTE PteContents; 05475 MMPTE TempPte; 05476 MMPTE PreviousPte; 05477 PMMPTE PointerPte; 05478 PMMPTE PointerPde; 05479 PMMPTE PointerProtoPte; 05480 ULONG ProtectionMask; 05481 PMMPFN Pfn1; 05482 PMMPFN ProtoPfn; 05483 LOGICAL SessionAddress; 05484 05485 #if defined(_X86_) 05486 ASSERT (MI_IS_PHYSICAL_ADDRESS(MiGetVirtualAddressMappedByPte(FirstPte)) == 0); 05487 #endif 05488 05489 SessionAddress = FALSE; 05490 05491 if (MI_IS_SESSION_ADDRESS(MiGetVirtualAddressMappedByPte(FirstPte))) { 05492 SessionAddress = TRUE; 05493 } 05494 05495 ProtectionMask = MM_EXECUTE_READ; 05496 05497 // 05498 // Make these PTEs read only. 05499 // 05500 // Note that the write bit may already be off (in the valid PTE) if the 05501 // page has already been inpaged from the paging file and has not since 05502 // been dirtied. 05503 // 05504 05505 PointerPte = FirstPte; 05506 05507 LOCK_PFN (OldIrql); 05508 05509 while (PointerPte <= LastPte) { 05510 05511 PteContents = *PointerPte; 05512 05513 if ((PteContents.u.Long == 0) || (!*MiPteStr)) { 05514 PointerPte += 1; 05515 continue; 05516 } 05517 05518 if (PteContents.u.Hard.Valid == 1) { 05519 05520 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 05521 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 05522 05523 // 05524 // Note the dirty and write bits get turned off here. 05525 // Any existing pagefile addresses for clean pages are preserved. 05526 // 05527 05528 if (MI_IS_PTE_DIRTY(PteContents)) { 05529 MI_CAPTURE_DIRTY_BIT_TO_PFN (&PteContents, Pfn1); 05530 } 05531 05532 MI_MAKE_VALID_PTE (TempPte, 05533 PteContents.u.Hard.PageFrameNumber, 05534 Pfn1->OriginalPte.u.Soft.Protection, 05535 PointerPte); 05536 05537 if (SessionAddress == TRUE) { 05538 05539 // 05540 // Session space has no ASN - flush the entire TB. 05541 // 05542 05543 MI_FLUSH_SINGLE_SESSION_TB (MiGetVirtualAddressMappedByPte (PointerPte), 05544 TRUE, 05545 TRUE, 05546 (PHARDWARE_PTE)PointerPte, 05547 TempPte.u.Flush, 05548 PreviousPte); 05549 } 05550 else { 05551 KeFlushSingleTb (MiGetVirtualAddressMappedByPte (PointerPte), 05552 TRUE, 05553 TRUE, 05554 (PHARDWARE_PTE)PointerPte, 05555 TempPte.u.Flush); 05556 } 05557 } 05558 else if (PteContents.u.Soft.Prototype == 1) { 05559 05560 if (SessionAddress == TRUE) { 05561 PointerPte->u.Proto.ReadOnly = 1; 05562 } 05563 else { 05564 PointerProtoPte = MiPteToProto(PointerPte); 05565 05566 if (!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte)) { 05567 PointerPde = MiGetPteAddress (PointerProtoPte); 05568 if (PointerPde->u.Hard.Valid == 0) { 05569 MiMakeSystemAddressValidPfn (PointerProtoPte); 05570 05571 // 05572 // The world may change if we had to wait. 05573 // 05574 05575 PteContents = *PointerPte; 05576 if ((PteContents.u.Hard.Valid == 1) || 05577 (PteContents.u.Soft.Prototype == 0)) { 05578 continue; 05579 } 05580 } 05581 05582 ProtoPfn = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 05583 MI_ADD_LOCKED_PAGE_CHARGE(ProtoPfn, 12); 05584 ProtoPfn->u3.e2.ReferenceCount += 1; 05585 ASSERT (ProtoPfn->u3.e2.ReferenceCount > 1); 05586 } 05587 05588 PteContents = *PointerProtoPte; 05589 05590 if (PteContents.u.Long != ZeroPte.u.Long) { 05591 05592 ASSERT (PteContents.u.Hard.Valid == 0); 05593 05594 PointerProtoPte->u.Soft.Protection = ProtectionMask; 05595 05596 if ((PteContents.u.Soft.Prototype == 0) && 05597 (PteContents.u.Soft.Transition == 1)) { 05598 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 05599 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 05600 } 05601 } 05602 05603 if (!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte)) { 05604 ASSERT (ProtoPfn->u3.e2.ReferenceCount > 1); 05605 MI_REMOVE_LOCKED_PAGE_CHARGE(ProtoPfn, 13); 05606 ProtoPfn->u3.e2.ReferenceCount -= 1; 05607 } 05608 } 05609 } 05610 else if (PteContents.u.Soft.Transition == 1) { 05611 05612 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 05613 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 05614 PointerPte->u.Soft.Protection = ProtectionMask; 05615 05616 } 05617 else { 05618 05619 // 05620 // Must be page file space or demand zero. 05621 // 05622 05623 PointerPte->u.Soft.Protection = ProtectionMask; 05624 } 05625 PointerPte += 1; 05626 } 05627 05628 UNLOCK_PFN (OldIrql); 05629 } 05630 05631 05632 VOID 05633 MiWriteProtectSystemImage ( 05634 IN PVOID DllBase 05635 ) 05636 05637 /*++ 05638 05639 Routine Description: 05640 05641 This function sets the protection of a system component to read only. 05642 05643 Arguments: 05644 05645 DllBase - Supplies the base address of the system component. 05646 05647 Return Value: 05648 05649 None. 05650 05651 --*/ 05652 05653 { 05654 ULONG SectionProtection; 05655 ULONG NumberOfSubsections; 05656 ULONG SectionVirtualSize; 05657 ULONG ImageAlignment; 05658 ULONG OffsetToSectionTable; 05659 ULONG NumberOfPtes; 05660 ULONG_PTR VirtualAddress; 05661 ULONG_PTR LastVirtualAddress; 05662 PMMPTE PointerPte; 05663 PMMPTE FirstPte; 05664 PMMPTE LastPte; 05665 PMMPTE LastImagePte; 05666 PMMPTE WritablePte; 05667 PIMAGE_NT_HEADERS NtHeader; 05668 PIMAGE_FILE_HEADER FileHeader; 05669 PIMAGE_SECTION_HEADER SectionTableEntry; 05670 05671 PAGED_CODE(); 05672 05673 if (MI_IS_PHYSICAL_ADDRESS(DllBase)) { 05674 return; 05675 } 05676 05677 NtHeader = RtlImageNtHeader (DllBase); 05678 05679 ASSERT (NtHeader); 05680 05681 ImageAlignment = NtHeader->OptionalHeader.SectionAlignment; 05682 05683 // 05684 // All session drivers must be one way or the other - no mixing is allowed 05685 // within multiple copy-on-write drivers. 05686 // 05687 05688 if (MI_IS_SESSION_ADDRESS(DllBase) == 0) { 05689 05690 // 05691 // Images prior to NT5 were not protected from stepping all over 05692 // their (and others) code and readonly data. Here we somewhat 05693 // preserve that behavior, but don't allow them to step on anyone else. 05694 // 05695 05696 // 05697 // Note that drivers that are built for NT5 have presumably run on 05698 // NT5, and these get the benefits of full protection. 05699 // 05700 05701 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion < 5) || 05702 (NtHeader->OptionalHeader.MajorOperatingSystemVersion > 10)) { 05703 return; 05704 } 05705 05706 if ((NtHeader->OptionalHeader.MajorImageVersion < 5) || 05707 (NtHeader->OptionalHeader.MajorImageVersion > 10)) { 05708 return; 05709 } 05710 } 05711 05712 NumberOfPtes = BYTES_TO_PAGES (NtHeader->OptionalHeader.SizeOfImage); 05713 05714 FileHeader = &NtHeader->FileHeader; 05715 05716 NumberOfSubsections = FileHeader->NumberOfSections; 05717 05718 ASSERT (NumberOfSubsections != 0); 05719 05720 OffsetToSectionTable = sizeof(ULONG) + 05721 sizeof(IMAGE_FILE_HEADER) + 05722 FileHeader->SizeOfOptionalHeader; 05723 05724 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 05725 OffsetToSectionTable); 05726 05727 // 05728 // Verify the image contains subsections ordered by increasing virtual 05729 // address and that there are no overlaps. 05730 // 05731 05732 FirstPte = NULL; 05733 LastVirtualAddress = (ULONG_PTR)DllBase; 05734 05735 for ( ; NumberOfSubsections > 0; NumberOfSubsections -= 1, SectionTableEntry += 1) { 05736 05737 if (SectionTableEntry->Misc.VirtualSize == 0) { 05738 SectionVirtualSize = SectionTableEntry->SizeOfRawData; 05739 } 05740 else { 05741 SectionVirtualSize = SectionTableEntry->Misc.VirtualSize; 05742 } 05743 05744 VirtualAddress = (ULONG_PTR)DllBase + SectionTableEntry->VirtualAddress; 05745 if (VirtualAddress <= LastVirtualAddress) { 05746 05747 // 05748 // Subsections are not in an increasing virtual address ordering. 05749 // No protection is provided for such a poorly linked image. 05750 // 05751 05752 KdPrint (("MM:sysload - Image at %p is badly linked\n", DllBase)); 05753 return; 05754 } 05755 LastVirtualAddress = VirtualAddress + SectionVirtualSize - 1; 05756 } 05757 05758 NumberOfSubsections = FileHeader->NumberOfSections; 05759 ASSERT (NumberOfSubsections != 0); 05760 05761 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 05762 OffsetToSectionTable); 05763 05764 LastVirtualAddress = 0; 05765 05766 // 05767 // Set writable PTE here so the image headers are excluded. This is 05768 // needed so that locking down of sections can continue to edit the 05769 // image headers for counts. 05770 // 05771 05772 WritablePte = MiGetPteAddress ((ULONG_PTR)(SectionTableEntry + NumberOfSubsections) - 1); 05773 LastImagePte = MiGetPteAddress(DllBase) + NumberOfPtes; 05774 05775 for ( ; NumberOfSubsections > 0; NumberOfSubsections -= 1, SectionTableEntry += 1) { 05776 05777 if (SectionTableEntry->Misc.VirtualSize == 0) { 05778 SectionVirtualSize = SectionTableEntry->SizeOfRawData; 05779 } 05780 else { 05781 SectionVirtualSize = SectionTableEntry->Misc.VirtualSize; 05782 } 05783 05784 VirtualAddress = (ULONG_PTR)DllBase + SectionTableEntry->VirtualAddress; 05785 05786 PointerPte = MiGetPteAddress (VirtualAddress); 05787 05788 if (PointerPte >= LastImagePte) { 05789 05790 // 05791 // Skip relocation subsections (which aren't given VA space). 05792 // 05793 05794 break; 05795 } 05796 05797 SectionProtection = (SectionTableEntry->Characteristics & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE)); 05798 05799 if (SectionProtection & IMAGE_SCN_MEM_WRITE) { 05800 05801 // 05802 // This is a writable subsection, skip it. Make sure if it's 05803 // sharing a PTE (and update the linker so this doesn't happen 05804 // for the kernel at least) that the last PTE isn't made 05805 // read only. 05806 // 05807 05808 WritablePte = MiGetPteAddress (VirtualAddress + SectionVirtualSize - 1); 05809 05810 if (LastVirtualAddress) { 05811 LastPte = MiGetPteAddress (LastVirtualAddress); 05812 05813 if (LastPte == PointerPte) { 05814 LastPte -= 1; 05815 } 05816 05817 if (FirstPte <= LastPte) { 05818 05819 ASSERT (PointerPte < LastImagePte); 05820 05821 if (LastPte >= LastImagePte) { 05822 LastPte = LastImagePte - 1; 05823 } 05824 05825 MiSetSystemCodeProtection (FirstPte, LastPte); 05826 } 05827 05828 LastVirtualAddress = 0; 05829 } 05830 continue; 05831 } 05832 05833 if (LastVirtualAddress == 0) { 05834 05835 // 05836 // There is no previous subsection or the previous 05837 // subsection was writable. Thus the current starting PTE 05838 // could be mapping both a readonly and a readwrite 05839 // subsection if the image alignment is less than PAGE_SIZE. 05840 // These cases (in either order) are handled here. 05841 // 05842 05843 if (PointerPte == WritablePte) { 05844 LastPte = MiGetPteAddress (VirtualAddress + SectionVirtualSize - 1); 05845 if (PointerPte == LastPte) { 05846 05847 // 05848 // Nothing can be protected in this subsection 05849 // due to the image alignment specified for the executable. 05850 // 05851 05852 continue; 05853 } 05854 PointerPte += 1; 05855 } 05856 FirstPte = PointerPte; 05857 } 05858 05859 LastVirtualAddress = VirtualAddress + SectionVirtualSize - 1; 05860 } 05861 05862 if (LastVirtualAddress) { 05863 LastPte = MiGetPteAddress (LastVirtualAddress); 05864 05865 if ((FirstPte <= LastPte) && (FirstPte < LastImagePte)) { 05866 05867 if (LastPte >= LastImagePte) { 05868 LastPte = LastImagePte - 1; 05869 } 05870 05871 MiSetSystemCodeProtection (FirstPte, LastPte); 05872 } 05873 } 05874 } 05875 05876 05877 VOID 05878 MiUpdateThunks ( 05879 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 05880 IN PVOID OldAddress, 05881 IN PVOID NewAddress, 05882 IN ULONG NumberOfBytes 05883 ) 05884 05885 /*++ 05886 05887 Routine Description: 05888 05889 This function updates the IATs of all the loaded modules in the system 05890 to handle a newly relocated image. 05891 05892 Arguments: 05893 05894 LoaderBlock - Supplies a pointer to the system loader block. 05895 05896 OldAddress - Supplies the old address of the DLL which was just relocated. 05897 05898 NewAddress - Supplies the new address of the DLL which was just relocated. 05899 05900 NumberOfBytes - Supplies the number of bytes spanned by the DLL. 05901 05902 Return Value: 05903 05904 None. 05905 05906 --*/ 05907 05908 { 05909 PULONG_PTR ImportThunk; 05910 ULONG_PTR OldAddressHigh; 05911 ULONG_PTR AddressDifference; 05912 PLDR_DATA_TABLE_ENTRY DataTableEntry; 05913 PLIST_ENTRY NextEntry; 05914 ULONG_PTR i; 05915 ULONG ImportSize; 05916 05917 // 05918 // Note this routine must not call any modules outside the kernel. 05919 // This is because that module may itself be the one being relocated right 05920 // now. 05921 // 05922 05923 OldAddressHigh = (ULONG_PTR)((PCHAR)OldAddress + NumberOfBytes - 1); 05924 AddressDifference = (ULONG_PTR)NewAddress - (ULONG_PTR)OldAddress; 05925 05926 NextEntry = LoaderBlock->LoadOrderListHead.Flink; 05927 05928 for ( ; NextEntry != &LoaderBlock->LoadOrderListHead; NextEntry = NextEntry->Flink) { 05929 05930 DataTableEntry = CONTAINING_RECORD(NextEntry, 05931 LDR_DATA_TABLE_ENTRY, 05932 InLoadOrderLinks); 05933 05934 ImportThunk = (PULONG_PTR)RtlImageDirectoryEntryToData( 05935 DataTableEntry->DllBase, 05936 TRUE, 05937 IMAGE_DIRECTORY_ENTRY_IAT, 05938 &ImportSize); 05939 05940 if (ImportThunk == NULL) { 05941 continue; 05942 } 05943 05944 ImportSize /= sizeof(PULONG_PTR); 05945 05946 for (i = 0; i < ImportSize; i += 1, ImportThunk += 1) { 05947 if (*ImportThunk >= (ULONG_PTR)OldAddress && *ImportThunk <= OldAddressHigh) { 05948 *ImportThunk += AddressDifference; 05949 } 05950 } 05951 } 05952 } 05953 05954 05955 VOID 05956 MiReloadBootLoadedDrivers ( 05957 IN PLOADER_PARAMETER_BLOCK LoaderBlock 05958 ) 05959 05960 /*++ 05961 05962 Routine Description: 05963 05964 The kernel, HAL and boot drivers are relocated by the loader. 05965 All the boot drivers are then relocated again here. 05966 05967 This function relocates osloader-loaded images into system PTEs. This 05968 gives these images the benefits that all other drivers already enjoy, 05969 including : 05970 05971 1. Paging of the drivers (this is more than 500K today). 05972 2. Write-protection of their text sections. 05973 3. Automatic unload of drivers on last dereference. 05974 05975 Note care must be taken when processing HIGHADJ relocations more than once. 05976 05977 Arguments: 05978 05979 LoaderBlock - Supplies a pointer to the system loader block. 05980 05981 Return Value: 05982 05983 None. 05984 05985 Environment: 05986 05987 Kernel mode, Phase 0 Initialization. 05988 05989 --*/ 05990 05991 { 05992 PLDR_DATA_TABLE_ENTRY DataTableEntry; 05993 PLIST_ENTRY NextEntry; 05994 PIMAGE_NT_HEADERS NtHeader; 05995 PIMAGE_DATA_DIRECTORY DataDirectory; 05996 ULONG_PTR i; 05997 ULONG NumberOfPtes; 05998 ULONG NumberOfLoaderPtes; 05999 PMMPTE PointerPte; 06000 PMMPTE LastPte; 06001 PMMPTE LoaderPte; 06002 MMPTE PteContents; 06003 MMPTE TempPte; 06004 PVOID LoaderImageAddress; 06005 PVOID NewImageAddress; 06006 NTSTATUS Status; 06007 PFN_NUMBER PageFrameIndex; 06008 PFN_NUMBER PteFramePage; 06009 PMMPTE PteFramePointer; 06010 PMMPFN Pfn1; 06011 PMMPFN Pfn2; 06012 KIRQL OldIrql; 06013 PCHAR RelocatedVa; 06014 PCHAR NonRelocatedVa; 06015 LOGICAL StopMoving; 06016 06017 #if !defined (_X86_) 06018 06019 // 06020 // Non-x86 platforms have map registers so no memory shuffling is needed. 06021 // 06022 06023 MmMakeLowMemory = FALSE; 06024 #endif 06025 StopMoving = FALSE; 06026 06027 i = 0; 06028 NextEntry = LoaderBlock->LoadOrderListHead.Flink; 06029 06030 for ( ; NextEntry != &LoaderBlock->LoadOrderListHead; NextEntry = NextEntry->Flink) { 06031 06032 // 06033 // Skip the kernel and the HAL. Note their relocation sections will 06034 // be automatically reclaimed. 06035 // 06036 06037 i += 1; 06038 if (i <= 2) { 06039 continue; 06040 } 06041 06042 DataTableEntry = CONTAINING_RECORD(NextEntry, 06043 LDR_DATA_TABLE_ENTRY, 06044 InLoadOrderLinks); 06045 06046 // 06047 // Ensure that the relocation section exists and that the loader 06048 // hasn't freed it already. 06049 // 06050 06051 NtHeader = RtlImageNtHeader(DataTableEntry->DllBase); 06052 06053 if (NtHeader == NULL) { 06054 continue; 06055 } 06056 06057 if (IMAGE_DIRECTORY_ENTRY_BASERELOC >= NtHeader->OptionalHeader.NumberOfRvaAndSizes) { 06058 continue; 06059 } 06060 06061 DataDirectory = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 06062 06063 if (DataDirectory->VirtualAddress == 0) { 06064 continue; 06065 } 06066 06067 if (DataDirectory->VirtualAddress + DataDirectory->Size > DataTableEntry->SizeOfImage) { 06068 06069 // 06070 // The relocation section has already been freed, the user must 06071 // be using an old loader that didn't save the relocations. 06072 // 06073 06074 continue; 06075 } 06076 06077 LoaderImageAddress = DataTableEntry->DllBase; 06078 LoaderPte = MiGetPteAddress(DataTableEntry->DllBase); 06079 NumberOfLoaderPtes = (ULONG)((ROUND_TO_PAGES(DataTableEntry->SizeOfImage)) >> PAGE_SHIFT); 06080 06081 LOCK_PFN (OldIrql); 06082 06083 PointerPte = LoaderPte; 06084 LastPte = PointerPte + NumberOfLoaderPtes; 06085 06086 while (PointerPte < LastPte) { 06087 ASSERT (PointerPte->u.Hard.Valid == 1); 06088 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 06089 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06090 06091 // 06092 // Mark the page as modified so boot drivers that call 06093 // MmPageEntireDriver don't lose their unmodified data ! 06094 // 06095 06096 Pfn1->u3.e1.Modified = 1; 06097 PointerPte += 1; 06098 } 06099 06100 UNLOCK_PFN (OldIrql); 06101 06102 // 06103 // Extra PTEs are allocated here to map the relocation section at the 06104 // new address so the image can be relocated. 06105 // 06106 06107 NumberOfPtes = NumberOfLoaderPtes; 06108 06109 PointerPte = MiReserveSystemPtes (NumberOfPtes, 06110 SystemPteSpace, 06111 0, 06112 0, 06113 FALSE); 06114 06115 if (PointerPte == NULL) { 06116 continue; 06117 } 06118 06119 LastPte = PointerPte + NumberOfPtes; 06120 06121 NewImageAddress = MiGetVirtualAddressMappedByPte (PointerPte); 06122 06123 #if DBG_SYSLOAD 06124 DbgPrint ("Relocating %wZ from %p to %p, %x bytes\n", 06125 &DataTableEntry->FullDllName, 06126 DataTableEntry->DllBase, 06127 NewImageAddress, 06128 DataTableEntry->SizeOfImage 06129 ); 06130 #endif 06131 06132 // 06133 // This assert is important because the assumption is made that PTEs 06134 // (not superpages) are mapping these drivers. 06135 // 06136 06137 ASSERT (InitializationPhase == 0); 06138 06139 // 06140 // If the system is configured to make low memory available for ISA 06141 // type drivers, then copy the boot loaded drivers now. Otherwise 06142 // only PTE adjustment is done. Presumably some day when ISA goes 06143 // away this code can be removed. 06144 // 06145 06146 RelocatedVa = NewImageAddress; 06147 NonRelocatedVa = (PCHAR) DataTableEntry->DllBase; 06148 06149 while (PointerPte < LastPte) { 06150 06151 PteContents = *LoaderPte; 06152 ASSERT (PteContents.u.Hard.Valid == 1); 06153 06154 if (MmMakeLowMemory == TRUE) { 06155 #if DBG 06156 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (LoaderPte); 06157 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06158 ASSERT (Pfn1->u1.WsIndex == 0); 06159 #endif 06160 LOCK_PFN (OldIrql); 06161 MiEnsureAvailablePageOrWait (NULL, NULL); 06162 PageFrameIndex = MiRemoveAnyPage( 06163 MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); 06164 06165 if (PageFrameIndex < (16*1024*1024)/PAGE_SIZE) { 06166 06167 // 06168 // If the frames cannot be replaced with high pages 06169 // then stop copying. 06170 // 06171 06172 #if defined (_X86PAE_) 06173 if (MiNoLowMemory == FALSE) 06174 #endif 06175 StopMoving = TRUE; 06176 } 06177 06178 MI_MAKE_VALID_PTE (TempPte, 06179 PageFrameIndex, 06180 MM_EXECUTE_READWRITE, 06181 PointerPte); 06182 06183 MI_SET_PTE_DIRTY (TempPte); 06184 MI_SET_ACCESSED_IN_PTE (&TempPte, 1); 06185 MI_WRITE_VALID_PTE (PointerPte, TempPte); 06186 06187 MiInitializePfn (PageFrameIndex, PointerPte, 1); 06188 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06189 Pfn1->u3.e1.Modified = 1; 06190 06191 // 06192 // Initialize the WsIndex just like the original page had it. 06193 // 06194 06195 Pfn1->u1.WsIndex = 0; 06196 06197 UNLOCK_PFN (OldIrql); 06198 RtlMoveMemory (RelocatedVa, NonRelocatedVa, PAGE_SIZE); 06199 RelocatedVa += PAGE_SIZE; 06200 NonRelocatedVa += PAGE_SIZE; 06201 } 06202 else { 06203 MI_MAKE_VALID_PTE (TempPte, 06204 PteContents.u.Hard.PageFrameNumber, 06205 MM_EXECUTE_READWRITE, 06206 PointerPte); 06207 06208 MI_WRITE_VALID_PTE (PointerPte, TempPte); 06209 } 06210 06211 PointerPte += 1; 06212 LoaderPte += 1; 06213 } 06214 PointerPte -= NumberOfPtes; 06215 06216 ASSERT (*(PULONG)NewImageAddress == *(PULONG)LoaderImageAddress); 06217 06218 // 06219 // Image is now mapped at the new address. Relocate it (again). 06220 // 06221 06222 #if defined(_ALPHA_) 06223 06224 // 06225 // HIGHADJ relocations need special re-processing. This needs to be 06226 // done before resetting ImageBase. 06227 // 06228 06229 Status = (NTSTATUS)LdrDoubleRelocateImage(NewImageAddress, 06230 LoaderImageAddress, 06231 "SYSLDR", 06232 (ULONG)STATUS_SUCCESS, 06233 (ULONG)STATUS_CONFLICTING_ADDRESSES, 06234 (ULONG)STATUS_INVALID_IMAGE_FORMAT 06235 ); 06236 #endif 06237 06238 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)LoaderImageAddress; 06239 if (MmMakeLowMemory == TRUE) { 06240 PIMAGE_NT_HEADERS NtHeader2; 06241 06242 NtHeader2 = (PIMAGE_NT_HEADERS)((PCHAR)NtHeader + (RelocatedVa - NonRelocatedVa)); 06243 NtHeader2->OptionalHeader.ImageBase = (ULONG_PTR)LoaderImageAddress; 06244 } 06245 06246 Status = (NTSTATUS)LdrRelocateImage(NewImageAddress, 06247 "SYSLDR", 06248 (ULONG)STATUS_SUCCESS, 06249 (ULONG)STATUS_CONFLICTING_ADDRESSES, 06250 (ULONG)STATUS_INVALID_IMAGE_FORMAT 06251 ); 06252 06253 if (!NT_SUCCESS(Status)) { 06254 06255 if (MmMakeLowMemory == TRUE) { 06256 while (PointerPte < LastPte) { 06257 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 06258 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06259 MiDecrementShareAndValidCount (Pfn1->PteFrame); 06260 MI_SET_PFN_DELETED (Pfn1); 06261 MiDecrementShareCountOnly (PageFrameIndex); 06262 PointerPte += 1; 06263 } 06264 } 06265 06266 MiReleaseSystemPtes (PointerPte, 06267 NumberOfPtes, 06268 SystemPteSpace); 06269 06270 if (StopMoving == TRUE) { 06271 MmMakeLowMemory = FALSE; 06272 } 06273 06274 continue; 06275 } 06276 06277 // 06278 // Update the IATs for all other loaded modules that reference this one. 06279 // 06280 06281 NonRelocatedVa = (PCHAR) DataTableEntry->DllBase; 06282 DataTableEntry->DllBase = NewImageAddress; 06283 06284 MiUpdateThunks (LoaderBlock, 06285 LoaderImageAddress, 06286 NewImageAddress, 06287 DataTableEntry->SizeOfImage); 06288 06289 06290 // 06291 // Update the loaded module list entry. 06292 // 06293 06294 DataTableEntry->Flags |= LDRP_SYSTEM_MAPPED; 06295 DataTableEntry->DllBase = NewImageAddress; 06296 DataTableEntry->EntryPoint = 06297 (PVOID)((PCHAR)NewImageAddress + NtHeader->OptionalHeader.AddressOfEntryPoint); 06298 DataTableEntry->SizeOfImage = NumberOfPtes << PAGE_SHIFT; 06299 06300 // 06301 // Update the PFNs of the image to support trimming. 06302 // Note that the loader addresses are freed now so no references 06303 // to it are permitted after this point. 06304 // 06305 06306 LoaderPte = MiGetPteAddress (NonRelocatedVa); 06307 06308 LOCK_PFN (OldIrql); 06309 06310 while (PointerPte < LastPte) { 06311 ASSERT (PointerPte->u.Hard.Valid == 1); 06312 06313 if (MmMakeLowMemory == TRUE) { 06314 ASSERT (LoaderPte->u.Hard.Valid == 1); 06315 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (LoaderPte); 06316 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06317 06318 #if defined (_X86_) || defined (_IA64_) 06319 06320 // 06321 // Decrement the share count on the original page table 06322 // page so it can be freed. 06323 // 06324 06325 MiDecrementShareAndValidCount (Pfn1->PteFrame); 06326 #endif 06327 06328 MI_SET_PFN_DELETED (Pfn1); 06329 MiDecrementShareCountOnly (PageFrameIndex); 06330 LoaderPte += 1; 06331 } 06332 else { 06333 06334 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 06335 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 06336 06337 #if defined (_X86_) || defined (_IA64_) 06338 06339 // 06340 // Decrement the share count on the original page table 06341 // page so it can be freed. 06342 // 06343 06344 MiDecrementShareAndValidCount (Pfn1->PteFrame); 06345 *Pfn1->PteAddress = ZeroPte; 06346 #endif 06347 06348 // 06349 // Chain the PFN entry to its new page table. 06350 // 06351 06352 PteFramePointer = MiGetPteAddress(PointerPte); 06353 PteFramePage = MI_GET_PAGE_FRAME_FROM_PTE (PteFramePointer); 06354 06355 Pfn1->PteFrame = PteFramePage; 06356 Pfn1->PteAddress = PointerPte; 06357 06358 // 06359 // Increment the share count for the page table page that now 06360 // contains the PTE that was copied. 06361 // 06362 06363 Pfn2 = MI_PFN_ELEMENT (PteFramePage); 06364 Pfn2->u2.ShareCount += 1; 06365 } 06366 06367 PointerPte += 1; 06368 } 06369 06370 UNLOCK_PFN (OldIrql); 06371 06372 // 06373 // The physical pages mapping the relocation section are freed 06374 // later with the rest of the initialization code spanned by the 06375 // DataTableEntry->SizeOfImage. 06376 // 06377 06378 if (StopMoving == TRUE) { 06379 MmMakeLowMemory = FALSE; 06380 } 06381 } 06382 #if defined (_X86PAE_) 06383 if (MiNoLowMemory == TRUE) { 06384 MiRemoveLowPages (); 06385 } 06386 #endif 06387 } 06388 06389 #if defined (_X86_) 06390 PMMPTE MiKernelResourceStartPte; 06391 PMMPTE MiKernelResourceEndPte; 06392 #endif 06393 06394 VOID 06395 MiLocateKernelSections ( 06396 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 06397 ) 06398 06399 /*++ 06400 06401 Routine Description: 06402 06403 This function locates the resource section in the kernel so it can be 06404 made readwrite if we bugcheck later, as the bugcheck code will write 06405 into it. 06406 06407 Arguments: 06408 06409 DataTableEntry - Supplies the kernel's data table entry. 06410 06411 Return Value: 06412 06413 None. 06414 06415 Environment: 06416 06417 Kernel mode, Phase 0 Initialization. 06418 06419 --*/ 06420 06421 { 06422 PVOID CurrentBase; 06423 PIMAGE_NT_HEADERS NtHeader; 06424 PIMAGE_SECTION_HEADER SectionTableEntry; 06425 LONG i; 06426 PMMPTE PointerPte; 06427 PVOID SectionBaseAddress; 06428 06429 CurrentBase = (PVOID)DataTableEntry->DllBase; 06430 06431 NtHeader = RtlImageNtHeader(CurrentBase); 06432 06433 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 06434 sizeof(ULONG) + 06435 sizeof(IMAGE_FILE_HEADER) + 06436 NtHeader->FileHeader.SizeOfOptionalHeader); 06437 06438 // 06439 // From the image header, locate the section named '.rsrc'. 06440 // 06441 06442 i = NtHeader->FileHeader.NumberOfSections; 06443 06444 PointerPte = NULL; 06445 06446 while (i > 0) { 06447 06448 SectionBaseAddress = SECTION_BASE_ADDRESS(SectionTableEntry); 06449 06450 #if defined (_X86_) 06451 if (*(PULONG)SectionTableEntry->Name == 'rsr.') { 06452 06453 MiKernelResourceStartPte = MiGetPteAddress ((ULONG_PTR)CurrentBase + 06454 SectionTableEntry->VirtualAddress); 06455 06456 MiKernelResourceEndPte = MiGetPteAddress (ROUND_TO_PAGES((ULONG_PTR)CurrentBase + 06457 SectionTableEntry->VirtualAddress + 06458 (NtHeader->OptionalHeader.SectionAlignment - 1) + 06459 SectionTableEntry->SizeOfRawData - 06460 PAGE_SIZE)); 06461 break; 06462 } 06463 #endif 06464 if (*(PULONG)SectionTableEntry->Name == 'LOOP') { 06465 if (*(PULONG)&SectionTableEntry->Name[4] == 'EDOC') { 06466 ExPoolCodeStart = (PVOID)((ULONG_PTR)CurrentBase + 06467 SectionTableEntry->VirtualAddress); 06468 ExPoolCodeEnd = (PVOID)((ULONG_PTR)CurrentBase + 06469 SectionTableEntry->VirtualAddress + 06470 SectionTableEntry->SizeOfRawData); 06471 } 06472 else if (*(PUSHORT)&SectionTableEntry->Name[4] == 'IM') { 06473 MmPoolCodeStart = (PVOID)((ULONG_PTR)CurrentBase + 06474 SectionTableEntry->VirtualAddress); 06475 MmPoolCodeEnd = (PVOID)((ULONG_PTR)CurrentBase + 06476 SectionTableEntry->VirtualAddress + 06477 SectionTableEntry->SizeOfRawData); 06478 } 06479 } 06480 else if ((*(PULONG)SectionTableEntry->Name == 'YSIM') && 06481 (*(PULONG)&SectionTableEntry->Name[4] == 'ETPS')) { 06482 MmPteCodeStart = (PVOID)((ULONG_PTR)CurrentBase + 06483 SectionTableEntry->VirtualAddress); 06484 MmPteCodeEnd = (PVOID)((ULONG_PTR)CurrentBase + 06485 SectionTableEntry->VirtualAddress + 06486 SectionTableEntry->SizeOfRawData); 06487 } 06488 06489 i -= 1; 06490 SectionTableEntry += 1; 06491 } 06492 } 06493 06494 VOID 06495 MmMakeKernelResourceSectionWritable ( 06496 VOID 06497 ) 06498 06499 /*++ 06500 06501 Routine Description: 06502 06503 This function makes the kernel's resource section readwrite so the bugcheck 06504 code can write into it. 06505 06506 Arguments: 06507 06508 None. 06509 06510 Return Value: 06511 06512 None. 06513 06514 Environment: 06515 06516 Kernel mode. Any IRQL. 06517 06518 --*/ 06519 06520 { 06521 #if defined (_X86_) 06522 MMPTE TempPte; 06523 MMPTE PteContents; 06524 PMMPTE PointerPte; 06525 06526 if (MiKernelResourceStartPte == NULL) { 06527 return; 06528 } 06529 06530 PointerPte = MiKernelResourceStartPte; 06531 06532 if (MI_IS_PHYSICAL_ADDRESS (MiGetVirtualAddressMappedByPte (PointerPte))) { 06533 06534 // 06535 // Mapped physically, doesn't need to be made readwrite. 06536 // 06537 06538 return; 06539 } 06540 06541 // 06542 // Since the entry state and IRQL are unknown, just go through the 06543 // PTEs without a lock and make them all readwrite. 06544 // 06545 06546 do { 06547 PteContents = *PointerPte; 06548 #if defined(NT_UP) 06549 if (PteContents.u.Hard.Write == 0) 06550 #else 06551 if (PteContents.u.Hard.Writable == 0) 06552 #endif 06553 { 06554 MI_MAKE_VALID_PTE (TempPte, 06555 PteContents.u.Hard.PageFrameNumber, 06556 MM_READWRITE, 06557 PointerPte); 06558 #if !defined(NT_UP) 06559 TempPte.u.Hard.Writable = 1; 06560 #endif 06561 MI_WRITE_VALID_PTE_NEW_PROTECTION (PointerPte, TempPte); 06562 } 06563 PointerPte += 1; 06564 } while (PointerPte <= MiKernelResourceEndPte); 06565 06566 // 06567 // Don't do this more than once. 06568 // 06569 06570 MiKernelResourceStartPte = NULL; 06571 06572 // 06573 // Only flush this processor as the state of the others is unknown. 06574 // 06575 06576 KeFlushCurrentTb (); 06577 #endif 06578 } 06579 06580 #ifdef i386 06581 PVOID PsNtosImageBase = (PVOID)0x80100000; 06582 #else 06583 PVOID PsNtosImageBase; 06584 #endif 06585 06586 LIST_ENTRY PsLoadedModuleList; 06587 ERESOURCE PsLoadedModuleResource; 06588 extern KSPIN_LOCK PsLoadedModuleSpinLock; 06589 06590 LOGICAL 06591 MiInitializeLoadedModuleList ( 06592 IN PLOADER_PARAMETER_BLOCK LoaderBlock 06593 ) 06594 06595 /*++ 06596 06597 Routine Description: 06598 06599 This function initializes the loaded module list based on the LoaderBlock. 06600 06601 Arguments: 06602 06603 LoaderBlock - Supplies a pointer to the system loader block. 06604 06605 Return Value: 06606 06607 None. 06608 06609 Environment: 06610 06611 Kernel mode, Phase 0 Initialization. 06612 06613 --*/ 06614 06615 { 06616 PLIST_ENTRY NextEntry; 06617 PLDR_DATA_TABLE_ENTRY DataTableEntry1; 06618 PLDR_DATA_TABLE_ENTRY DataTableEntry2; 06619 06620 // 06621 // Initialize the loaded module list executive resource and spin lock. 06622 // 06623 06624 ExInitializeResource (&PsLoadedModuleResource); 06625 KeInitializeSpinLock (&PsLoadedModuleSpinLock); 06626 06627 InitializeListHead (&PsLoadedModuleList); 06628 06629 // 06630 // Scan the loaded module list and allocate and initialize a data table 06631 // entry for each module. The data table entry is inserted in the loaded 06632 // module list and the initialization order list in the order specified 06633 // in the loader parameter block. The data table entry is inserted in the 06634 // memory order list in memory order. 06635 // 06636 06637 NextEntry = LoaderBlock->LoadOrderListHead.Flink; 06638 DataTableEntry2 = CONTAINING_RECORD(NextEntry, 06639 LDR_DATA_TABLE_ENTRY, 06640 InLoadOrderLinks); 06641 PsNtosImageBase = DataTableEntry2->DllBase; 06642 06643 MiLocateKernelSections (DataTableEntry2); 06644 06645 while (NextEntry != &LoaderBlock->LoadOrderListHead) { 06646 06647 DataTableEntry2 = CONTAINING_RECORD(NextEntry, 06648 LDR_DATA_TABLE_ENTRY, 06649 InLoadOrderLinks); 06650 06651 // 06652 // Allocate a data table entry. 06653 // 06654 06655 DataTableEntry1 = ExAllocatePoolWithTag (NonPagedPool, 06656 sizeof(LDR_DATA_TABLE_ENTRY), 06657 'dLmM'); 06658 06659 if (DataTableEntry1 == NULL) { 06660 return FALSE; 06661 } 06662 06663 // 06664 // Copy the data table entry. 06665 // 06666 06667 *DataTableEntry1 = *DataTableEntry2; 06668 06669 DataTableEntry1->FullDllName.Buffer = ExAllocatePoolWithTag (PagedPool, 06670 DataTableEntry2->FullDllName.MaximumLength + sizeof(UNICODE_NULL), 06671 'TDmM'); 06672 06673 if (DataTableEntry1->FullDllName.Buffer == NULL) { 06674 ExFreePool (DataTableEntry1); 06675 return FALSE; 06676 } 06677 06678 DataTableEntry1->BaseDllName.Buffer = ExAllocatePoolWithTag (NonPagedPool, 06679 DataTableEntry2->BaseDllName.MaximumLength + sizeof(UNICODE_NULL), 06680 'dLmM'); 06681 06682 if (DataTableEntry1->BaseDllName.Buffer == NULL) { 06683 ExFreePool (DataTableEntry1->FullDllName.Buffer); 06684 ExFreePool (DataTableEntry1); 06685 return FALSE; 06686 } 06687 06688 // 06689 // Copy the strings. 06690 // 06691 06692 RtlMoveMemory (DataTableEntry1->FullDllName.Buffer, 06693 DataTableEntry2->FullDllName.Buffer, 06694 DataTableEntry1->FullDllName.MaximumLength); 06695 06696 RtlMoveMemory (DataTableEntry1->BaseDllName.Buffer, 06697 DataTableEntry2->BaseDllName.Buffer, 06698 DataTableEntry1->BaseDllName.MaximumLength); 06699 06700 // 06701 // Insert the data table entry in the load order list in the order 06702 // they are specified. 06703 // 06704 06705 InsertTailList(&PsLoadedModuleList, 06706 &DataTableEntry1->InLoadOrderLinks); 06707 06708 NextEntry = NextEntry->Flink; 06709 } 06710 06711 MiBuildImportsForBootDrivers (); 06712 06713 return TRUE; 06714 } 06715 06716 NTSTATUS 06717 MmCallDllInitialize( 06718 IN PLDR_DATA_TABLE_ENTRY DataTableEntry 06719 ) 06720 06721 /*++ 06722 06723 Routine Description: 06724 06725 This function calls the DLL's initialize routine. 06726 06727 Arguments: 06728 06729 DataTableEntry - Supplies the kernel's data table entry. 06730 06731 Return Value: 06732 06733 Various NTSTATUS error codes. 06734 06735 Environment: 06736 06737 Kernel mode. 06738 06739 --*/ 06740 06741 { 06742 NTSTATUS st; 06743 PWCHAR Dot; 06744 PMM_DLL_INITIALIZE Func; 06745 UNICODE_STRING RegistryPath; 06746 UNICODE_STRING ImportName; 06747 06748 Func = MiLocateExportName (DataTableEntry->DllBase, "DllInitialize"); 06749 06750 if (!Func) { 06751 return STATUS_SUCCESS; 06752 } 06753 06754 ImportName.MaximumLength = DataTableEntry->BaseDllName.Length; 06755 ImportName.Buffer = ExAllocatePoolWithTag (NonPagedPool, 06756 ImportName.MaximumLength, 06757 'TDmM'); 06758 06759 if (ImportName.Buffer == NULL) { 06760 return STATUS_INSUFFICIENT_RESOURCES; 06761 } 06762 06763 ImportName.Length = DataTableEntry->BaseDllName.Length; 06764 RtlMoveMemory (ImportName.Buffer, 06765 DataTableEntry->BaseDllName.Buffer, 06766 ImportName.Length); 06767 06768 RegistryPath.MaximumLength = CmRegistryMachineSystemCurrentControlSetServices.Length + 06769 ImportName.Length + 06770 (USHORT)(2*sizeof(WCHAR)); 06771 06772 RegistryPath.Buffer = ExAllocatePoolWithTag (NonPagedPool, 06773 RegistryPath.MaximumLength, 06774 'TDmM'); 06775 06776 if (RegistryPath.Buffer == NULL) { 06777 ExFreePool (ImportName.Buffer); 06778 return STATUS_INSUFFICIENT_RESOURCES; 06779 } 06780 06781 RegistryPath.Length = CmRegistryMachineSystemCurrentControlSetServices.Length; 06782 RtlMoveMemory (RegistryPath.Buffer, 06783 CmRegistryMachineSystemCurrentControlSetServices.Buffer, 06784 CmRegistryMachineSystemCurrentControlSetServices.Length); 06785 06786 RtlAppendUnicodeToString (&RegistryPath, L"\\"); 06787 Dot = wcschr (ImportName.Buffer, L'.'); 06788 if (Dot) { 06789 ImportName.Length = (USHORT)((Dot - ImportName.Buffer) * sizeof(WCHAR)); 06790 } 06791 06792 RtlAppendUnicodeStringToString (&RegistryPath, &ImportName); 06793 ExFreePool (ImportName.Buffer); 06794 06795 // 06796 // Invoke the DLL's initialization routine. 06797 // 06798 06799 st = Func (&RegistryPath); 06800 06801 ExFreePool (RegistryPath.Buffer); 06802 06803 return st; 06804 } 06805 06806 NTKERNELAPI 06807 PVOID 06808 MmGetSystemRoutineAddress ( 06809 IN PUNICODE_STRING SystemRoutineName 06810 ) 06811 06812 /*++ 06813 06814 Routine Description: 06815 06816 This function returns the address of the argument function pointer if 06817 it is in the kernel or HAL, NULL if it is not. 06818 06819 Arguments: 06820 06821 SystemRoutineName - Supplies the name of the desired routine. 06822 06823 Return Value: 06824 06825 Non-NULL function pointer if successful. NULL if not. 06826 06827 Environment: 06828 06829 Kernel mode. 06830 06831 --*/ 06832 06833 { 06834 ULONG AnsiLength; 06835 NTSTATUS Status; 06836 PLDR_DATA_TABLE_ENTRY DataTableEntry; 06837 ANSI_STRING AnsiString; 06838 PLIST_ENTRY NextEntry; 06839 UNICODE_STRING KernelString; 06840 UNICODE_STRING HalString; 06841 PVOID FunctionAddress; 06842 LOGICAL Found; 06843 ULONG EntriesChecked; 06844 06845 ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); 06846 06847 EntriesChecked = 0; 06848 FunctionAddress = NULL; 06849 06850 RtlInitUnicodeString (&KernelString, L"ntoskrnl.exe"); 06851 RtlInitUnicodeString (&HalString, L"hal.dll"); 06852 06853 do { 06854 Status = RtlUnicodeStringToAnsiString( &AnsiString, 06855 SystemRoutineName, 06856 TRUE ); 06857 06858 if (NT_SUCCESS( Status)) { 06859 break; 06860 } 06861 06862 KeDelayExecutionThread (KernelMode, FALSE, &MmShortTime); 06863 06864 } while (TRUE); 06865 06866 // 06867 // Arbitrary process context so prevent suspend APCs now. 06868 // 06869 06870 KeEnterCriticalRegion(); 06871 ExAcquireResourceShared (&PsLoadedModuleResource, TRUE); 06872 06873 // 06874 // Check only the kernel and the HAL for exports. 06875 // 06876 06877 NextEntry = PsLoadedModuleList.Flink; 06878 while (NextEntry != &PsLoadedModuleList) { 06879 06880 Found = FALSE; 06881 06882 DataTableEntry = CONTAINING_RECORD(NextEntry, 06883 LDR_DATA_TABLE_ENTRY, 06884 InLoadOrderLinks); 06885 06886 if (RtlEqualUnicodeString (&KernelString, 06887 &DataTableEntry->BaseDllName, 06888 TRUE)) { 06889 06890 Found = TRUE; 06891 EntriesChecked += 1; 06892 06893 } 06894 else if (RtlEqualUnicodeString (&HalString, 06895 &DataTableEntry->BaseDllName, 06896 TRUE)) { 06897 06898 Found = TRUE; 06899 EntriesChecked += 1; 06900 } 06901 06902 if (Found == TRUE) { 06903 06904 FunctionAddress = MiFindExportedRoutineByName (DataTableEntry, 06905 &AnsiString); 06906 06907 if (FunctionAddress != NULL) { 06908 break; 06909 } 06910 06911 if (EntriesChecked == 2) { 06912 break; 06913 } 06914 } 06915 06916 NextEntry = NextEntry->Flink; 06917 } 06918 06919 ExReleaseResource (&PsLoadedModuleResource); 06920 KeLeaveCriticalRegion(); 06921 06922 RtlFreeAnsiString (&AnsiString); 06923 06924 return FunctionAddress; 06925 } 06926 06927 PVOID 06928 MiFindExportedRoutineByName( 06929 IN PLDR_DATA_TABLE_ENTRY DataTableEntry, 06930 IN PANSI_STRING AnsiImageRoutineName 06931 ) 06932 06933 /*++ 06934 06935 Routine Description: 06936 06937 This function snaps a thunk using the specified Export Section data. 06938 If the section data does not support the thunk, then the thunk is 06939 partially snapped (Dll field is still non-null, but snap address is 06940 set). 06941 06942 Arguments: 06943 06944 DllBase - Base of DLL being snapped to. 06945 06946 ImageBase - Base of image that contains the thunks to snap. 06947 06948 Thunk - On input, supplies the thunk to snap. When successfully 06949 snapped, the function field is set to point to the address in 06950 the DLL, and the DLL field is set to NULL. 06951 06952 ExportDirectory - Supplies the Export Section data from a DLL. 06953 06954 SnapForwarder - determine if the snap is for a forwarder, and therefore 06955 Address of Data is already setup. 06956 06957 Return Value: 06958 06959 06960 STATUS_SUCCESS or STATUS_DRIVER_ENTRYPOINT_NOT_FOUND or 06961 STATUS_DRIVER_ORDINAL_NOT_FOUND 06962 06963 --*/ 06964 06965 { 06966 PCHAR DllBase; 06967 USHORT OrdinalNumber; 06968 PULONG NameTableBase; 06969 PUSHORT NameOrdinalTableBase; 06970 PULONG Addr; 06971 ULONG High; 06972 ULONG Low; 06973 ULONG Middle; 06974 LONG Result; 06975 ULONG ExportSize; 06976 PVOID FunctionAddress; 06977 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 06978 06979 PAGED_CODE(); 06980 06981 DllBase = DataTableEntry->DllBase; 06982 06983 ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( 06984 DllBase, 06985 TRUE, 06986 IMAGE_DIRECTORY_ENTRY_EXPORT, 06987 &ExportSize 06988 ); 06989 06990 ASSERT (ExportDirectory != NULL); 06991 06992 // 06993 // Initialize the pointer to the array of RVA-based ansi export strings. 06994 // 06995 06996 NameTableBase = (PULONG)(DllBase + (ULONG)ExportDirectory->AddressOfNames); 06997 06998 // 06999 // Initialize the pointer to the array of USHORT ordinal numbers. 07000 // 07001 07002 NameOrdinalTableBase = (PUSHORT)(DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); 07003 07004 // 07005 // Lookup the desired name in the name table using a binary search. 07006 // 07007 07008 Low = 0; 07009 High = ExportDirectory->NumberOfNames - 1; 07010 07011 while (High >= Low) { 07012 07013 // 07014 // Compute the next probe index and compare the import name 07015 // with the export name entry. 07016 // 07017 07018 Middle = (Low + High) >> 1; 07019 07020 Result = strcmp(AnsiImageRoutineName->Buffer, 07021 (PCHAR)(DllBase + NameTableBase[Middle])); 07022 07023 if (Result < 0) { 07024 High = Middle - 1; 07025 } 07026 else if (Result > 0) { 07027 Low = Middle + 1; 07028 } 07029 else { 07030 break; 07031 } 07032 } 07033 07034 // 07035 // If the high index is less than the low index, then a matching 07036 // table entry was not found. Otherwise, get the ordinal number 07037 // from the ordinal table. 07038 // 07039 07040 if (High < Low) { 07041 return NULL; 07042 } 07043 07044 OrdinalNumber = NameOrdinalTableBase[Middle]; 07045 07046 // 07047 // If the OrdinalNumber is not within the Export Address Table, 07048 // then this image does not implement the function. Return not found. 07049 // 07050 07051 if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) { 07052 return NULL; 07053 } 07054 07055 // 07056 // Index into the array of RVA export addresses by ordinal number. 07057 // 07058 07059 Addr = (PULONG)(DllBase + (ULONG)ExportDirectory->AddressOfFunctions); 07060 07061 FunctionAddress = (PVOID)(DllBase + Addr[OrdinalNumber]); 07062 07063 // 07064 // Forwarders are not used by the kernel and HAL to each other. 07065 // 07066 07067 ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || 07068 (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize))); 07069 07070 return FunctionAddress; 07071 }

Generated on Sat May 15 19:41:56 2004 for test by doxygen 1.3.7