12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- psimag.c
- Abstract:
- This module implements the underlying support routines for the image
- library to be run in the kernel.
- Author:
- Evan Green 14-Oct-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/kernel/kdebug.h>
- #include "psp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define PROCESS_USER_MODULE_MAX_NAME 100
- #define PROCESS_USER_MODULE_MAX_COUNT 200
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores associations between images in two processes during
- a clone operation.
- Members:
- SourceImage - Stores a pointer to the loaded image the source process.
- DestinationImage - Stores a pointer to the loaded image in the destination
- process.
- --*/
- typedef struct _IMAGE_ASSOCIATION {
- PLOADED_IMAGE SourceImage;
- PLOADED_IMAGE DestinationImage;
- } IMAGE_ASSOCIATION, *PIMAGE_ASSOCIATION;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- PVOID
- PspImAllocateMemory (
- ULONG Size,
- ULONG Tag
- );
- VOID
- PspImFreeMemory (
- PVOID Allocation
- );
- KSTATUS
- PspImOpenFile (
- PVOID SystemContext,
- PSTR BinaryName,
- PIMAGE_FILE_INFORMATION File
- );
- VOID
- PspImCloseFile (
- PIMAGE_FILE_INFORMATION File
- );
- KSTATUS
- PspImLoadFile (
- PIMAGE_FILE_INFORMATION File,
- PIMAGE_BUFFER Buffer
- );
- KSTATUS
- PspImReadFile (
- PIMAGE_FILE_INFORMATION File,
- ULONGLONG Offset,
- UINTN Size,
- PIMAGE_BUFFER Buffer
- );
- VOID
- PspImUnloadBuffer (
- PIMAGE_FILE_INFORMATION File,
- PIMAGE_BUFFER Buffer
- );
- KSTATUS
- PspImAllocateAddressSpace (
- PLOADED_IMAGE Image
- );
- VOID
- PspImFreeAddressSpace (
- PLOADED_IMAGE Image
- );
- KSTATUS
- PspImMapImageSegment (
- HANDLE AddressSpaceHandle,
- PVOID AddressSpaceAllocation,
- PIMAGE_FILE_INFORMATION File,
- ULONGLONG FileOffset,
- PIMAGE_SEGMENT Segment,
- PIMAGE_SEGMENT PreviousSegment
- );
- VOID
- PspImUnmapImageSegment (
- HANDLE AddressSpaceHandle,
- PIMAGE_SEGMENT Segment
- );
- KSTATUS
- PspImNotifyImageLoad (
- PLOADED_IMAGE Image
- );
- VOID
- PspImNotifyImageUnload (
- PLOADED_IMAGE Image
- );
- VOID
- PspImInvalidateInstructionCacheRegion (
- PVOID Address,
- ULONG Size
- );
- PSTR
- PspImGetEnvironmentVariable (
- PSTR Variable
- );
- KSTATUS
- PspImFinalizeSegments (
- HANDLE AddressSpaceHandle,
- PIMAGE_SEGMENT Segments,
- UINTN SegmentCount
- );
- KSTATUS
- PspImCloneImage (
- PKPROCESS Source,
- PKPROCESS Destination,
- PLOADED_IMAGE SourceImage,
- PLOADED_IMAGE *NewDestinationImage
- );
- PLOADED_IMAGE
- PspImGetAssociatedImage (
- PLOADED_IMAGE QueryImage,
- PIMAGE_ASSOCIATION AssociationMapping,
- ULONG AssociationCount
- );
- KSTATUS
- PspLoadProcessImageIntoKernelDebugger (
- PKPROCESS Process,
- PLOADED_IMAGE Image
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Set this global to always load all user mode images into the kernel mode
- // debugger. Setting this is great for debugging as all usermode symbols are
- // always visible. It's not on by default however because it's wasteful (as
- // it costs lots of non-paged pool allocations) and adds buckets of symbols to
- // the debugger.
- //
- BOOL PsKdLoadAllImages = FALSE;
- //
- // Store a handle to the OS base library.
- //
- PIO_HANDLE PsOsBaseLibrary;
- //
- // Store the image library function table.
- //
- IM_IMPORT_TABLE PsImFunctionTable = {
- PspImAllocateMemory,
- PspImFreeMemory,
- PspImOpenFile,
- PspImCloseFile,
- PspImLoadFile,
- PspImReadFile,
- PspImUnloadBuffer,
- PspImAllocateAddressSpace,
- PspImFreeAddressSpace,
- PspImMapImageSegment,
- PspImUnmapImageSegment,
- PspImNotifyImageLoad,
- PspImNotifyImageUnload,
- PspImInvalidateInstructionCacheRegion,
- PspImGetEnvironmentVariable,
- PspImFinalizeSegments,
- NULL,
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- PspInitializeImageSupport (
- PVOID KernelLowestAddress,
- PLIST_ENTRY ListHead
- )
- /*++
- Routine Description:
- This routine initializes the image library for use in the kernel.
- Arguments:
- KernelLowestAddress - Supplies the lowest address of the kernel's image.
- This is used to avoid loading the kernel image in the debugger twice.
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE Image;
- IMAGE_BUFFER ImageBuffer;
- PKPROCESS KernelProcess;
- PLOADED_IMAGE NewImage;
- KSTATUS Status;
- RtlZeroMemory(&ImageBuffer, sizeof(IMAGE_BUFFER));
- Status = ImInitialize(&PsImFunctionTable);
- if (!KSUCCESS(Status)) {
- goto InitializeImageSupportEnd;
- }
- KernelProcess = PsGetKernelProcess();
- CurrentEntry = ListHead->Next;
- while (CurrentEntry != ListHead) {
- Image = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ImageBuffer.Data = Image->LoadedLowestAddress;
- ImageBuffer.Size = Image->Size;
- Status = ImAddImage(Image->BinaryName, &ImageBuffer, &NewImage);
- if (!KSUCCESS(Status)) {
- ASSERT(FALSE);
- goto InitializeImageSupportEnd;
- }
- NewImage->Flags = Image->Flags | IMAGE_FLAG_INITIALIZED |
- IMAGE_FLAG_RELOCATED | IMAGE_FLAG_IMPORTS_LOADED;
- NewImage->LoadFlags = Image->LoadFlags;
- NewImage->ImportDepth = Image->ImportDepth;
- NewImage->File.ModificationDate = Image->File.ModificationDate;
- NewImage->File.Size = Image->File.Size;
- NewImage->Size = Image->Size;
- INSERT_BEFORE(&(NewImage->ListEntry), &(KernelProcess->ImageListHead));
- KernelProcess->ImageCount += 1;
- KernelProcess->ImageListSignature +=
- NewImage->File.ModificationDate +
- (UINTN)(NewImage->LoadedLowestAddress);
- //
- // Load this image into the kernel debugger, but skip the kernel
- // image as that was already loaded.
- //
- if (NewImage->LoadedLowestAddress != KernelLowestAddress) {
- Status = PspLoadProcessImageIntoKernelDebugger(KernelProcess,
- NewImage);
- if (!KSUCCESS(Status)) {
- goto InitializeImageSupportEnd;
- }
- }
- }
- Status = STATUS_SUCCESS;
- InitializeImageSupportEnd:
- return Status;
- }
- KSTATUS
- PspImCloneProcessImages (
- PKPROCESS Source,
- PKPROCESS Destination
- )
- /*++
- Routine Description:
- This routine makes a copy of the given process' image list.
- Arguments:
- Source - Supplies a pointer to the source process.
- Destination - Supplies a pointer to the destination process.
- Return Value:
- Status code.
- --*/
- {
- PIMAGE_ASSOCIATION Association;
- ULONG AssociationIndex;
- PLIST_ENTRY CurrentEntry;
- ULONG ImageCount;
- ULONG ImportIndex;
- PLOADED_IMAGE NewImage;
- PLOADED_IMAGE SourceImage;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- PsAcquireImageListLock(Source);
- ImageCount = Source->ImageCount;
- //
- // Allocate space for the association mapping.
- //
- Association = MmAllocatePagedPool(sizeof(IMAGE_ASSOCIATION) * ImageCount,
- PS_ALLOCATION_TAG);
- if (Association == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ImCloneProcessImagesEnd;
- }
- //
- // Loop through copying images.
- //
- AssociationIndex = 0;
- CurrentEntry = Source->ImageListHead.Next;
- while (CurrentEntry != &(Source->ImageListHead)) {
- SourceImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ASSERT(AssociationIndex < ImageCount);
- //
- // Clone the image.
- //
- Status = PspImCloneImage(Source, Destination, SourceImage, &NewImage);
- if (!KSUCCESS(Status)) {
- goto ImCloneProcessImagesEnd;
- }
- //
- // Remember the association between source and destination image.
- //
- Association[AssociationIndex].SourceImage = SourceImage;
- Association[AssociationIndex].DestinationImage = NewImage;
- AssociationIndex += 1;
- }
- //
- // Now loop through the new process image list and restore all the import
- // relationships.
- //
- CurrentEntry = Source->ImageListHead.Next;
- while (CurrentEntry != &(Source->ImageListHead)) {
- NewImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (NewImage->ImportCount == 0) {
- continue;
- }
- //
- // Get the source image associated with this destination image.
- //
- SourceImage = PspImGetAssociatedImage(NewImage,
- Association,
- ImageCount);
- ASSERT(SourceImage != NULL);
- ASSERT(SourceImage->ImportCount == NewImage->ImportCount);
- //
- // Loop through and match up every import in the source with its
- // corresponding image in the destination.
- //
- for (ImportIndex = 0;
- ImportIndex < NewImage->ImportCount;
- ImportIndex += 1) {
- NewImage->Imports[ImportIndex] =
- PspImGetAssociatedImage(SourceImage->Imports[ImportIndex],
- Association,
- ImageCount);
- ASSERT(NewImage->Imports[ImportIndex] != NULL);
- }
- }
- Status = STATUS_SUCCESS;
- ImCloneProcessImagesEnd:
- PsReleaseImageListLock(Source);
- if (Association != NULL) {
- MmFreePagedPool(Association);
- }
- return Status;
- }
- VOID
- PspImUnloadAllImages (
- PKPROCESS Process
- )
- /*++
- Routine Description:
- This routine unloads all images in the given process.
- Arguments:
- Process - Supplies a pointer to the process whose images should be unloaded.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE Image;
- //
- // Unload all images. Be careful traversing this list as it will shift
- // as images and their imports are unloaded.
- //
- PsAcquireImageListLock(Process);
- while (LIST_EMPTY(&(Process->ImageListHead)) == FALSE) {
- CurrentEntry = Process->ImageListHead.Next;
- while (CurrentEntry != &(Process->ImageListHead)) {
- Image = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- if (Image->ImportDepth == 0) {
- //
- // Mark the image as having unload called on it, and then
- // unload the image.
- //
- Image->ImportDepth = -1;
- ImImageReleaseReference(Image);
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // If the image list is not empty but no images were found with a
- // depth of zero, then a reference counting problem has occurred.
- // Decrementing the reference count on all images with a depth
- // of zero should cause a domino effect that unloads all images.
- //
- ASSERT(CurrentEntry != &(Process->ImageListHead));
- }
- PsReleaseImageListLock(Process);
- return;
- }
- KSTATUS
- PspProcessUserModeModuleChange (
- PPROCESS_DEBUG_MODULE_CHANGE ModuleChangeUser
- )
- /*++
- Routine Description:
- This routine handles module change notifications from user mode.
- Arguments:
- ModuleChangeUser - Supplies the module change notification from user mode.
- Return Value:
- None.
- --*/
- {
- UINTN AllocationSize;
- PROCESS_DEBUG_MODULE_CHANGE Change;
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE CurrentImage;
- PLOADED_IMAGE ExistingImage;
- LOADED_IMAGE Image;
- BOOL LockHeld;
- PLOADED_IMAGE NewImage;
- PKPROCESS Process;
- KSTATUS Status;
- LockHeld = FALSE;
- NewImage = NULL;
- Process = PsGetCurrentProcess();
- Status = MmCopyFromUserMode(&Change,
- ModuleChangeUser,
- sizeof(PROCESS_DEBUG_MODULE_CHANGE));
- if (!KSUCCESS(Status)) {
- goto ProcessUserModeModuleChangeEnd;
- }
- if (Change.Version < PROCESS_DEBUG_MODULE_CHANGE_VERSION) {
- Status = STATUS_NOT_SUPPORTED;
- goto ProcessUserModeModuleChangeEnd;
- }
- Status = MmCopyFromUserMode(&Image, Change.Image, sizeof(LOADED_IMAGE));
- if (!KSUCCESS(Status)) {
- goto ProcessUserModeModuleChangeEnd;
- }
- if (Image.Format != ImageElf32) {
- ASSERT(FALSE);
- Status = STATUS_INVALID_PARAMETER;
- goto ProcessUserModeModuleChangeEnd;
- }
- //
- // Try to find a module matching this base address.
- //
- PsAcquireImageListLock(Process);
- LockHeld = TRUE;
- CurrentEntry = Process->ImageListHead.Next;
- ExistingImage = NULL;
- while (CurrentEntry != &(Process->ImageListHead)) {
- CurrentImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (CurrentImage->LoadedLowestAddress == Image.LoadedLowestAddress) {
- ExistingImage = CurrentImage;
- break;
- }
- }
- //
- // Handle an unload.
- //
- if (Change.Load == FALSE) {
- if (ExistingImage == NULL) {
- Status = STATUS_NOT_FOUND;
- goto ProcessUserModeModuleChangeEnd;
- }
- if ((ExistingImage->LoadFlags & IMAGE_LOAD_FLAG_PLACEHOLDER) == 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto ProcessUserModeModuleChangeEnd;
- }
- PspImNotifyImageUnload(ExistingImage);
- LIST_REMOVE(&(ExistingImage->ListEntry));
- PspImFreeMemory(ExistingImage);
- Status = STATUS_SUCCESS;
- goto ProcessUserModeModuleChangeEnd;
- }
- //
- // This is a load. Handle shenanigans.
- //
- if (ExistingImage != NULL) {
- Status = STATUS_RESOURCE_IN_USE;
- goto ProcessUserModeModuleChangeEnd;
- }
- if (Process->ImageCount >= PROCESS_USER_MODULE_MAX_COUNT) {
- Status = STATUS_TOO_MANY_HANDLES;
- goto ProcessUserModeModuleChangeEnd;
- }
- if (Change.BinaryNameSize > PROCESS_USER_MODULE_MAX_NAME) {
- Status = STATUS_NAME_TOO_LONG;
- goto ProcessUserModeModuleChangeEnd;
- }
- if (Change.BinaryNameSize == 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto ProcessUserModeModuleChangeEnd;
- }
- //
- // Create a faked up image.
- //
- AllocationSize = sizeof(LOADED_IMAGE) + Change.BinaryNameSize;
- NewImage = PspImAllocateMemory(AllocationSize, PS_IMAGE_ALLOCATION_TAG);
- if (NewImage == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ProcessUserModeModuleChangeEnd;
- }
- RtlZeroMemory(NewImage, sizeof(LOADED_IMAGE));
- NewImage->BinaryName = (PSTR)(NewImage + 1);
- Status = MmCopyFromUserMode(NewImage->BinaryName,
- Image.BinaryName,
- Change.BinaryNameSize);
- if (!KSUCCESS(Status)) {
- goto ProcessUserModeModuleChangeEnd;
- }
- NewImage->BinaryName[Change.BinaryNameSize - 1] = '\0';
- NewImage->File.Handle = INVALID_HANDLE;
- NewImage->AllocatorHandle = INVALID_HANDLE;
- NewImage->Format = Image.Format;
- NewImage->Machine = Image.Machine;
- NewImage->Size = Image.Size;
- NewImage->DeclaredBase = Image.DeclaredBase;
- NewImage->PreferredLowestAddress = Image.PreferredLowestAddress;
- NewImage->LoadedLowestAddress = Image.LoadedLowestAddress;
- NewImage->EntryPoint = Image.EntryPoint;
- NewImage->ReferenceCount = 1;
- NewImage->LoadFlags = IMAGE_LOAD_FLAG_PLACEHOLDER;
- INSERT_BEFORE(&(NewImage->ListEntry), &(Process->ImageListHead));
- Status = PspImNotifyImageLoad(NewImage);
- if (!KSUCCESS(Status)) {
- LIST_REMOVE(&(NewImage->ListEntry));
- goto ProcessUserModeModuleChangeEnd;
- }
- Status = STATUS_SUCCESS;
- ProcessUserModeModuleChangeEnd:
- if (LockHeld != FALSE) {
- PsReleaseImageListLock(Process);
- }
- if (!KSUCCESS(Status)) {
- if (NewImage != NULL) {
- PspImFreeMemory(NewImage);
- }
- }
- return Status;
- }
- KSTATUS
- PspLoadProcessImagesIntoKernelDebugger (
- PKPROCESS Process
- )
- /*++
- Routine Description:
- This routine loads the images in the given process into the kernel debugger.
- Arguments:
- Process - Supplies a pointer to the process.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE Image;
- KSTATUS Status;
- KSTATUS TotalStatus;
- ASSERT((KeGetRunLevel() == RunLevelLow) &&
- (Process != PsGetKernelProcess()));
- PsAcquireImageListLock(Process);
- TotalStatus = STATUS_SUCCESS;
- CurrentEntry = Process->ImageListHead.Next;
- while (CurrentEntry != &(Process->ImageListHead)) {
- Image = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- Status = PspLoadProcessImageIntoKernelDebugger(Process, Image);
- if (!KSUCCESS(Status)) {
- TotalStatus = Status;
- }
- }
- PsReleaseImageListLock(Process);
- return TotalStatus;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- PVOID
- PspImAllocateMemory (
- ULONG Size,
- ULONG Tag
- )
- /*++
- Routine Description:
- This routine allocates memory from the kernel for the image library.
- Arguments:
- Size - Supplies the number of bytes required for the memory allocation.
- Tag - Supplies a 32-bit ASCII identifier used to tag the memroy allocation.
- Return Value:
- Returns a pointer to the memory allocation on success.
- NULL on failure.
- --*/
- {
- return MmAllocatePagedPool(Size, Tag);
- }
- VOID
- PspImFreeMemory (
- PVOID Allocation
- )
- /*++
- Routine Description:
- This routine frees memory to the kernel allocated by the image library.
- Arguments:
- Allocation - Supplies a pointer the allocation to free.
- Return Value:
- None.
- --*/
- {
- MmFreePagedPool(Allocation);
- return;
- }
- KSTATUS
- PspImOpenFile (
- PVOID SystemContext,
- PSTR BinaryName,
- PIMAGE_FILE_INFORMATION File
- )
- /*++
- Routine Description:
- This routine opens a file.
- Arguments:
- SystemContext - Supplies the context pointer passed to the load executable
- function.
- BinaryName - Supplies the name of the executable image to open.
- File - Supplies a pointer where the information for the file including its
- open handle will be returned.
- Return Value:
- Status code.
- --*/
- {
- FILE_PROPERTIES FileProperties;
- BOOL FromKernelMode;
- ULONGLONG LocalFileSize;
- ULONG NameLength;
- PIO_HANDLE OutputHandle;
- PKPROCESS Process;
- KSTATUS Status;
- OutputHandle = INVALID_HANDLE;
- Process = (PKPROCESS)SystemContext;
- NameLength = RtlStringLength(BinaryName) + 1;
- //
- // If this is for the kernel process, then a driver is being loaded.
- // Always use the path directly as the kernel processes current working
- // directory should aways be the drivers directory on the system partition.
- //
- if (Process == PsGetKernelProcess()) {
- if (Process != PsGetCurrentProcess()) {
- FromKernelMode = FALSE;
- } else {
- FromKernelMode = TRUE;
- }
- Status = IoOpen(FromKernelMode,
- NULL,
- BinaryName,
- NameLength,
- IO_ACCESS_READ | IO_ACCESS_EXECUTE,
- 0,
- FILE_PERMISSION_NONE,
- &OutputHandle);
- goto ImOpenFileEnd;
- } else {
- //
- // If this is the first image being opened in a user mode app, then
- // it's always the OS base library.
- //
- if (Process->ImageCount == 0) {
- ASSERT(RtlAreStringsEqual(BinaryName,
- OS_BASE_LIBRARY,
- NameLength) != FALSE);
- IoIoHandleAddReference(PsOsBaseLibrary);
- OutputHandle = PsOsBaseLibrary;
- Status = STATUS_SUCCESS;
- } else {
- Status = IoOpen(FALSE,
- NULL,
- BinaryName,
- NameLength,
- IO_ACCESS_READ | IO_ACCESS_EXECUTE,
- 0,
- FILE_PERMISSION_NONE,
- &OutputHandle);
- if (KSUCCESS(Status)) {
- goto ImOpenFileEnd;
- }
- }
- }
- ImOpenFileEnd:
- if (KSUCCESS(Status)) {
- Status = IoGetFileInformation(OutputHandle, &FileProperties);
- if (KSUCCESS(Status)) {
- READ_INT64_SYNC(&(FileProperties.FileSize), &LocalFileSize);
- File->Size = LocalFileSize;
- File->ModificationDate = FileProperties.ModifiedTime.Seconds;
- }
- } else {
- OutputHandle = INVALID_HANDLE;
- }
- File->Handle = OutputHandle;
- return Status;
- }
- VOID
- PspImCloseFile (
- PIMAGE_FILE_INFORMATION File
- )
- /*++
- Routine Description:
- This routine closes an open file, invalidating any memory mappings to it.
- Arguments:
- File - Supplies a pointer to the file information.
- Return Value:
- None.
- --*/
- {
- if (File->Handle == INVALID_HANDLE) {
- return;
- }
- IoClose(File->Handle);
- return;
- }
- KSTATUS
- PspImLoadFile (
- PIMAGE_FILE_INFORMATION File,
- PIMAGE_BUFFER Buffer
- )
- /*++
- Routine Description:
- This routine loads an entire file into memory so the image library can
- access it.
- Arguments:
- File - Supplies a pointer to the file information.
- Buffer - Supplies a pointer where the buffer will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AlignedSize;
- UINTN PageSize;
- KSTATUS Status;
- VM_ALLOCATION_PARAMETERS VaRequest;
- PageSize = MmPageSize();
- AlignedSize = ALIGN_RANGE_UP(File->Size, PageSize);
- if (AlignedSize > MAX_UINTN) {
- return STATUS_NOT_SUPPORTED;;
- }
- VaRequest.Address = NULL;
- VaRequest.Size = AlignedSize;
- VaRequest.Alignment = PageSize;
- VaRequest.Min = 0;
- VaRequest.Max = MAX_ADDRESS;
- VaRequest.MemoryType = MemoryTypeReserved;
- VaRequest.Strategy = AllocationStrategyAnyAddress;
- Status = MmMapFileSection(File->Handle,
- 0,
- &VaRequest,
- IMAGE_SECTION_READABLE | IMAGE_SECTION_WRITABLE,
- TRUE,
- NULL);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Buffer->Data = VaRequest.Address;
- Buffer->Size = File->Size;
- return STATUS_SUCCESS;
- }
- KSTATUS
- PspImReadFile (
- PIMAGE_FILE_INFORMATION File,
- ULONGLONG Offset,
- UINTN Size,
- PIMAGE_BUFFER Buffer
- )
- /*++
- Routine Description:
- This routine reads a portion of the given file into a buffer, allocated by
- this function.
- Arguments:
- File - Supplies a pointer to the file information.
- Offset - Supplies the file offset to read from in bytes.
- Size - Supplies the size to read, in bytes.
- Buffer - Supplies a pointer where the buffer will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- UINTN AlignedSize;
- UINTN BytesComplete;
- PIO_BUFFER IoBuffer;
- UINTN PageSize;
- KSTATUS Status;
- PageSize = MmPageSize();
- AlignedSize = ALIGN_RANGE_UP(Size, PageSize);
- IoBuffer = MmAllocateUninitializedIoBuffer(AlignedSize, 0);
- if (IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ImReadFileEnd;
- }
- Status = IoReadAtOffset(File->Handle,
- IoBuffer,
- Offset,
- AlignedSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesComplete,
- NULL);
- if (Status == STATUS_END_OF_FILE) {
- Status = STATUS_SUCCESS;
- } else if (!KSUCCESS(Status)) {
- goto ImReadFileEnd;
- }
- Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, TRUE);
- if (!KSUCCESS(Status)) {
- goto ImReadFileEnd;
- }
- Buffer->Context = IoBuffer;
- Buffer->Data = IoBuffer->Fragment[0].VirtualAddress;
- Buffer->Size = BytesComplete;
- Status = STATUS_SUCCESS;
- ImReadFileEnd:
- if (!KSUCCESS(Status)) {
- if (IoBuffer != NULL) {
- MmFreeIoBuffer(IoBuffer);
- IoBuffer = NULL;
- }
- }
- return Status;
- }
- VOID
- PspImUnloadBuffer (
- PIMAGE_FILE_INFORMATION File,
- PIMAGE_BUFFER Buffer
- )
- /*++
- Routine Description:
- This routine unloads a file buffer created from either the load file or
- read file function, and frees the buffer.
- Arguments:
- File - Supplies a pointer to the file information.
- Buffer - Supplies the buffer returned by the load file function.
- Return Value:
- None.
- --*/
- {
- ULONGLONG AlignedSize;
- UINTN PageSize;
- KSTATUS Status;
- ASSERT(Buffer->Data != NULL);
- if (Buffer->Context != NULL) {
- MmFreeIoBuffer(Buffer->Context);
- } else {
- PageSize = MmPageSize();
- AlignedSize = ALIGN_RANGE_UP(File->Size, PageSize);
- Status = MmUnmapFileSection(NULL, Buffer->Data, AlignedSize, NULL);
- ASSERT(KSUCCESS(Status));
- }
- Buffer->Data = NULL;
- Buffer->Context = NULL;
- return;
- }
- KSTATUS
- PspImAllocateAddressSpace (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine allocates a section of virtual address space that an image
- can be mapped in to.
- Arguments:
- Image - Supplies a pointer to the image being loaded. The system context,
- size, file information, load flags, and preferred virtual address will
- be initialized. This routine should set up the loaded image buffer,
- loaded lowest address, and allocator handle if needed.
- Return Value:
- Status code.
- --*/
- {
- PVOID Address;
- PVOID AlignedPreferredAddress;
- BOOL KernelMode;
- PVOID Max;
- UINTN PageOffset;
- UINTN PageSize;
- PKPROCESS Process;
- PMEMORY_RESERVATION Reservation;
- KSTATUS Status;
- ALLOCATION_STRATEGY Strategy;
- PageSize = MmPageSize();
- Process = (PKPROCESS)(Image->SystemContext);
- Address = NULL;
- AlignedPreferredAddress = NULL;
- if (Process == PsGetKernelProcess()) {
- KernelMode = TRUE;
- Max = MAX_ADDRESS;
- Strategy = AllocationStrategyAnyAddress;
- } else {
- KernelMode = FALSE;
- Max = Process->AddressSpace->MaxMemoryMap;
- Strategy = AllocationStrategyHighestAddress;
- if ((Image->LoadFlags & IMAGE_LOAD_FLAG_PRIMARY_EXECUTABLE) != 0) {
- Strategy = AllocationStrategyAnyAddress;
- Address = Image->PreferredLowestAddress;
- AlignedPreferredAddress =
- (PVOID)(UINTN)ALIGN_RANGE_DOWN((UINTN)Address, PageSize);
- }
- }
- //
- // Align the preferred address down to a page.
- //
- PageOffset = (UINTN)Address - (UINTN)AlignedPreferredAddress;
- Reservation = MmCreateMemoryReservation(AlignedPreferredAddress,
- Image->Size + PageOffset,
- 0,
- Max,
- Strategy,
- KernelMode);
- if (Reservation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AllocateAddressSpaceEnd;
- }
- //
- // Upon success, return the virtual address, accessible address, and return
- // the reservation as the handle. Since images are set up the process they
- // run in, the accessible VA is the same as the final VA.
- //
- Address = Reservation->VirtualBase + PageOffset;
- Image->LoadedLowestAddress = Address;
- Image->LoadedImageBuffer = Address;
- Image->AllocatorHandle = (HANDLE)Reservation;
- Status = STATUS_SUCCESS;
- AllocateAddressSpaceEnd:
- if (!KSUCCESS(Status)) {
- if (Reservation != NULL) {
- MmFreeMemoryReservation(Reservation);
- }
- }
- return Status;
- }
- VOID
- PspImFreeAddressSpace (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine frees a section of virtual address space that was previously
- allocated.
- Arguments:
- Image - Supplies a pointer to the loaded (or partially loaded) image.
- Return Value:
- None.
- --*/
- {
- PMEMORY_RESERVATION Reservation;
- Reservation = (PMEMORY_RESERVATION)(Image->AllocatorHandle);
- if ((Reservation != NULL) && (Reservation != INVALID_HANDLE)) {
- MmFreeMemoryReservation(Reservation);
- }
- return;
- }
- KSTATUS
- PspImMapImageSegment (
- HANDLE AddressSpaceHandle,
- PVOID AddressSpaceAllocation,
- PIMAGE_FILE_INFORMATION File,
- ULONGLONG FileOffset,
- PIMAGE_SEGMENT Segment,
- PIMAGE_SEGMENT PreviousSegment
- )
- /*++
- Routine Description:
- This routine maps a section of the image to the given virtual address.
- Arguments:
- AddressSpaceHandle - Supplies the handle used to claim the overall region
- of address space.
- AddressSpaceAllocation - Supplies the original lowest virtual address for
- this image.
- File - Supplies an optional pointer to the file being mapped. If this
- parameter is NULL, then a zeroed memory section is being mapped.
- FileOffset - Supplies the offset from the beginning of the file to the
- beginning of the mapping, in bytes.
- Segment - Supplies a pointer to the segment information to map. On output,
- the virtual address will contain the actual mapped address, and the
- mapping handle may be set.
- PreviousSegment - Supplies an optional pointer to the previous segment
- that was mapped, so this routine can handle overlap appropriately. This
- routine can assume that segments are always mapped in increasing order.
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesCompleted;
- PIO_HANDLE FileHandle;
- PVOID FileRegion;
- UINTN FileRegionSize;
- UINTN FileSize;
- IO_BUFFER IoBuffer;
- ULONG IoBufferFlags;
- UINTN IoSize;
- BOOL KernelMode;
- PKPROCESS KernelProcess;
- ULONG MapFlags;
- UINTN MemorySize;
- UINTN NextPage;
- UINTN PageMask;
- UINTN PageOffset;
- UINTN PageSize;
- UINTN PreviousEnd;
- PKPROCESS Process;
- UINTN RegionEnd;
- UINTN RegionSize;
- PMEMORY_RESERVATION Reservation;
- UINTN SegmentAddress;
- KSTATUS Status;
- VM_ALLOCATION_PARAMETERS VaRequest;
- ASSERT((PreviousSegment == NULL) ||
- (Segment->VirtualAddress > PreviousSegment->VirtualAddress));
- FileRegion = NULL;
- FileRegionSize = 0;
- FileHandle = NULL;
- IoBufferFlags = 0;
- if (File != NULL) {
- FileHandle = File->Handle;
- }
- FileSize = Segment->FileSize;
- MemorySize = Segment->MemorySize;
- ASSERT((FileSize == Segment->FileSize) &&
- (MemorySize == Segment->MemorySize));
- Reservation = AddressSpaceHandle;
- KernelMode = FALSE;
- KernelProcess = PsGetKernelProcess();
- MapFlags = SYS_MAP_FLAG_READ;
- if ((Segment->Flags & IMAGE_MAP_FLAG_WRITE) != 0) {
- MapFlags |= SYS_MAP_FLAG_WRITE;
- }
- //
- // Map everything writable for now, it will get fixed up during
- // finalization.
- //
- MapFlags = IMAGE_SECTION_READABLE | IMAGE_SECTION_WRITABLE;
- if ((Segment->Flags & IMAGE_MAP_FLAG_EXECUTE) != 0) {
- MapFlags |= IMAGE_SECTION_EXECUTABLE;
- }
- VaRequest.Alignment = 0;
- VaRequest.Min = 0;
- VaRequest.MemoryType = MemoryTypeReserved;
- VaRequest.Strategy = AllocationStrategyFixedAddress;
- Process = Reservation->Process;
- if (Process == KernelProcess) {
- KernelMode = TRUE;
- MapFlags |= IMAGE_SECTION_NON_PAGED;
- IoBufferFlags |= IO_BUFFER_FLAG_KERNEL_MODE_DATA;
- VaRequest.Max = MAX_ADDRESS;
- } else {
- VaRequest.Max = Process->AddressSpace->MaxMemoryMap;
- }
- //
- // Handle the first part, which may overlap with the previous segment.
- //
- PageSize = MmPageSize();
- PageMask = PageSize - 1;
- SegmentAddress = (UINTN)(Segment->VirtualAddress);
- if (PreviousSegment != NULL) {
- PreviousEnd = (UINTN)(PreviousSegment->VirtualAddress) +
- PreviousSegment->MemorySize;
- RegionEnd = ALIGN_RANGE_UP(PreviousEnd, PageSize);
- if (RegionEnd > SegmentAddress) {
- //
- // Fail if this region is executable but the previous one was not,
- // as the kernel can't go make a portion of the previous section
- // executable. One potential workaround would be to make the entire
- // previous section executable. So far this is not needed.
- //
- if (((Segment->Flags & IMAGE_MAP_FLAG_EXECUTE) != 0) &&
- ((PreviousSegment->Flags & IMAGE_MAP_FLAG_EXECUTE) == 0)) {
- RtlDebugPrint("Error: Executable image section at 0x%x "
- "overlaps with non-executable section at "
- "0x%x.\n",
- Segment->VirtualAddress,
- PreviousSegment->VirtualAddress);
- Status = STATUS_MEMORY_CONFLICT;
- goto MapImageSegmentEnd;
- }
- //
- // Compute the portion of this section that needs to be read or
- // zeroed into it.
- //
- if (SegmentAddress + MemorySize < RegionEnd) {
- RegionEnd = SegmentAddress + MemorySize;
- }
- RegionSize = RegionEnd - SegmentAddress;
- IoSize = FileSize;
- if (IoSize > RegionSize) {
- IoSize = RegionSize;
- }
- Status = MmInitializeIoBuffer(&IoBuffer,
- (PVOID)SegmentAddress,
- INVALID_PHYSICAL_ADDRESS,
- IoSize,
- IoBufferFlags);
- if (!KSUCCESS(Status)) {
- goto MapImageSegmentEnd;
- }
- Status = IoReadAtOffset(FileHandle,
- &IoBuffer,
- FileOffset,
- IoSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto MapImageSegmentEnd;
- }
- if (BytesCompleted != IoSize) {
- Status = STATUS_END_OF_FILE;
- goto MapImageSegmentEnd;
- }
- if (IoSize < RegionSize) {
- RtlZeroMemory((PVOID)SegmentAddress + IoSize,
- RegionSize - IoSize);
- }
- if (((Segment->Flags | PreviousSegment->Flags) &
- IMAGE_MAP_FLAG_EXECUTE) != 0) {
- Status = MmSyncCacheRegion((PVOID)SegmentAddress, RegionSize);
- ASSERT(KSUCCESS(Status));
- }
- FileOffset += IoSize;
- FileSize -= IoSize;
- MemorySize -= RegionSize;
- SegmentAddress = RegionEnd;
- }
- }
- //
- // This is the main portion. If the file offset and address have the same
- // page alignment, then it can be mapped directly. Otherwise, it must be
- // read in.
- //
- if (FileSize != 0) {
- PageOffset = FileOffset & PageMask;
- FileRegion = (PVOID)(SegmentAddress - PageOffset);
- FileRegionSize = ALIGN_RANGE_UP(FileSize + PageOffset, PageSize);
- VaRequest.Address = FileRegion;
- VaRequest.Size = FileRegionSize;
- //
- // Try to memory map the file directly.
- //
- if (PageOffset == (SegmentAddress & PageMask)) {
- Status = MmMapFileSection(FileHandle,
- FileOffset - PageOffset,
- &VaRequest,
- MapFlags,
- KernelMode,
- Reservation);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to map %x bytes at %x: %x\n",
- FileRegionSize,
- FileRegion,
- Status);
- FileRegionSize = 0;
- goto MapImageSegmentEnd;
- }
- IoSize = 0;
- //
- // The file offsets don't agree. Allocate a region for reading.
- //
- } else {
- Status = MmMapFileSection(INVALID_HANDLE,
- 0,
- &VaRequest,
- MapFlags,
- KernelMode,
- Reservation);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to map %x bytes at %x: %x\n",
- FileRegionSize,
- FileRegion,
- Status);
- FileRegionSize = 0;
- goto MapImageSegmentEnd;
- }
- IoSize = FileSize;
- }
- Segment->MappingStart = FileRegion;
- ASSERT((UINTN)FileRegion == SegmentAddress - PageOffset);
- //
- // Read from the file if the file wasn't mapped directly.
- //
- if (IoSize != 0) {
- Status = MmInitializeIoBuffer(&IoBuffer,
- (PVOID)SegmentAddress,
- INVALID_PHYSICAL_ADDRESS,
- IoSize,
- IoBufferFlags);
- if (!KSUCCESS(Status)) {
- goto MapImageSegmentEnd;
- }
- Status = IoReadAtOffset(FileHandle,
- &IoBuffer,
- FileOffset,
- IoSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto MapImageSegmentEnd;
- }
- if (BytesCompleted != IoSize) {
- Status = STATUS_END_OF_FILE;
- goto MapImageSegmentEnd;
- }
- if ((Segment->Flags & IMAGE_MAP_FLAG_EXECUTE) != 0) {
- Status = MmSyncCacheRegion((PVOID)SegmentAddress, IoSize);
- ASSERT(KSUCCESS(Status));
- }
- }
- SegmentAddress += FileSize;
- MemorySize -= FileSize;
- //
- // Zero out any region between the end of the file portion and the next
- // page.
- //
- NextPage = ALIGN_RANGE_UP(SegmentAddress, PageSize);
- if (NextPage - SegmentAddress != 0) {
- RtlZeroMemory((PVOID)SegmentAddress, NextPage - SegmentAddress);
- if ((Segment->Flags & IMAGE_MAP_FLAG_EXECUTE) != 0) {
- Status = MmSyncCacheRegion((PVOID)SegmentAddress,
- NextPage - SegmentAddress);
- ASSERT(KSUCCESS(Status));
- }
- }
- if (NextPage >= SegmentAddress + MemorySize) {
- Status = STATUS_SUCCESS;
- goto MapImageSegmentEnd;
- }
- MemorySize -= NextPage - SegmentAddress;
- SegmentAddress = NextPage;
- }
- //
- // Memory map the remaining region, which is not backed by the image.
- //
- PageOffset = SegmentAddress & PageMask;
- VaRequest.Address = (PVOID)(SegmentAddress - PageOffset);
- VaRequest.Size = ALIGN_RANGE_UP(MemorySize + PageOffset, PageSize);
- Status = MmMapFileSection(INVALID_HANDLE,
- 0,
- &VaRequest,
- MapFlags,
- KernelMode,
- Reservation);
- if (!KSUCCESS(Status)) {
- ASSERT(FALSE);
- goto MapImageSegmentEnd;
- }
- //
- // If this is a kernel mode segment, then the anonymous non-paged section
- // just created will have been backed by fresh pages but not initialized to
- // zero.
- //
- if (KernelMode != FALSE) {
- RtlZeroMemory(VaRequest.Address, VaRequest.Size);
- }
- if (Segment->MappingStart == NULL) {
- Segment->MappingStart = VaRequest.Address;
- }
- MapImageSegmentEnd:
- if (!KSUCCESS(Status)) {
- if (FileRegionSize != 0) {
- MmUnmapFileSection(Reservation->Process,
- FileRegion,
- FileRegionSize,
- Reservation);
- }
- }
- return Status;
- }
- VOID
- PspImUnmapImageSegment (
- HANDLE AddressSpaceHandle,
- PIMAGE_SEGMENT Segment
- )
- /*++
- Routine Description:
- This routine maps unmaps an image segment.
- Arguments:
- AddressSpaceHandle - Supplies the handle used to claim the overall region
- of address space.
- Segment - Supplies a pointer to the segment information to unmap.
- Return Value:
- None.
- --*/
- {
- UINTN End;
- UINTN PageSize;
- PMEMORY_RESERVATION Reservation;
- UINTN SectionBegin;
- KSTATUS Status;
- PageSize = MmPageSize();
- Reservation = AddressSpaceHandle;
- if (AddressSpaceHandle == INVALID_HANDLE) {
- Reservation = NULL;
- }
- if (Segment->MappingStart == NULL) {
- return;
- }
- SectionBegin = (UINTN)(Segment->MappingStart);
- End = (UINTN)(Segment->VirtualAddress) + Segment->MemorySize;
- End = ALIGN_RANGE_UP((UINTN)End, PageSize);
- Status = MmUnmapFileSection(NULL,
- (PVOID)SectionBegin,
- End - SectionBegin,
- Reservation);
- ASSERT(KSUCCESS(Status));
- return;
- }
- KSTATUS
- PspImNotifyImageLoad (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine notifies the primary consumer of the image library that an
- image has been loaded.
- Arguments:
- Image - Supplies the image that has just been loaded. This image should
- be subsequently returned to the image library upon requests for loaded
- images with the given name.
- Return Value:
- Status code. Failing status codes veto the image load.
- --*/
- {
- PKPROCESS KernelProcess;
- PKPROCESS Process;
- PMEMORY_RESERVATION Reservation;
- KSTATUS Status;
- if (Image->AllocatorHandle == INVALID_HANDLE) {
- Process = PsGetCurrentProcess();
- } else {
- Reservation = (PMEMORY_RESERVATION)(Image->AllocatorHandle);
- Process = Reservation->Process;
- }
- KernelProcess = PsGetKernelProcess();
- ASSERT((KeIsQueuedLockHeld(Process->QueuedLock) != FALSE) ||
- (Process == KernelProcess));
- Process->ImageCount += 1;
- Process->ImageListSignature += Image->File.ModificationDate +
- (UINTN)(Image->LoadedLowestAddress);
- //
- // If the debug flag is enabled, then make the kernel debugger aware of
- // this user mode module.
- //
- if ((PsKdLoadAllImages != FALSE) ||
- (Image->SystemContext == KernelProcess)) {
- PspLoadProcessImageIntoKernelDebugger(Process, Image);
- }
- //
- // Let I/O do some initialization if this is a driver.
- //
- if (Image->SystemContext == KernelProcess) {
- if (Image->TlsSize != 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto ImNotifyImageLoadEnd;
- }
- Status = IoCreateDriverStructure(Image);
- if (!KSUCCESS(Status)) {
- goto ImNotifyImageLoadEnd;
- }
- }
- Status = STATUS_SUCCESS;
- ImNotifyImageLoadEnd:
- return Status;
- }
- VOID
- PspImNotifyImageUnload (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine notifies the primary consumer of the image library that an
- image is about to be unloaded from memory. Once this routine returns, the
- image should not be referenced again as it will be freed.
- Arguments:
- Image - Supplies the image that is about to be unloaded.
- Return Value:
- None.
- --*/
- {
- PKPROCESS KernelProcess;
- PKPROCESS Process;
- KernelProcess = PsGetKernelProcess();
- Process = Image->SystemContext;
- if (Process == NULL) {
- Process = PsGetCurrentProcess();
- }
- ASSERT((KeIsQueuedLockHeld(Process->QueuedLock) != FALSE) ||
- (Process == KernelProcess));
- ASSERT(Process->ImageCount != 0);
- Process->ImageCount -= 1;
- Process->ImageListSignature -= Image->File.ModificationDate +
- (UINTN)(Image->LoadedLowestAddress);
- if (Image->DebuggerModule != NULL) {
- KdReportModuleChange(Image->DebuggerModule, FALSE);
- MmFreeNonPagedPool(Image->DebuggerModule);
- Image->DebuggerModule = NULL;
- }
- //
- // Let I/O destroy its structures if this is a driver.
- //
- if (Image->SystemContext == KernelProcess) {
- IoDestroyDriverStructure(Image);
- }
- return;
- }
- VOID
- PspImInvalidateInstructionCacheRegion (
- PVOID Address,
- ULONG Size
- )
- /*++
- Routine Description:
- This routine invalidates an instruction cache region after code has been
- modified.
- Arguments:
- Address - Supplies the virtual address of the revion to invalidate.
- Size - Supplies the number of bytes to invalidate.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- Status = MmSyncCacheRegion(Address, Size);
- ASSERT(KSUCCESS(Status));
- return;
- }
- PSTR
- PspImGetEnvironmentVariable (
- PSTR Variable
- )
- /*++
- Routine Description:
- This routine gets an environment variable value for the image library.
- Arguments:
- Variable - Supplies a pointer to a null terminated string containing the
- name of the variable to get.
- Return Value:
- Returns a pointer to the value of the environment variable. The image
- library will not free or modify this value.
- NULL if the given environment variable is not set.
- --*/
- {
- BOOL Match;
- PKPROCESS Process;
- UINTN VariableLength;
- //
- // User mode gets no help.
- //
- Process = PsGetCurrentProcess();
- if (Process != PsGetKernelProcess()) {
- return NULL;
- }
- VariableLength = RtlStringLength(Variable);
- Match = RtlAreStringsEqual(Variable,
- IMAGE_DYNAMIC_LIBRARY_PATH_VARIABLE,
- VariableLength + 1);
- if (Match != FALSE) {
- //
- // Return a separator, which will append an empty prefix.
- //
- return ":";
- }
- return NULL;
- }
- KSTATUS
- PspImFinalizeSegments (
- HANDLE AddressSpaceHandle,
- PIMAGE_SEGMENT Segments,
- UINTN SegmentCount
- )
- /*++
- Routine Description:
- This routine applies the final memory protection attributes to the given
- segments. Read and execute bits can be applied at the time of mapping, but
- write protection may be applied here.
- Arguments:
- AddressSpaceHandle - Supplies the handle used to claim the overall region
- of address space.
- Segments - Supplies the final array of segments.
- SegmentCount - Supplies the number of segments.
- Return Value:
- Status code.
- --*/
- {
- UINTN End;
- ULONG MapFlags;
- UINTN PageSize;
- PIMAGE_SEGMENT Segment;
- UINTN SegmentIndex;
- UINTN Size;
- KSTATUS Status;
- PageSize = MmPageSize();
- for (SegmentIndex = 0; SegmentIndex < SegmentCount; SegmentIndex += 1) {
- Segment = &(Segments[SegmentIndex]);
- if (Segment->Type == ImageSegmentInvalid) {
- continue;
- }
- //
- // If the segment has no protection features, then there's nothing to
- // tighten up.
- //
- if ((Segment->Flags & IMAGE_MAP_FLAG_WRITE) != 0) {
- continue;
- }
- //
- // If the image was so small it fit entirely in some other segment's
- // remainder, skip it.
- //
- if (Segment->MappingStart == NULL) {
- continue;
- }
- //
- // Compute the region whose protection should actually be changed.
- //
- End = (UINTN)(Segment->VirtualAddress) + Segment->MemorySize;
- End = ALIGN_RANGE_UP(End, PageSize);
- //
- // If the region has a real size, changed its protection to read-only.
- //
- if ((PVOID)End > Segment->MappingStart) {
- Size = End - (UINTN)(Segment->MappingStart);
- MapFlags = IMAGE_SECTION_READABLE;
- if ((Segment->Flags & IMAGE_MAP_FLAG_EXECUTE) != 0) {
- MapFlags |= IMAGE_SECTION_EXECUTABLE;
- }
- Status = MmChangeImageSectionRegionAccess(Segment->MappingStart,
- Size,
- MapFlags);
- if (!KSUCCESS(Status)) {
- goto FinalizeSegmentsEnd;
- }
- }
- }
- Status = STATUS_SUCCESS;
- FinalizeSegmentsEnd:
- return Status;
- }
- KSTATUS
- PspImCloneImage (
- PKPROCESS Source,
- PKPROCESS Destination,
- PLOADED_IMAGE SourceImage,
- PLOADED_IMAGE *NewDestinationImage
- )
- /*++
- Routine Description:
- This routine makes a copy of the given process' image. This routine creates
- the imports array but every entry is null, and needs to be filled in later.
- Arguments:
- Source - Supplies a pointer to the source process.
- Destination - Supplies a pointer to the destination process.
- SourceImage - Supplies a pointer to the image to copy.
- NewDestinationImage - Supplies a pointer where a pointer to the newly
- created destination image will be returned.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- ULONG NameSize;
- PLOADED_IMAGE NewImage;
- KSTATUS Status;
- //
- // Allocate a new image.
- //
- NameSize = RtlStringLength(SourceImage->BinaryName) + 1;
- AllocationSize = sizeof(LOADED_IMAGE) + NameSize;
- NewImage = PspImAllocateMemory(AllocationSize, PS_ALLOCATION_TAG);
- if (NewImage == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ImCloneImageEnd;
- }
- //
- // Initialize the new image.
- //
- ASSERT(SourceImage->BinaryName == (PSTR)(SourceImage + 1));
- RtlCopyMemory(NewImage, SourceImage, AllocationSize);
- NewImage->BinaryName = (PSTR)(NewImage + 1);
- NewImage->ListEntry.Next = NULL;
- NewImage->ListEntry.Previous = NULL;
- if (NewImage->File.Handle != INVALID_HANDLE) {
- IoIoHandleAddReference(NewImage->File.Handle);
- }
- NewImage->SystemContext = Destination;
- NewImage->AllocatorHandle = INVALID_HANDLE;
- NewImage->Segments = NULL;
- NewImage->Imports = NULL;
- NewImage->DebuggerModule = NULL;
- NewImage->StaticFunctions = NULL;
- NewImage->ImageContext = NULL;
- //
- // Create the image segments.
- //
- if (NewImage->SegmentCount != 0) {
- AllocationSize = sizeof(IMAGE_SEGMENT) * NewImage->SegmentCount;
- NewImage->Segments = PspImAllocateMemory(AllocationSize,
- PS_ALLOCATION_TAG);
- if (NewImage->Segments == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ImCloneImageEnd;
- }
- RtlCopyMemory(NewImage->Segments,
- SourceImage->Segments,
- AllocationSize);
- }
- //
- // Allocate space for the imports array. Unfortunately it cannot be
- // populated yet because it may point to images that have not yet been
- // cloned.
- //
- if (SourceImage->ImportCount != 0) {
- AllocationSize = SourceImage->ImportCount * sizeof(PLOADED_IMAGE);
- NewImage->Imports = PspImAllocateMemory(AllocationSize,
- PS_ALLOCATION_TAG);
- if (NewImage->Imports == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ImCloneImageEnd;
- }
- RtlZeroMemory(NewImage->Imports, AllocationSize);
- }
- INSERT_BEFORE(&(NewImage->ListEntry), &(Destination->ImageListHead));
- Destination->ImageCount += 1;
- if (PsKdLoadAllImages != FALSE) {
- PspLoadProcessImageIntoKernelDebugger(Destination, NewImage);
- }
- Destination->ImageListSignature += NewImage->File.ModificationDate +
- (UINTN)(NewImage->LoadedLowestAddress);
- Status = STATUS_SUCCESS;
- ImCloneImageEnd:
- if (!KSUCCESS(Status)) {
- if (NewImage != NULL) {
- if (NewImage->Imports != NULL) {
- PspImFreeMemory(NewImage->Imports);
- }
- if (NewImage->Segments != NULL) {
- PspImFreeMemory(NewImage->Segments);
- }
- PspImFreeMemory(NewImage);
- NewImage = NULL;
- }
- }
- *NewDestinationImage = NewImage;
- return Status;
- }
- PLOADED_IMAGE
- PspImGetAssociatedImage (
- PLOADED_IMAGE QueryImage,
- PIMAGE_ASSOCIATION AssociationMapping,
- ULONG AssociationCount
- )
- /*++
- Routine Description:
- This routine searches through the given association mapping looking for
- an image that maps to the query.
- Arguments:
- QueryImage - Supplies a pointer to the image whose associated image is
- requested.
- AssociationMapping - Supplies a pointer to the association mapping array.
- AssociationCount - Supplies the number of elements in the association array.
- Return Value:
- Returns a pointer to the image associated with the query image on success.
- NULL if no mapping could be found.
- --*/
- {
- ULONG AssociationIndex;
- for (AssociationIndex = 0;
- AssociationIndex < AssociationCount;
- AssociationIndex += 1) {
- if (AssociationMapping[AssociationIndex].SourceImage == QueryImage) {
- return AssociationMapping[AssociationIndex].DestinationImage;
- }
- if (AssociationMapping[AssociationIndex].DestinationImage ==
- QueryImage) {
- return AssociationMapping[AssociationIndex].SourceImage;
- }
- }
- return NULL;
- }
- KSTATUS
- PspLoadProcessImageIntoKernelDebugger (
- PKPROCESS Process,
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine loads the given image into the kernel debugger. This routine
- assumes the process image list lock is already held.
- Arguments:
- Process - Supplies a pointer to the process.
- Image - Supplies a pointer to the image to load into the kernel debugger.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- UINTN BaseDifference;
- PDEBUG_MODULE DebuggerModule;
- ULONG NameSize;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // If the image is already loaded, skip it.
- //
- if (Image->DebuggerModule != NULL) {
- return STATUS_SUCCESS;
- }
- //
- // If for some odd reason the image doesn't have a name, skip it.
- //
- if (Image->BinaryName == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- //
- // Allocate and initialize the debugger module structure.
- //
- NameSize = ((RtlStringLength(Image->BinaryName) + 1) * sizeof(CHAR));
- AllocationSize = sizeof(DEBUG_MODULE) + NameSize -
- (sizeof(CHAR) * ANYSIZE_ARRAY);
- DebuggerModule = MmAllocateNonPagedPool(AllocationSize,
- PS_DEBUG_ALLOCATION_TAG);
- if (DebuggerModule == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(DebuggerModule, AllocationSize);
- DebuggerModule->StructureSize = AllocationSize;
- DebuggerModule->Timestamp = Image->File.ModificationDate;
- BaseDifference = (UINTN)Image->LoadedLowestAddress -
- (UINTN)Image->PreferredLowestAddress;
- DebuggerModule->BaseAddress = Image->DeclaredBase + BaseDifference;
- DebuggerModule->LowestAddress = Image->LoadedLowestAddress;
- DebuggerModule->EntryPoint = Image->EntryPoint;
- DebuggerModule->Size = Image->Size;
- DebuggerModule->Process = Process->Identifiers.ProcessId;
- RtlStringCopy(DebuggerModule->BinaryName, Image->BinaryName, NameSize);
- //
- // Save the pointer and make the debugger aware of this new module.
- //
- Image->DebuggerModule = DebuggerModule;
- KdReportModuleChange(DebuggerModule, TRUE);
- return STATUS_SUCCESS;
- }
|