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

creasect.c File Reference

#include "mi.h"

Go to the source code of this file.

Classes

struct  _PHARLAP_CONFIG

Defines

#define MM_SIZE_OF_LARGEST_IMAGE   ((ULONG)0x77000000)
#define MM_MAXIMUM_IMAGE_HEADER   (2 * PAGE_SIZE)
#define MM_ALLOCATION_FRAGMENT   (64 * 1024)
#define MM_MAXIMUM_IMAGE_SECTIONS
#define INIT_IMAGE_INFORMATION(OptHdr)
#define VALIDATE_NTHEADER(Hdr)

Typedefs

typedef _PHARLAP_CONFIG CONFIGPHARLAP
typedef _PHARLAP_CONFIGPCONFIGPHARLAP

Functions

CCHAR MiGetImageProtection (IN ULONG SectionCharacteristics)
NTSTATUS MiVerifyImageHeader (IN PIMAGE_NT_HEADERS NtHeader, IN PIMAGE_DOS_HEADER DosHeader, IN ULONG NtHeaderSize)
BOOLEAN MiCheckDosCalls (IN PIMAGE_OS2_HEADER Os2Header, IN ULONG HeaderSize)
PCONTROL_AREA MiFindImageSectionObject (IN PFILE_OBJECT File, IN PBOOLEAN GlobalNeeded)
VOID MiInsertImageSectionObject (IN PFILE_OBJECT File, IN PCONTROL_AREA ControlArea)
VOID MiFlushDataSection (IN PFILE_OBJECT File)
NTSTATUS NtCreateSection (OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL)
NTSTATUS MmCreateSection (OUT PVOID *SectionObject, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER InputMaximumSize, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL, IN PFILE_OBJECT FileObject OPTIONAL)
NTSTATUS MiCreateImageFileMap (IN PFILE_OBJECT File, OUT PSEGMENT *Segment)
NTSTATUS MiCreateDataFileMap (IN PFILE_OBJECT File, OUT PSEGMENT *Segment, IN PUINT64 MaximumSize, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN ULONG IgnoreFileSizing)
NTSTATUS MiCreatePagingFileMap (OUT PSEGMENT *Segment, IN PUINT64 MaximumSize, IN ULONG ProtectionMask, IN ULONG AllocationAttributes)
NTSTATUS NtOpenSection (OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
PFN_NUMBER MiGetPageForHeader (VOID)
VOID MiUpdateImageHeaderPage (IN PMMPTE PointerPte, IN PFN_NUMBER PageFrameNumber, IN PCONTROL_AREA ControlArea)
VOID MiRemoveImageHeaderPage (IN PFN_NUMBER PageFrameNumber)
PCONTROL_AREA MiFindImageSectionObject (IN PFILE_OBJECT File, OUT PBOOLEAN GlobalNeeded)
VOID MiRemoveImageSectionObject (IN PFILE_OBJECT File, IN PCONTROL_AREA InputControlArea)
NTSTATUS MiGetWritablePagesInSection (IN PSECTION Section, OUT PULONG WritablePages)

Variables

ULONG MMCONTROL = 'aCmM'
ULONG MMTEMPORARY = 'xxmM'
ULONG MMSECT = 'tSmM'
POBJECT_TYPE IoFileObjectType
CCHAR MmImageProtectionArray [16]


Define Documentation

#define INIT_IMAGE_INFORMATION OptHdr   ) 
 

Value:

{ \ NewSegment->ImageInformation->TransferAddress = \ (PVOID)((ULONG_PTR)((OptHdr).ImageBase) + \ (OptHdr).AddressOfEntryPoint); \ NewSegment->ImageInformation->MaximumStackSize = \ (OptHdr).SizeOfStackReserve; \ NewSegment->ImageInformation->CommittedStackSize = \ (OptHdr).SizeOfStackCommit; \ NewSegment->ImageInformation->SubSystemType = \ (OptHdr).Subsystem; \ NewSegment->ImageInformation->SubSystemMajorVersion = (USHORT)((OptHdr).MajorSubsystemVersion); \ NewSegment->ImageInformation->SubSystemMinorVersion = (USHORT)((OptHdr).MinorSubsystemVersion); \ NewSegment->ImageInformation->DllCharacteristics = \ (OptHdr).DllCharacteristics; \ NewSegment->ImageInformation->ImageContainsCode = \ (BOOLEAN)(((OptHdr).SizeOfCode != 0) || \ ((OptHdr).AddressOfEntryPoint != 0)); \ }

Referenced by MiCreateImageFileMap().

#define MM_ALLOCATION_FRAGMENT   (64 * 1024)
 

Definition at line 33 of file creasect.c.

Referenced by MiCreateDataFileMap().

#define MM_MAXIMUM_IMAGE_HEADER   (2 * PAGE_SIZE)
 

Definition at line 31 of file creasect.c.

Referenced by MiCreateImageFileMap().

#define MM_MAXIMUM_IMAGE_SECTIONS
 

Value:

((MM_MAXIMUM_IMAGE_HEADER - (PAGE_SIZE + sizeof(IMAGE_NT_HEADERS))) / \ sizeof(IMAGE_SECTION_HEADER))

Definition at line 41 of file creasect.c.

#define MM_SIZE_OF_LARGEST_IMAGE   ((ULONG)0x77000000)
 

Definition at line 29 of file creasect.c.

#define VALIDATE_NTHEADER Hdr   ) 
 

Value:

{ \ /* File alignment must be multiple of 512 and power of 2. */ \ if (((((Hdr)->OptionalHeader).FileAlignment & 511) != 0) && \ (((Hdr)->OptionalHeader).FileAlignment != \ ((Hdr)->OptionalHeader).SectionAlignment)) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ \ if (((Hdr)->OptionalHeader).FileAlignment == 0) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ \ if (((((Hdr)->OptionalHeader).FileAlignment - 1) & \ ((Hdr)->OptionalHeader).FileAlignment) != 0) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ \ if (((Hdr)->OptionalHeader).SectionAlignment < ((Hdr)->OptionalHeader).FileAlignment) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ \ if (((Hdr)->OptionalHeader).SizeOfImage > MM_SIZE_OF_LARGEST_IMAGE) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ \ if ((Hdr)->FileHeader.NumberOfSections > MM_MAXIMUM_IMAGE_SECTIONS) { \ return STATUS_INVALID_IMAGE_FORMAT; \ } \ }

Referenced by MiVerifyImageHeader().


Typedef Documentation

typedef struct _PHARLAP_CONFIG CONFIGPHARLAP
 

typedef struct _PHARLAP_CONFIG * PCONFIGPHARLAP
 

Referenced by MiVerifyImageHeader().


Function Documentation

BOOLEAN MiCheckDosCalls IN PIMAGE_OS2_HEADER  Os2Header,
IN ULONG  HeaderSize
 

Definition at line 3159 of file creasect.c.

References EXCEPTION_EXECUTE_HANDLER, FALSE, PAGED_CODE, PUSHORT, TRUE, and USHORT.

Referenced by MiVerifyImageHeader().

03166 : 03167 03168 03169 Arguments: 03170 03171 Return Value: 03172 03173 Returns the status value. 03174 03175 --*/ 03176 03177 { 03178 PUCHAR ImportTable; 03179 UCHAR EntrySize; 03180 USHORT ModuleCount; 03181 USHORT ModuleSize; 03182 USHORT i; 03183 PUSHORT ModuleTable; 03184 03185 PAGED_CODE(); 03186 03187 // 03188 // If there are no modules to check return immediately. 03189 // 03190 03191 ModuleCount = Os2Header->ne_cmod; 03192 03193 if (ModuleCount == 0) { 03194 return FALSE; 03195 } 03196 03197 // 03198 // exe headers are notorious for having junk values for offsets 03199 // in the import table and module table. We guard against this 03200 // via careful checking plus our exception handler. 03201 // 03202 03203 try { 03204 03205 // 03206 // Find out where the Module ref table is. Mod table has two byte 03207 // for each entry in import table. These two bytes tell the offset 03208 // in the import table for that entry. 03209 // 03210 03211 ModuleTable = (PUSHORT)((PCHAR)Os2Header + (ULONG)Os2Header->ne_modtab); 03212 03213 // 03214 // Make sure that the module table fits within the passed-in header. 03215 // Note that each module table entry is 2 bytes long. 03216 // 03217 03218 if (((ULONG)Os2Header->ne_modtab + (ModuleCount * 2)) > HeaderSize) { 03219 return FALSE; 03220 } 03221 03222 // 03223 // Now search individual entries for DOSCALLs. 03224 // 03225 03226 for (i = 0; i < ModuleCount; i += 1) { 03227 03228 ModuleSize = *((UNALIGNED USHORT *)ModuleTable); 03229 03230 // 03231 // Import table has count byte followed by the string where count 03232 // is the string length. 03233 // 03234 03235 ImportTable = (PUCHAR)((PCHAR)Os2Header + 03236 (ULONG)Os2Header->ne_imptab + (ULONG)ModuleSize); 03237 03238 // 03239 // Make sure the offset is within the valid range. 03240 // 03241 03242 if (((ULONG)Os2Header->ne_imptab + (ULONG)ModuleSize) 03243 >= HeaderSize) { 03244 return FALSE; 03245 } 03246 03247 EntrySize = *ImportTable++; 03248 03249 // 03250 // 0 is a bad size, bail out. 03251 // 03252 03253 if (EntrySize == 0) { 03254 return FALSE; 03255 } 03256 03257 // 03258 // Make sure the offset is within the valid range. 03259 // The sizeof(UCHAR) is included in the check because ImportTable 03260 // was incremented above and is used in the RtlEqualMemory 03261 // comparison below. 03262 // 03263 03264 if (((ULONG)Os2Header->ne_imptab + (ULONG)ModuleSize + 03265 (ULONG)EntrySize + sizeof(UCHAR)) > HeaderSize) { 03266 return FALSE; 03267 } 03268 03269 // 03270 // If size matches compare DOSCALLS. 03271 // 03272 03273 if (EntrySize == 8) { 03274 if (RtlEqualMemory (ImportTable, "DOSCALLS", 8) ) { 03275 return TRUE; 03276 } 03277 } 03278 03279 // 03280 // Move on to the next module table entry. Each entry is 2 bytes. 03281 // 03282 03283 ModuleTable = (PUSHORT)((PCHAR)ModuleTable + 2); 03284 } 03285 } except (EXCEPTION_EXECUTE_HANDLER) { 03286 return FALSE; 03287 } 03288 03289 return FALSE; 03290 }

NTSTATUS MiCreateDataFileMap IN PFILE_OBJECT  File,
OUT PSEGMENT Segment,
IN PUINT64  MaximumSize,
IN ULONG  SectionPageProtection,
IN ULONG  AllocationAttributes,
IN ULONG  IgnoreFileSizing
 

Definition at line 3553 of file creasect.c.

References ASSERT, _SUBSECTION::ControlArea, EX_REAL_POOL_USAGE, ExAllocatePoolWithTag, ExFreePool(), FALSE, File, _CONTROL_AREA::FilePointer, FsRtlGetFileSize(), FsRtlSetFileSize(), Mi4KStartForSubsection, MI_MAXIMUM_SECTION_SIZE, MiFillMemoryPte, MiGetSubsectionAddressForPte, MM4K_MASK, MM4K_SHIFT, MM_ALLOCATION_FRAGMENT, MM_EXECUTE_READWRITE, MM_PROTO_PTE_ALIGNMENT, MMPTE, MMSECT, _SUBSECTION::NextSubsection, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, _SUBSECTION::NumberOfFullSectors, _CONTROL_AREA::NumberOfSectionReferences, _CONTROL_AREA::NumberOfSubsections, _CONTROL_AREA::NumberOfUserReferences, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, PagedPool, _CONTROL_AREA::PagedPoolUsage, PTE_SHIFT, _SUBSECTION::PtesInSubsection, ROUND_TO_PAGES, _CONTROL_AREA::Segment, SEGMENT, Size, Status, SUBSECTION, _SUBSECTION::SubsectionBase, TRUE, _CONTROL_AREA::u, _MMPTE::u, _SUBSECTION::u, _SUBSECTION::UnusedPtes, USHORT, and X64K.

Referenced by MmCreateSection().

03564 : 03565 03566 This function creates the necessary structures to allow the mapping 03567 of a data file. 03568 03569 The data file is accessed to verify desired access, a segment 03570 object is created and initialized. 03571 03572 Arguments: 03573 03574 File - Supplies the file object for the image file. 03575 03576 Segment - Returns the segment object. 03577 03578 FileHandle - Supplies the handle to the image file. 03579 03580 MaximumSize - Supplies the maximum size for the mapping. 03581 03582 SectionPageProtection - Supplies the initial page protection. 03583 03584 AllocationAttributes - Supplies the allocation attributes for the 03585 mapping. 03586 03587 Return Value: 03588 03589 Returns the status value. 03590 03591 TBS 03592 03593 03594 --*/ 03595 03596 { 03597 03598 NTSTATUS Status; 03599 ULONG NumberOfPtes; 03600 ULONG SizeOfSegment; 03601 ULONG j; 03602 ULONG Size; 03603 ULONG PartialSize; 03604 ULONG First; 03605 PCONTROL_AREA ControlArea; 03606 PSEGMENT NewSegment; 03607 PSUBSECTION Subsection; 03608 PSUBSECTION ExtendedSubsection; 03609 PMMPTE PointerPte; 03610 MMPTE TempPte; 03611 ULONG NumberOfPtesWithAlignment; 03612 UINT64 EndOfFile; 03613 UINT64 LastFileChunk; 03614 UINT64 FileOffset; 03615 UINT64 NumberOfPtesForEntireFile; 03616 ULONG ExtendedSubsections; 03617 PSUBSECTION FirstSubsection; 03618 PSUBSECTION Last; 03619 ULONG NumberOfNewSubsections; 03620 03621 PAGED_CODE(); 03622 03623 ExtendedSubsections = 0; 03624 FirstSubsection = NULL; 03625 NumberOfNewSubsections = 0; 03626 03627 // ************************************************************* 03628 // Create mapped file section. 03629 // ************************************************************* 03630 03631 if (!IgnoreFileSizing) { 03632 03633 Status = FsRtlGetFileSize (File, (PLARGE_INTEGER)&EndOfFile); 03634 03635 if (Status == STATUS_FILE_IS_A_DIRECTORY) { 03636 03637 // 03638 // Can't map a directory as a section. Return error. 03639 // 03640 03641 return STATUS_INVALID_FILE_FOR_SECTION; 03642 } 03643 03644 if (!NT_SUCCESS (Status)) { 03645 return Status; 03646 } 03647 03648 if (EndOfFile == 0 && *MaximumSize == 0) { 03649 03650 // 03651 // Can't map a zero length without specifying the maximum 03652 // size as non-zero. 03653 // 03654 03655 return STATUS_MAPPED_FILE_SIZE_ZERO; 03656 } 03657 03658 // 03659 // Make sure this file is big enough for the section. 03660 // 03661 03662 if (*MaximumSize > EndOfFile) { 03663 03664 // 03665 // If the maximum size is greater than the end-of-file, 03666 // and the user did not request page_write or page_execute_readwrite 03667 // to the section, reject the request. 03668 // 03669 03670 if (((SectionPageProtection & PAGE_READWRITE) | 03671 (SectionPageProtection & PAGE_EXECUTE_READWRITE)) == 0) { 03672 03673 return STATUS_SECTION_TOO_BIG; 03674 } 03675 03676 // 03677 // Check to make sure that the allocation size large enough 03678 // to contain all the data, if not set a new allocation size. 03679 // 03680 03681 EndOfFile = *MaximumSize; 03682 03683 Status = FsRtlSetFileSize (File, (PLARGE_INTEGER)&EndOfFile); 03684 03685 if (!NT_SUCCESS (Status)) { 03686 return Status; 03687 } 03688 } 03689 } else { 03690 03691 // 03692 // Ignore the file size, this call is from the cache manager. 03693 // 03694 03695 EndOfFile = *MaximumSize; 03696 } 03697 03698 // 03699 // Calculate the number of prototype PTEs to build for this section. 03700 // 03701 03702 // 03703 // Each subsection is limited to 16TB - 64K because the NumberOfFullSectors 03704 // and various other fields in the subsection are ULONGs. For NT64, the 03705 // allocation could be split into multiple subsections as needed to 03706 // conform to this limit - this is not worth doing for NT32 unless 03707 // sparse prototype PTE allocations are supported. 03708 // 03709 // This must be a multiple of the size of prototype pte allocation so any 03710 // given prototype pte allocation will have the same subsection for all 03711 // PTEs. 03712 // 03713 // The total section size is limited to 16PB - 4K because of the 03714 // StartingSector4132 field in each subsection. 03715 // 03716 03717 NumberOfPtesForEntireFile = (EndOfFile + PAGE_SIZE - 1) >> PAGE_SHIFT; 03718 03719 NumberOfPtes = (ULONG)NumberOfPtesForEntireFile; 03720 03721 if (EndOfFile > MI_MAXIMUM_SECTION_SIZE) { 03722 return STATUS_SECTION_TOO_BIG; 03723 } 03724 03725 if (NumberOfPtesForEntireFile > (UINT64)((MAXULONG_PTR / sizeof(MMPTE)) - sizeof (SEGMENT))) { 03726 return STATUS_SECTION_TOO_BIG; 03727 } 03728 03729 if (NumberOfPtesForEntireFile > EndOfFile) { 03730 return STATUS_SECTION_TOO_BIG; 03731 } 03732 03733 // 03734 // Calculate the number of PTEs to allocate to maintain the 03735 // desired alignment. On x86 and R3000 no additional PTEs are 03736 // needed; on MIPS, the desired alignment is 64k to avoid cache 03737 // problems. 03738 // 03739 03740 NumberOfPtesWithAlignment = (NumberOfPtes + 03741 ((MM_PROTO_PTE_ALIGNMENT >> PAGE_SHIFT) - 1)) & 03742 (~((MM_PROTO_PTE_ALIGNMENT >> PAGE_SHIFT) - 1)); 03743 03744 if (NumberOfPtesWithAlignment < NumberOfPtes) { 03745 return STATUS_SECTION_TOO_BIG; 03746 } 03747 03748 SizeOfSegment = sizeof(SEGMENT) + sizeof(MMPTE) * 03749 (NumberOfPtesWithAlignment - 1); 03750 03751 NewSegment = ExAllocatePoolWithTag (PagedPool, 03752 SizeOfSegment, 03753 MMSECT); 03754 if (NewSegment == NULL) { 03755 03756 // 03757 // The requested pool could not be allocated. 03758 // Try to allocate the memory in smaller sizes. 03759 // 03760 03761 if (SizeOfSegment < MM_ALLOCATION_FRAGMENT) { 03762 return STATUS_INSUFFICIENT_RESOURCES; 03763 } 03764 03765 Size = MM_ALLOCATION_FRAGMENT; 03766 PartialSize = SizeOfSegment; 03767 03768 do { 03769 03770 if (PartialSize < MM_ALLOCATION_FRAGMENT) { 03771 PartialSize = (ULONG) ROUND_TO_PAGES (PartialSize); 03772 Size = PartialSize; 03773 } 03774 03775 NewSegment = ExAllocatePoolWithTag (PagedPool, 03776 Size, 03777 MMSECT); 03778 ExtendedSubsection = ExAllocatePoolWithTag (NonPagedPool, 03779 sizeof(SUBSECTION), 03780 'bSmM'); 03781 03782 if ((NewSegment == NULL) || (ExtendedSubsection == NULL)) { 03783 if (NewSegment) { 03784 ExFreePool (NewSegment); 03785 } 03786 if (ExtendedSubsection) { 03787 ExFreePool (ExtendedSubsection); 03788 } 03789 03790 // 03791 // Free all the previous allocations and return an error. 03792 // 03793 03794 while (FirstSubsection != NULL) { 03795 ExFreePool (FirstSubsection->SubsectionBase); 03796 Last = FirstSubsection->NextSubsection; 03797 ExFreePool (FirstSubsection); 03798 FirstSubsection = Last; 03799 } 03800 return STATUS_INSUFFICIENT_RESOURCES; 03801 } 03802 03803 NumberOfNewSubsections += 1; 03804 RtlZeroMemory (ExtendedSubsection, sizeof(SUBSECTION)); 03805 03806 if (FirstSubsection == NULL) { 03807 FirstSubsection = ExtendedSubsection; 03808 Last = ExtendedSubsection; 03809 NumberOfNewSubsections = 0; 03810 } else { 03811 Last->NextSubsection = ExtendedSubsection; 03812 } 03813 03814 ExtendedSubsection->PtesInSubsection = Size / sizeof(MMPTE); 03815 ExtendedSubsection->SubsectionBase = (PMMPTE)NewSegment; 03816 Last = ExtendedSubsection; 03817 PartialSize -= Size; 03818 } while (PartialSize != 0); 03819 03820 // 03821 // Reset new segment and free the first subsection, as 03822 // the subsection after the control area will become the 03823 // first subsection. 03824 // 03825 03826 NewSegment = (PSEGMENT)FirstSubsection->SubsectionBase; 03827 } 03828 03829 *Segment = NewSegment; 03830 RtlZeroMemory (NewSegment, sizeof(SEGMENT)); 03831 03832 ControlArea = 03833 (PCONTROL_AREA)File->SectionObjectPointer->DataSectionObject; 03834 03835 // 03836 // Control area and first subsection have been zeroed when allocated. 03837 // 03838 03839 ControlArea->Segment = NewSegment; 03840 ControlArea->NumberOfSectionReferences = 1; 03841 03842 if (IgnoreFileSizing == FALSE) { 03843 03844 // 03845 // This reference is not from the cache manager. 03846 // 03847 03848 ControlArea->NumberOfUserReferences = 1; 03849 } 03850 03851 ControlArea->u.Flags.BeingCreated = 1; 03852 ControlArea->u.Flags.File = 1; 03853 03854 if (FILE_REMOTE_DEVICE & File->DeviceObject->Characteristics) { 03855 03856 // 03857 // This file resides on a redirected drive. 03858 // 03859 03860 ControlArea->u.Flags.Networked = 1; 03861 } 03862 03863 if (AllocationAttributes & SEC_NOCACHE) { 03864 ControlArea->u.Flags.NoCache = 1; 03865 } 03866 03867 if (IgnoreFileSizing) { 03868 // Set the was purged flag to indicate that the 03869 // file size was not explicitly set. 03870 // 03871 03872 ControlArea->u.Flags.WasPurged = 1; 03873 } 03874 03875 ControlArea->NumberOfSubsections = (USHORT)(1 + NumberOfNewSubsections); 03876 ControlArea->FilePointer = File; 03877 03878 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 03879 03880 Subsection = (PSUBSECTION)(ControlArea + 1); 03881 03882 if (FirstSubsection) { 03883 03884 Subsection->NextSubsection = FirstSubsection->NextSubsection; 03885 Subsection->PtesInSubsection = FirstSubsection->PtesInSubsection; 03886 ExFreePool (FirstSubsection); 03887 #if DBG 03888 FirstSubsection = NULL; 03889 #endif //DBG 03890 } else { 03891 ASSERT (Subsection->NextSubsection == NULL); 03892 } 03893 03894 First = TRUE; 03895 03896 FileOffset = 0; 03897 03898 do { 03899 03900 // 03901 // Loop through all the subsections and fill in the PTEs. 03902 // 03903 03904 03905 TempPte.u.Long = MiGetSubsectionAddressForPte (Subsection); 03906 TempPte.u.Soft.Prototype = 1; 03907 03908 // 03909 // Set all the PTEs to the execute-read-write protection. 03910 // The section will control access to these and the segment 03911 // must provide a method to allow other users to map the file 03912 // for various protections. 03913 // 03914 03915 TempPte.u.Soft.Protection = MM_EXECUTE_READWRITE; 03916 03917 // 03918 // Align the prototype PTEs on the proper boundary. 03919 // 03920 03921 if (First) { 03922 03923 PointerPte = &NewSegment->ThePtes[0]; 03924 j = (ULONG) (((ULONG_PTR)PointerPte >> PTE_SHIFT) & 03925 ((MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - 1)); 03926 03927 if (j != 0) { 03928 j = (MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - j; 03929 } 03930 03931 NewSegment->PrototypePte = &NewSegment->ThePtes[j]; 03932 NewSegment->ControlArea = ControlArea; 03933 NewSegment->SizeOfSegment = EndOfFile; 03934 NewSegment->TotalNumberOfPtes = NumberOfPtes; 03935 NewSegment->SegmentPteTemplate = TempPte; 03936 PointerPte = NewSegment->PrototypePte; 03937 Subsection->SubsectionBase = PointerPte; 03938 ControlArea->PagedPoolUsage = EX_REAL_POOL_USAGE((sizeof(SEGMENT) + (NumberOfPtes * sizeof(MMPTE)))); 03939 03940 if (Subsection->NextSubsection != NULL) { 03941 03942 // 03943 // Multiple segments and subsections. 03944 // Align first so it is a multiple of 64k sizes. 03945 // 03946 // 03947 03948 NewSegment->NonExtendedPtes = (ULONG) 03949 ((((Subsection->PtesInSubsection * sizeof(MMPTE)) - 03950 ((PCHAR)NewSegment->PrototypePte - (PCHAR)NewSegment)) 03951 / sizeof(MMPTE)) & ~((X64K >> PAGE_SHIFT) - 1)); 03952 } else { 03953 NewSegment->NonExtendedPtes = NumberOfPtesWithAlignment; 03954 } 03955 Subsection->PtesInSubsection = NewSegment->NonExtendedPtes; 03956 03957 First = FALSE; 03958 } else { 03959 PointerPte = (PMMPTE)Subsection->SubsectionBase; 03960 } 03961 03962 Subsection->ControlArea = ControlArea; 03963 03964 Mi4KStartForSubsection(&FileOffset, Subsection); 03965 03966 Subsection->u.SubsectionFlags.Protection = MM_EXECUTE_READWRITE; 03967 03968 if (Subsection->NextSubsection == NULL) { 03969 03970 LastFileChunk = (EndOfFile >> MM4K_SHIFT) - FileOffset; 03971 03972 // 03973 // Note this next line restricts the number of bytes mapped by 03974 // a single subsection to 16TB-4K. multiple subsections can always 03975 // be chained together to support an overall file of size 16K TB. 03976 // 03977 03978 Subsection->NumberOfFullSectors = (ULONG)LastFileChunk; 03979 03980 Subsection->u.SubsectionFlags.SectorEndOffset = 03981 (ULONG) EndOfFile & MM4K_MASK; 03982 03983 j = Subsection->PtesInSubsection; 03984 03985 Subsection->PtesInSubsection = (ULONG)( 03986 NumberOfPtesForEntireFile - 03987 (FileOffset >> (PAGE_SHIFT - MM4K_SHIFT))); 03988 03989 #if DBG 03990 MiSubsectionConsistent(Subsection); 03991 #endif 03992 03993 Subsection->UnusedPtes = j - Subsection->PtesInSubsection; 03994 } else { 03995 03996 Subsection->NumberOfFullSectors = 03997 Subsection->PtesInSubsection << (PAGE_SHIFT - MM4K_SHIFT); 03998 #if DBG 03999 MiSubsectionConsistent(Subsection); 04000 #endif 04001 04002 } 04003 04004 MiFillMemoryPte (PointerPte, 04005 (Subsection->PtesInSubsection + 04006 Subsection->UnusedPtes) * sizeof(MMPTE), 04007 TempPte.u.Long); 04008 04009 FileOffset += Subsection->PtesInSubsection << 04010 (PAGE_SHIFT - MM4K_SHIFT); 04011 Subsection = Subsection->NextSubsection; 04012 } while (Subsection != NULL); 04013 04014 return STATUS_SUCCESS; 04015 }

NTSTATUS MiCreateImageFileMap IN PFILE_OBJECT  File,
OUT PSEGMENT Segment
 

Definition at line 1424 of file creasect.c.

References ASSERT, BYTE_OFFSET, BYTES_TO_PAGES, CcZeroEndOfLastPage(), CONTROL_AREA, _SUBSECTION::ControlArea, EX_REAL_POOL_USAGE, ExAllocatePoolWithTag, ExFreePool(), FALSE, File, _CONTROL_AREA::FilePointer, FsRtlGetFileSize(), _SEGMENT::ImageInformation, INIT_IMAGE_INFORMATION, IoPageRead(), KeClearEvent, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), LARGE_CONTROL_AREA, _MDL::MappedSystemVa, MDL_MAPPED_TO_SYSTEM_VA, MDL_PAGES_LOCKED, _MDL::MdlFlags, MI_GET_PROTECTION_FROM_SOFT_PTE, MI_ROUND_TO_SIZE, MI_WRITE_INVALID_PTE, MiChargeCommitment(), MiFlushDataSection(), MiGetImageProtection(), MiGetPageForHeader(), MiGetSubsectionAddress, MiGetSubsectionAddressForPte, MiHydra, MiMapImageHeaderInHyperSpace(), MiRemoveImageHeaderPage(), MiReturnCommitment(), MiUnmapImageHeaderInHyperSpace(), MiUpdateImageHeaderPage(), MiVerifyImageHeader(), MM_COPY_ON_WRITE_MASK, MM_DBG_COMMIT_IMAGE, MM_DBG_COMMIT_RETURN_IMAGE_NO_LARGE_CA, MM_EXECUTE_WRITECOPY, MM_MAXIMUM_IMAGE_HEADER, MM_PROTECTION_WRITE_MASK, MM_PROTO_PTE_ALIGNMENT, MM_READONLY, MM_TRACK_COMMIT, MmBuildMdlForNonPagedPool(), MMCONTROL, MmCreateMdl(), MMPTE, MMSECT, MmSectionCommitMutex, MMSECTOR_MASK, MMSECTOR_SHIFT, MmSharedCommit, MmSizeOfMdl(), MMTEMPORARY, MmUnmapLockedPages(), _SUBSECTION::NextSubsection, NonPagedPool, _CONTROL_AREA::NonPagedPoolUsage, _LARGE_CONTROL_AREA::NonPagedPoolUsage, NT_SUCCESS, NTSTATUS(), NULL, _SUBSECTION::NumberOfFullSectors, _CONTROL_AREA::NumberOfSectionReferences, _CONTROL_AREA::NumberOfSubsections, _CONTROL_AREA::NumberOfUserReferences, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, PagedPool, _CONTROL_AREA::PagedPoolUsage, PLARGE_CONTROL_AREA, _SEGMENT::PrototypePte, PTE_SHIFT, _SUBSECTION::PtesInSubsection, SectorOffset, SEGMENT, _CONTROL_AREA::Segment, _LARGE_CONTROL_AREA::SessionId, _SUBSECTION::StartingSector, Status, SUBSECTION, _SUBSECTION::SubsectionBase, _SEGMENT::TotalNumberOfPtes, TRUE, _CONTROL_AREA::u, _MMPTE::u, _SUBSECTION::u, _LARGE_CONTROL_AREA::u, _SUBSECTION::UnusedPtes, _LARGE_CONTROL_AREA::UserGlobalList, USHORT, WrPageIn, X64K, ZERO_LARGE, and ZeroPte.

Referenced by MmCreateSection().

01431 : 01432 01433 This function creates the necessary structures to allow the mapping 01434 of an image file. 01435 01436 The image file is opened and verified for correctness, a segment 01437 object is created and initialized based on data in the image 01438 header. 01439 01440 Arguments: 01441 01442 File - Supplies the file object for the image file. 01443 01444 Segment - Returns the segment object. 01445 01446 Return Value: 01447 01448 Returns the status value. 01449 01450 TBS 01451 01452 01453 --*/ 01454 01455 { 01456 NTSTATUS Status; 01457 ULONG_PTR EndingAddress; 01458 ULONG NumberOfPtes; 01459 ULONG SizeOfSegment; 01460 ULONG SectionVirtualSize; 01461 ULONG i; 01462 ULONG j; 01463 PCONTROL_AREA ControlArea; 01464 PSUBSECTION Subsection; 01465 PMMPTE PointerPte; 01466 MMPTE TempPte; 01467 MMPTE TempPteDemandZero; 01468 PVOID Base; 01469 PIMAGE_DOS_HEADER DosHeader; 01470 PIMAGE_NT_HEADERS NtHeader; 01471 PIMAGE_FILE_HEADER FileHeader; 01472 ULONG SizeOfImage; 01473 ULONG SizeOfHeaders; 01474 #if defined(_WIN64) 01475 PIMAGE_NT_HEADERS32 NtHeader32; 01476 #endif 01477 PIMAGE_SECTION_HEADER SectionTableEntry; 01478 PSEGMENT NewSegment; 01479 ULONG SectorOffset; 01480 ULONG NumberOfSubsections; 01481 PFN_NUMBER PageFrameNumber; 01482 LARGE_INTEGER StartingOffset; 01483 PCHAR ExtendedHeader; 01484 PPFN_NUMBER Page; 01485 ULONG_PTR PreferredImageBase; 01486 ULONG_PTR NextVa; 01487 PKEVENT InPageEvent; 01488 PMDL Mdl; 01489 ULONG ImageFileSize; 01490 ULONG OffsetToSectionTable; 01491 ULONG ImageAlignment; 01492 ULONG RoundingAlignment; 01493 ULONG FileAlignment; 01494 BOOLEAN ImageCommit; 01495 BOOLEAN SectionCommit; 01496 IO_STATUS_BLOCK IoStatus; 01497 LARGE_INTEGER EndOfFile; 01498 ULONG NtHeaderSize; 01499 ULONG SubsectionsAllocated; 01500 PLARGE_CONTROL_AREA LargeControlArea; 01501 PSUBSECTION NewSubsection; 01502 ULONG OriginalProtection; 01503 ULONG LoaderFlags; 01504 01505 #if defined (_ALPHA_) || defined(_IA64_) 01506 //[barrybo] bugbug: The image alignment code should be switched back 01507 // out on IA64 when EMNT supports 4k pages for WOW64. 01508 BOOLEAN InvalidAlignmentAllowed = FALSE; 01509 01510 ULONG TempNumberOfSubsections; 01511 PIMAGE_SECTION_HEADER TempSectionTableEntry; 01512 ULONG AdditionalSubsections; 01513 ULONG AdditionalPtes; 01514 ULONG AdditionalBasePtes; 01515 ULONG NewSubsectionsAllocated; 01516 PSEGMENT OldSegment; 01517 PMMPTE NewPointerPte; 01518 PMMPTE OldPointerPte; 01519 ULONG OrigNumberOfPtes; 01520 PCONTROL_AREA NewControlArea; 01521 01522 #endif 01523 01524 ExtendedHeader = NULL; 01525 01526 // ************************************************************* 01527 // Create image file section. 01528 // ************************************************************* 01529 01530 PAGED_CODE(); 01531 01532 01533 Status = FsRtlGetFileSize (File, &EndOfFile); 01534 01535 if (Status == STATUS_FILE_IS_A_DIRECTORY) { 01536 01537 // 01538 // Can't map a directory as a section. Return error. 01539 // 01540 01541 return STATUS_INVALID_FILE_FOR_SECTION; 01542 } 01543 01544 if (!NT_SUCCESS (Status)) { 01545 return Status; 01546 } 01547 01548 if (EndOfFile.HighPart != 0) { 01549 01550 // 01551 // File too big. Return error. 01552 // 01553 01554 return STATUS_INVALID_FILE_FOR_SECTION; 01555 } 01556 01557 // 01558 // Create a segment which maps an image file. 01559 // For now map a COFF image file with the subsections 01560 // containing the based address of the file. 01561 // 01562 01563 // 01564 // Read in the file header. 01565 // 01566 01567 InPageEvent = ExAllocatePoolWithTag (NonPagedPool, 01568 sizeof(KEVENT) + MmSizeOfMdl ( 01569 NULL, 01570 MM_MAXIMUM_IMAGE_HEADER), 01571 MMTEMPORARY); 01572 if (InPageEvent == NULL) { 01573 return STATUS_INSUFFICIENT_RESOURCES; 01574 } 01575 01576 Mdl = (PMDL)(InPageEvent + 1); 01577 01578 // 01579 // Create an event for the read operation. 01580 // 01581 01582 KeInitializeEvent (InPageEvent, NotificationEvent, FALSE); 01583 01584 // 01585 // Build an MDL for the operation. 01586 // 01587 01588 MmCreateMdl( Mdl, NULL, PAGE_SIZE); 01589 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 01590 01591 PageFrameNumber = MiGetPageForHeader(); 01592 01593 Page = (PPFN_NUMBER)(Mdl + 1); 01594 *Page = PageFrameNumber; 01595 01596 ZERO_LARGE (StartingOffset); 01597 01598 CcZeroEndOfLastPage (File); 01599 01600 // 01601 // Flush the data section if there is one. 01602 // 01603 01604 MiFlushDataSection (File); 01605 01606 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 01607 Status = IoPageRead (File, 01608 Mdl, 01609 &StartingOffset, 01610 InPageEvent, 01611 &IoStatus 01612 ); 01613 01614 if (Status == STATUS_PENDING) { 01615 KeWaitForSingleObject( InPageEvent, 01616 WrPageIn, 01617 KernelMode, 01618 FALSE, 01619 (PLARGE_INTEGER)NULL); 01620 } 01621 01622 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { 01623 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 01624 } 01625 01626 if ((!NT_SUCCESS(Status)) || (!NT_SUCCESS(IoStatus.Status))) { 01627 if (Status != STATUS_FILE_LOCK_CONFLICT) { 01628 Status = STATUS_INVALID_FILE_FOR_SECTION; 01629 } 01630 goto BadSection; 01631 } 01632 01633 Base = MiMapImageHeaderInHyperSpace (PageFrameNumber); 01634 DosHeader = (PIMAGE_DOS_HEADER)Base; 01635 01636 if (IoStatus.Information != PAGE_SIZE) { 01637 01638 // 01639 // A full page was not read from the file, zero any remaining 01640 // bytes. 01641 // 01642 01643 RtlZeroMemory ((PVOID)((PCHAR)Base + IoStatus.Information), 01644 PAGE_SIZE - IoStatus.Information); 01645 } 01646 01647 // 01648 // Check to determine if this is an NT image (PE format) or 01649 // a DOS image, Win-16 image, or OS/2 image. If the image is 01650 // not NT format, return an error indicating which image it 01651 // appears to be. 01652 // 01653 01654 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 01655 01656 Status = STATUS_INVALID_IMAGE_NOT_MZ; 01657 goto NeImage; 01658 } 01659 01660 #ifndef i386 01661 if (((ULONG)DosHeader->e_lfanew & 3) != 0) { 01662 01663 // 01664 // The image header is not aligned on a longword boundary. 01665 // Report this as an invalid protect mode image. 01666 // 01667 01668 Status = STATUS_INVALID_IMAGE_PROTECT; 01669 goto NeImage; 01670 } 01671 #endif 01672 01673 if ((ULONG)DosHeader->e_lfanew > EndOfFile.LowPart) { 01674 Status = STATUS_INVALID_IMAGE_PROTECT; 01675 goto NeImage; 01676 } 01677 01678 if (((ULONG)DosHeader->e_lfanew + 01679 sizeof(IMAGE_NT_HEADERS) + 01680 (16 * sizeof(IMAGE_SECTION_HEADER))) <= (ULONG)DosHeader->e_lfanew) { 01681 Status = STATUS_INVALID_IMAGE_PROTECT; 01682 goto NeImage; 01683 } 01684 01685 if (((ULONG)DosHeader->e_lfanew + 01686 sizeof(IMAGE_NT_HEADERS) + 01687 (16 * sizeof(IMAGE_SECTION_HEADER))) > PAGE_SIZE) { 01688 01689 // 01690 // The PE header is not within the page already read or the 01691 // objects are in another page. 01692 // Build another MDL and read an additional 8k. 01693 // 01694 01695 ExtendedHeader = ExAllocatePoolWithTag (NonPagedPool, 01696 MM_MAXIMUM_IMAGE_HEADER, 01697 MMTEMPORARY); 01698 if (ExtendedHeader == NULL) { 01699 Status = STATUS_INSUFFICIENT_RESOURCES; 01700 goto NeImage; 01701 } 01702 01703 // 01704 // Build an MDL for the operation. 01705 // 01706 01707 MmCreateMdl( Mdl, ExtendedHeader, MM_MAXIMUM_IMAGE_HEADER); 01708 01709 MmBuildMdlForNonPagedPool (Mdl); 01710 01711 StartingOffset.LowPart = PtrToUlong(PAGE_ALIGN ((ULONG)DosHeader->e_lfanew)); 01712 01713 KeClearEvent (InPageEvent); 01714 Status = IoPageRead (File, 01715 Mdl, 01716 &StartingOffset, 01717 InPageEvent, 01718 &IoStatus 01719 ); 01720 01721 if (Status == STATUS_PENDING) { 01722 KeWaitForSingleObject( InPageEvent, 01723 WrPageIn, 01724 KernelMode, 01725 FALSE, 01726 (PLARGE_INTEGER)NULL); 01727 } 01728 01729 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { 01730 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 01731 } 01732 01733 if ((!NT_SUCCESS(Status)) || (!NT_SUCCESS(IoStatus.Status))) { 01734 if (Status != STATUS_FILE_LOCK_CONFLICT) { 01735 Status = STATUS_INVALID_FILE_FOR_SECTION; 01736 } 01737 goto NeImage; 01738 } 01739 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)ExtendedHeader + 01740 BYTE_OFFSET((ULONG)DosHeader->e_lfanew)); 01741 NtHeaderSize = MM_MAXIMUM_IMAGE_HEADER - 01742 (ULONG)(BYTE_OFFSET((ULONG)DosHeader->e_lfanew)); 01743 01744 } else { 01745 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)DosHeader + 01746 (ULONG)DosHeader->e_lfanew); 01747 NtHeaderSize = PAGE_SIZE - (ULONG)DosHeader->e_lfanew; 01748 } 01749 FileHeader = &NtHeader->FileHeader; 01750 01751 // 01752 // Check to see if this is an NT image or a DOS or OS/2 image. 01753 // 01754 01755 Status = MiVerifyImageHeader (NtHeader, DosHeader, NtHeaderSize); 01756 if (Status != STATUS_SUCCESS) { 01757 goto NeImage; 01758 } 01759 01760 #if defined(_WIN64) 01761 if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 01762 // 01763 // The image is 32-bit. All code below this point must check 01764 // if NtHeader is NULL. If it is, then the image is PE32 and 01765 // NtHeader32 must be used. 01766 // 01767 NtHeader32 = (PIMAGE_NT_HEADERS32)NtHeader; 01768 NtHeader = NULL; 01769 } else { 01770 NtHeader32 = NULL; 01771 } 01772 01773 if (NtHeader) { 01774 #endif 01775 ImageAlignment = NtHeader->OptionalHeader.SectionAlignment; 01776 FileAlignment = NtHeader->OptionalHeader.FileAlignment - 1; 01777 SizeOfImage = NtHeader->OptionalHeader.SizeOfImage; 01778 LoaderFlags = NtHeader->OptionalHeader.LoaderFlags; 01779 #if defined (_WIN64) 01780 } else { 01781 ImageAlignment = NtHeader32->OptionalHeader.SectionAlignment; 01782 FileAlignment = NtHeader32->OptionalHeader.FileAlignment - 1; 01783 SizeOfImage = NtHeader32->OptionalHeader.SizeOfImage; 01784 LoaderFlags = NtHeader32->OptionalHeader.LoaderFlags; 01785 } 01786 #endif 01787 01788 RoundingAlignment = ImageAlignment; 01789 NumberOfSubsections = FileHeader->NumberOfSections; 01790 01791 if (ImageAlignment < PAGE_SIZE) { 01792 01793 // 01794 // The image alignment is less than the page size, 01795 // map the image with a single subsection. 01796 // 01797 01798 ControlArea = ExAllocatePoolWithTag (NonPagedPool, 01799 (ULONG)(sizeof(CONTROL_AREA) + (sizeof(SUBSECTION))), 01800 MMCONTROL); 01801 SubsectionsAllocated = 1; 01802 } else { 01803 01804 // 01805 // Allocate a control area and a subsection for each section 01806 // header plus one for the image header which has no section. 01807 // 01808 01809 ControlArea = ExAllocatePoolWithTag(NonPagedPool, 01810 (ULONG)(sizeof(CONTROL_AREA) + 01811 (sizeof(SUBSECTION) * 01812 (NumberOfSubsections + 1))), 01813 'iCmM'); 01814 SubsectionsAllocated = NumberOfSubsections + 1; 01815 } 01816 01817 if (ControlArea == NULL) { 01818 01819 // 01820 // The requested pool could not be allocated. 01821 // 01822 01823 Status = STATUS_INSUFFICIENT_RESOURCES; 01824 goto NeImage; 01825 } 01826 01827 // 01828 // Zero the control area and the FIRST subsection. 01829 // 01830 01831 RtlZeroMemory (ControlArea, 01832 sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 01833 01834 ControlArea->NonPagedPoolUsage = EX_REAL_POOL_USAGE(sizeof(CONTROL_AREA) + 01835 sizeof(SUBSECTION) * 01836 SubsectionsAllocated); 01837 01838 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 01839 01840 Subsection = (PSUBSECTION)(ControlArea + 1); 01841 01842 NumberOfPtes = BYTES_TO_PAGES (SizeOfImage); 01843 01844 if (NumberOfPtes == 0) { 01845 ExFreePool (ControlArea); 01846 Status = STATUS_INVALID_IMAGE_FORMAT; 01847 goto NeImage; 01848 } 01849 01850 #if defined (_ALPHA_) || defined(_IA64_) 01851 if (ImageAlignment < PAGE_SIZE && KeGetPreviousMode() != KernelMode && 01852 (FileHeader->Machine < USER_SHARED_DATA->ImageNumberLow || 01853 FileHeader->Machine > USER_SHARED_DATA->ImageNumberHigh)) { 01854 01855 InvalidAlignmentAllowed = TRUE; 01856 } 01857 OrigNumberOfPtes = NumberOfPtes; 01858 #endif 01859 01860 SizeOfSegment = sizeof(SEGMENT) + (sizeof(MMPTE) * (NumberOfPtes - 1)) + 01861 sizeof(SECTION_IMAGE_INFORMATION); 01862 01863 NewSegment = ExAllocatePoolWithTag (PagedPool, 01864 SizeOfSegment, 01865 MMSECT); 01866 01867 if (NewSegment == NULL) { 01868 01869 // 01870 // The requested pool could not be allocated. 01871 // 01872 01873 ExFreePool (ControlArea); 01874 Status = STATUS_INSUFFICIENT_RESOURCES; 01875 goto NeImage; 01876 } 01877 *Segment = NewSegment; 01878 RtlZeroMemory (NewSegment, sizeof(SEGMENT)); 01879 01880 // 01881 // Align the prototype PTEs on the proper boundary. 01882 // 01883 01884 PointerPte = &NewSegment->ThePtes[0]; 01885 i = (ULONG) (((ULONG_PTR)PointerPte >> PTE_SHIFT) & 01886 ((MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - 1)); 01887 01888 if (i != 0) { 01889 i = (MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - i; 01890 } 01891 01892 NewSegment->PrototypePte = &NewSegment->ThePtes[i]; 01893 01894 NewSegment->ControlArea = ControlArea; 01895 NewSegment->ImageInformation = 01896 (PSECTION_IMAGE_INFORMATION)((PCHAR)NewSegment + sizeof(SEGMENT) + 01897 (sizeof(MMPTE) * (NumberOfPtes - 1))); 01898 NewSegment->TotalNumberOfPtes = NumberOfPtes; 01899 NewSegment->NonExtendedPtes = NumberOfPtes; 01900 NewSegment->SizeOfSegment = (ULONG_PTR)NumberOfPtes * PAGE_SIZE; 01901 01902 RtlZeroMemory (NewSegment->ImageInformation, 01903 sizeof (SECTION_IMAGE_INFORMATION)); 01904 01905 01906 // 01907 // This code is built twice on the Win64 build - once for PE32+ and once for 01908 // PE32 images. 01909 // 01910 #define INIT_IMAGE_INFORMATION(OptHdr) { \ 01911 NewSegment->ImageInformation->TransferAddress = \ 01912 (PVOID)((ULONG_PTR)((OptHdr).ImageBase) + \ 01913 (OptHdr).AddressOfEntryPoint); \ 01914 NewSegment->ImageInformation->MaximumStackSize = \ 01915 (OptHdr).SizeOfStackReserve; \ 01916 NewSegment->ImageInformation->CommittedStackSize = \ 01917 (OptHdr).SizeOfStackCommit; \ 01918 NewSegment->ImageInformation->SubSystemType = \ 01919 (OptHdr).Subsystem; \ 01920 NewSegment->ImageInformation->SubSystemMajorVersion = (USHORT)((OptHdr).MajorSubsystemVersion); \ 01921 NewSegment->ImageInformation->SubSystemMinorVersion = (USHORT)((OptHdr).MinorSubsystemVersion); \ 01922 NewSegment->ImageInformation->DllCharacteristics = \ 01923 (OptHdr).DllCharacteristics; \ 01924 NewSegment->ImageInformation->ImageContainsCode = \ 01925 (BOOLEAN)(((OptHdr).SizeOfCode != 0) || \ 01926 ((OptHdr).AddressOfEntryPoint != 0)); \ 01927 } 01928 01929 #if defined (_WIN64) 01930 if (NtHeader) { 01931 #endif 01932 INIT_IMAGE_INFORMATION(NtHeader->OptionalHeader); 01933 #if defined (_WIN64) 01934 } else { 01935 // The image is 32-bit so use the 32-bit header 01936 INIT_IMAGE_INFORMATION(NtHeader32->OptionalHeader); 01937 } 01938 #endif 01939 #undef INIT_IMAGE_INFORMATION 01940 01941 NewSegment->ImageInformation->ImageCharacteristics = 01942 FileHeader->Characteristics; 01943 NewSegment->ImageInformation->Machine = 01944 FileHeader->Machine; 01945 01946 ControlArea->Segment = NewSegment; 01947 ControlArea->NumberOfSectionReferences = 1; 01948 ControlArea->NumberOfUserReferences = 1; 01949 ControlArea->u.Flags.BeingCreated = 1; 01950 ControlArea->PagedPoolUsage = EX_REAL_POOL_USAGE((sizeof(SEGMENT) + (NumberOfPtes * sizeof(MMPTE)))); 01951 01952 if (ImageAlignment < PAGE_SIZE) { 01953 01954 // 01955 // Image alignment is less than a page, the number 01956 // of subsections is 1. 01957 // 01958 01959 ControlArea->NumberOfSubsections = 1; 01960 } else { 01961 ControlArea->NumberOfSubsections = (USHORT)NumberOfSubsections; 01962 } 01963 01964 ControlArea->u.Flags.Image = 1; 01965 ControlArea->u.Flags.File = 1; 01966 01967 if ((FILE_FLOPPY_DISKETTE & File->DeviceObject->Characteristics) || 01968 ((FileHeader->Characteristics & 01969 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) && 01970 (FILE_REMOVABLE_MEDIA & File->DeviceObject->Characteristics)) || 01971 ((FileHeader->Characteristics & 01972 IMAGE_FILE_NET_RUN_FROM_SWAP) && 01973 (FILE_REMOTE_DEVICE & File->DeviceObject->Characteristics))) { 01974 01975 // 01976 // This file resides on a floppy disk or a removable media or 01977 // network with flags set indicating it should be copied 01978 // to the paging file. 01979 // 01980 01981 ControlArea->u.Flags.FloppyMedia = 1; 01982 } 01983 01984 if (FILE_REMOTE_DEVICE & File->DeviceObject->Characteristics) { 01985 01986 // 01987 // This file resides on a redirected drive. 01988 // 01989 01990 ControlArea->u.Flags.Networked = 1; 01991 } 01992 01993 ControlArea->FilePointer = File; 01994 01995 // 01996 // Build the subsection and prototype PTEs for the image header. 01997 // 01998 01999 Subsection->ControlArea = ControlArea; 02000 #if defined(_WIN64) 02001 if (NtHeader) { 02002 #endif 02003 NextVa = NtHeader->OptionalHeader.ImageBase; 02004 #if defined(_WIN64) 02005 } else { 02006 NextVa = NtHeader32->OptionalHeader.ImageBase; 02007 } 02008 #endif 02009 02010 02011 if ((NextVa & (X64K - 1)) != 0) { 02012 02013 // 02014 // Image header is not aligned on a 64k boundary. 02015 // 02016 02017 goto BadPeImageSegment; 02018 } 02019 02020 NewSegment->BasedAddress = (PVOID)NextVa; 02021 #if defined(_WIN64) 02022 if (NtHeader) { 02023 #endif 02024 SizeOfHeaders = NtHeader->OptionalHeader.SizeOfHeaders; 02025 #if defined(_WIN64) 02026 } else { 02027 SizeOfHeaders = NtHeader32->OptionalHeader.SizeOfHeaders; 02028 } 02029 #endif 02030 02031 if (SizeOfHeaders >= SizeOfImage) { 02032 goto BadPeImageSegment; 02033 } 02034 02035 Subsection->PtesInSubsection = MI_ROUND_TO_SIZE ( 02036 SizeOfHeaders, 02037 ImageAlignment 02038 ) >> PAGE_SHIFT; 02039 02040 PointerPte = NewSegment->PrototypePte; 02041 Subsection->SubsectionBase = PointerPte; 02042 02043 TempPte.u.Long = MiGetSubsectionAddressForPte (Subsection); 02044 TempPte.u.Soft.Prototype = 1; 02045 02046 NewSegment->SegmentPteTemplate = TempPte; 02047 SectorOffset = 0; 02048 02049 if (ImageAlignment < PAGE_SIZE) { 02050 02051 // 02052 // Aligned on less than a page size boundary. 02053 // Build a single subsection to refer to the image. 02054 // 02055 02056 PointerPte = NewSegment->PrototypePte; 02057 02058 Subsection->PtesInSubsection = NumberOfPtes; 02059 02060 Subsection->NumberOfFullSectors = 02061 (ULONG)(EndOfFile.QuadPart >> MMSECTOR_SHIFT); 02062 02063 ASSERT ((ULONG)(EndOfFile.HighPart & 0xFFFFF000) == 0); 02064 02065 Subsection->u.SubsectionFlags.SectorEndOffset = 02066 EndOfFile.LowPart & MMSECTOR_MASK; 02067 02068 Subsection->u.SubsectionFlags.Protection = MM_EXECUTE_WRITECOPY; 02069 02070 // 02071 // Set all the PTEs to the execute-read-write protection. 02072 // The section will control access to these and the segment 02073 // must provide a method to allow other users to map the file 02074 // for various protections. 02075 // 02076 02077 TempPte.u.Soft.Protection = MM_EXECUTE_WRITECOPY; 02078 02079 NewSegment->SegmentPteTemplate = TempPte; 02080 02081 02082 #if defined (_ALPHA_) || defined(_IA64_) 02083 // 02084 // Invalid image alignments are supported for cross platform 02085 // emulation. Only alpha and IA64 require extra handling because page 02086 // size is larger than x86. 02087 // 02088 02089 02090 if (InvalidAlignmentAllowed) { 02091 02092 TempPteDemandZero.u.Long = 0; 02093 TempPteDemandZero.u.Soft.Protection = MM_EXECUTE_WRITECOPY; 02094 SectorOffset = 0; 02095 02096 for (i = 0; i < NumberOfPtes; i += 1) { 02097 02098 // 02099 // Set prototype PTEs. 02100 // 02101 02102 if (SectorOffset < EndOfFile.LowPart) { 02103 02104 // 02105 // Data resides on the disk, refer to the control section. 02106 // 02107 02108 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 02109 02110 } else { 02111 02112 // 02113 // Data does not reside on the disk, use Demand zero pages. 02114 // 02115 02116 MI_WRITE_INVALID_PTE (PointerPte, TempPteDemandZero); 02117 } 02118 02119 SectorOffset += PAGE_SIZE; 02120 PointerPte += 1; 02121 } 02122 02123 } else 02124 #endif 02125 { 02126 02127 for (i = 0; i < NumberOfPtes; i += 1) { 02128 02129 // 02130 // Set all the prototype PTEs to refer to the control section. 02131 // 02132 02133 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 02134 PointerPte += 1; 02135 } 02136 } 02137 02138 NewSegment->ImageCommitment = NumberOfPtes; 02139 02140 02141 // 02142 // Indicate alignment is less than a page. 02143 // 02144 02145 TempPte.u.Long = 0; 02146 02147 } else { 02148 02149 // 02150 // Alignment is PAGE_SIZE or greater. 02151 // 02152 02153 if (Subsection->PtesInSubsection > NumberOfPtes) { 02154 02155 // 02156 // Inconsistent image, size does not agree with header. 02157 // 02158 02159 goto BadPeImageSegment; 02160 } 02161 NumberOfPtes -= Subsection->PtesInSubsection; 02162 02163 Subsection->NumberOfFullSectors = 02164 SizeOfHeaders >> MMSECTOR_SHIFT; 02165 02166 Subsection->u.SubsectionFlags.SectorEndOffset = 02167 SizeOfHeaders & MMSECTOR_MASK; 02168 02169 Subsection->u.SubsectionFlags.ReadOnly = 1; 02170 Subsection->u.SubsectionFlags.CopyOnWrite = 1; 02171 Subsection->u.SubsectionFlags.Protection = MM_READONLY; 02172 02173 TempPte.u.Soft.Protection = MM_READONLY; 02174 NewSegment->SegmentPteTemplate = TempPte; 02175 02176 for (i = 0; i < Subsection->PtesInSubsection; i += 1) { 02177 02178 // 02179 // Set all the prototype PTEs to refer to the control section. 02180 // 02181 02182 if (SectorOffset < SizeOfHeaders) { 02183 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 02184 } else { 02185 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 02186 } 02187 SectorOffset += PAGE_SIZE; 02188 PointerPte += 1; 02189 NextVa += PAGE_SIZE; 02190 } 02191 } 02192 02193 // 02194 // Build the next subsections. 02195 // 02196 02197 #if defined(_WIN64) 02198 if (NtHeader) { 02199 #endif 02200 PreferredImageBase = NtHeader->OptionalHeader.ImageBase; 02201 #if defined(_WIN64) 02202 } else { 02203 PreferredImageBase = NtHeader32->OptionalHeader.ImageBase; 02204 } 02205 #endif 02206 02207 // 02208 // At this point the object table is read in (if it was not 02209 // already read in) and may displace the image header. 02210 // 02211 02212 SectionTableEntry = NULL; 02213 OffsetToSectionTable = sizeof(ULONG) + 02214 sizeof(IMAGE_FILE_HEADER) + 02215 FileHeader->SizeOfOptionalHeader; 02216 02217 if ((BYTE_OFFSET(NtHeader) + OffsetToSectionTable + 02218 #if defined (_WIN64) 02219 BYTE_OFFSET(NtHeader32) + 02220 #endif 02221 ((NumberOfSubsections + 1) * 02222 sizeof (IMAGE_SECTION_HEADER))) <= PAGE_SIZE) { 02223 02224 // 02225 // Section tables are within the header which was read. 02226 // 02227 02228 #if defined(_WIN64) 02229 if (NtHeader32) { 02230 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader32 + 02231 OffsetToSectionTable); 02232 } else 02233 #endif 02234 { 02235 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 02236 OffsetToSectionTable); 02237 } 02238 02239 } else { 02240 02241 // 02242 // Has an extended header been read in and are the object 02243 // tables resident? 02244 // 02245 02246 if (ExtendedHeader != NULL) { 02247 02248 #if defined(_WIN64) 02249 if (NtHeader32) { 02250 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader32 + 02251 OffsetToSectionTable); 02252 } else 02253 #endif 02254 { 02255 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 02256 OffsetToSectionTable); 02257 } 02258 02259 // 02260 // Is the whole range of object tables mapped by the 02261 // extended header? 02262 // 02263 02264 if ((((PCHAR)SectionTableEntry + 02265 ((NumberOfSubsections + 1) * 02266 sizeof (IMAGE_SECTION_HEADER))) - 02267 (PCHAR)ExtendedHeader) > 02268 MM_MAXIMUM_IMAGE_HEADER) { 02269 SectionTableEntry = NULL; 02270 02271 } 02272 } 02273 } 02274 02275 if (SectionTableEntry == NULL) { 02276 02277 // 02278 // The section table entries are not in the same 02279 // pages as the other data already read in. Read in 02280 // the object table entries. 02281 // 02282 02283 if (ExtendedHeader == NULL) { 02284 ExtendedHeader = ExAllocatePoolWithTag (NonPagedPool, 02285 MM_MAXIMUM_IMAGE_HEADER, 02286 MMTEMPORARY); 02287 if (ExtendedHeader == NULL) { 02288 ExFreePool (NewSegment); 02289 ExFreePool (ControlArea); 02290 Status = STATUS_INSUFFICIENT_RESOURCES; 02291 goto NeImage; 02292 } 02293 02294 // 02295 // Build an MDL for the operation. 02296 // 02297 02298 MmCreateMdl( Mdl, ExtendedHeader, MM_MAXIMUM_IMAGE_HEADER); 02299 02300 MmBuildMdlForNonPagedPool (Mdl); 02301 } 02302 02303 StartingOffset.LowPart = PtrToUlong(PAGE_ALIGN ( 02304 (ULONG)DosHeader->e_lfanew + 02305 OffsetToSectionTable)); 02306 02307 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)ExtendedHeader + 02308 BYTE_OFFSET((ULONG)DosHeader->e_lfanew + 02309 OffsetToSectionTable)); 02310 02311 KeClearEvent (InPageEvent); 02312 Status = IoPageRead (File, 02313 Mdl, 02314 &StartingOffset, 02315 InPageEvent, 02316 &IoStatus 02317 ); 02318 02319 if (Status == STATUS_PENDING) { 02320 KeWaitForSingleObject( InPageEvent, 02321 WrPageIn, 02322 KernelMode, 02323 FALSE, 02324 (PLARGE_INTEGER)NULL); 02325 } 02326 02327 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { 02328 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 02329 } 02330 02331 if ((!NT_SUCCESS(Status)) || (!NT_SUCCESS(IoStatus.Status))) { 02332 if (Status != STATUS_FILE_LOCK_CONFLICT) { 02333 Status = STATUS_INVALID_FILE_FOR_SECTION; 02334 } 02335 ExFreePool (NewSegment); 02336 ExFreePool (ControlArea); 02337 goto NeImage; 02338 } 02339 02340 // 02341 // From this point on NtHeader is only valid if it 02342 // was in the first 4k of the image, otherwise reading in 02343 // the object tables wiped it out. 02344 // 02345 02346 } 02347 02348 if (TempPte.u.Long == 0 02349 #if defined (_ALPHA_) || defined(_IA64_) 02350 && (!InvalidAlignmentAllowed) 02351 #endif 02352 ) { 02353 02354 // The image header is no longer valid, TempPte is 02355 // used to indicate that this image alignment is 02356 // less than a PAGE_SIZE. 02357 02358 // 02359 // Loop through all sections and make sure there is no 02360 // uninitialized data. 02361 // 02362 02363 Status = STATUS_SUCCESS; 02364 02365 while (NumberOfSubsections > 0) { 02366 if (SectionTableEntry->Misc.VirtualSize == 0) { 02367 SectionVirtualSize = SectionTableEntry->SizeOfRawData; 02368 } else { 02369 SectionVirtualSize = SectionTableEntry->Misc.VirtualSize; 02370 } 02371 02372 // 02373 // If the raw pointer + raw size overflows a long word, return an error. 02374 // 02375 02376 if (SectionTableEntry->PointerToRawData + 02377 SectionTableEntry->SizeOfRawData < 02378 SectionTableEntry->PointerToRawData) { 02379 02380 KdPrint(("MMCREASECT: invalid section/file size %Z\n", 02381 &File->FileName)); 02382 02383 Status = STATUS_INVALID_IMAGE_FORMAT; 02384 break; 02385 } 02386 02387 // 02388 // If the virtual size and address does not match the rawdata 02389 // and invalid alignments not allowed return an error. 02390 // 02391 02392 if (((SectionTableEntry->PointerToRawData != 02393 SectionTableEntry->VirtualAddress)) 02394 || 02395 (SectionVirtualSize > SectionTableEntry->SizeOfRawData)) { 02396 02397 KdPrint(("MMCREASECT: invalid BSS/Trailingzero %Z\n", 02398 &File->FileName)); 02399 02400 Status = STATUS_INVALID_IMAGE_FORMAT; 02401 break; 02402 } 02403 02404 02405 SectionTableEntry += 1; 02406 NumberOfSubsections -= 1; 02407 } 02408 02409 02410 if (!NT_SUCCESS(Status)) { 02411 ExFreePool (NewSegment); 02412 ExFreePool (ControlArea); 02413 goto NeImage; 02414 } 02415 02416 goto PeReturnSuccess; 02417 02418 } 02419 #if defined (_ALPHA_) || defined(_IA64_) 02420 02421 else if (TempPte.u.Long == 0 && InvalidAlignmentAllowed) { 02422 02423 TempNumberOfSubsections = NumberOfSubsections; 02424 TempSectionTableEntry = SectionTableEntry; 02425 02426 // 02427 // The image header is no longer valid, TempPte is 02428 // used to indicate that this image alignment is 02429 // less than a PAGE_SIZE. 02430 // 02431 02432 // 02433 // Loop through all sections and make sure there is no 02434 // uninitialized data. 02435 // 02436 // Also determine if there are shared data sections and 02437 // the number of extra ptes they require. 02438 // 02439 02440 AdditionalSubsections = 0; 02441 AdditionalPtes = 0; 02442 AdditionalBasePtes = 0; 02443 RoundingAlignment = PAGE_SIZE; 02444 02445 while (TempNumberOfSubsections > 0) { 02446 ULONG EndOfSection; 02447 ULONG ExtraPages; 02448 02449 if (TempSectionTableEntry->Misc.VirtualSize == 0) { 02450 SectionVirtualSize = TempSectionTableEntry->SizeOfRawData; 02451 } else { 02452 SectionVirtualSize = TempSectionTableEntry->Misc.VirtualSize; 02453 } 02454 02455 EndOfSection = TempSectionTableEntry->PointerToRawData + 02456 TempSectionTableEntry->SizeOfRawData; 02457 02458 // 02459 // If the raw pointer + raw size overflows a long word, return an error. 02460 // 02461 02462 if (EndOfSection < TempSectionTableEntry->PointerToRawData) { 02463 02464 KdPrint(("MMCREASECT: invalid section/file size %Z\n", 02465 &File->FileName)); 02466 02467 Status = STATUS_INVALID_IMAGE_FORMAT; 02468 02469 ExFreePool (NewSegment); 02470 ExFreePool (ControlArea); 02471 goto NeImage; 02472 } 02473 02474 // 02475 // If the section goes past SizeOfImage then allocate additional PTEs. 02476 // On x86 this is handled by the subsection mapping. On alpha this is handled 02477 // by the Wx86 loader extension after the image has been mapped in. But the 02478 // additional data must be in memory so it can be shuffled around later. 02479 // 02480 02481 if ((EndOfSection <= EndOfFile.LowPart) && 02482 (EndOfSection > SizeOfImage)) { 02483 02484 // 02485 // Allocate enough PTEs to cover the end of this section. 02486 // Maximize with any other sections that extend beyond SizeOfImage 02487 // 02488 02489 ExtraPages = MI_ROUND_TO_SIZE (EndOfSection - SizeOfImage, RoundingAlignment) >> PAGE_SHIFT; 02490 if (ExtraPages > AdditionalBasePtes) { 02491 AdditionalBasePtes = ExtraPages; 02492 } 02493 } 02494 02495 // Count number of shared data sections and additional ptes needed 02496 02497 if ((TempSectionTableEntry->Characteristics & IMAGE_SCN_MEM_SHARED) && 02498 (!(TempSectionTableEntry->Characteristics & IMAGE_SCN_MEM_EXECUTE) || 02499 (TempSectionTableEntry->Characteristics & IMAGE_SCN_MEM_WRITE))) { 02500 AdditionalPtes += 02501 MI_ROUND_TO_SIZE (SectionVirtualSize, RoundingAlignment) >> 02502 PAGE_SHIFT; 02503 AdditionalSubsections += 1; 02504 } 02505 02506 TempSectionTableEntry += 1; 02507 TempNumberOfSubsections -= 1; 02508 } 02509 02510 if (AdditionalBasePtes == 0 && (AdditionalSubsections == 0 || AdditionalPtes == 0)) { 02511 // no shared data sections 02512 goto PeReturnSuccess; 02513 } 02514 02515 // 02516 // There are additional Base PTEs or shared data sections. 02517 // For shared sections, allocate new PTEs for these sections 02518 // at the end of the image. The WX86 loader will change 02519 // fixups to point to the new pages. 02520 // 02521 // First reallocate the control area. 02522 // 02523 02524 NewSubsectionsAllocated = SubsectionsAllocated + 02525 AdditionalSubsections; 02526 02527 NewControlArea = ExAllocatePoolWithTag(NonPagedPool, 02528 (ULONG) (sizeof(CONTROL_AREA) + 02529 (sizeof(SUBSECTION) * 02530 NewSubsectionsAllocated)), 02531 'iCmM'); 02532 if (NewControlArea == NULL) { 02533 ExFreePool (NewSegment); 02534 ExFreePool (ControlArea); 02535 Status = STATUS_INSUFFICIENT_RESOURCES; 02536 goto NeImage; 02537 } 02538 02539 // 02540 // Copy the old control area to the new one, modify some fields. 02541 // 02542 02543 RtlMoveMemory (NewControlArea, ControlArea, 02544 sizeof(CONTROL_AREA) + 02545 sizeof(SUBSECTION) * SubsectionsAllocated); 02546 02547 NewControlArea->NonPagedPoolUsage = 02548 EX_REAL_POOL_USAGE(sizeof(CONTROL_AREA) + 02549 (sizeof(SUBSECTION) * 02550 NewSubsectionsAllocated)); 02551 02552 NewControlArea->NumberOfSubsections = (USHORT) NewSubsectionsAllocated; 02553 02554 // 02555 // Now allocate a new segment that has the newly calculated number 02556 // of PTEs, initialize it from the previously allocated new segment, 02557 // and overwrite the fields that should be changed. 02558 // 02559 02560 OldSegment = NewSegment; 02561 02562 02563 OrigNumberOfPtes += AdditionalBasePtes; 02564 02565 SizeOfSegment = sizeof(SEGMENT) + 02566 (sizeof(MMPTE) * (OrigNumberOfPtes + AdditionalPtes - 1)) + 02567 sizeof(SECTION_IMAGE_INFORMATION); 02568 02569 NewSegment = ExAllocatePoolWithTag (PagedPool, 02570 SizeOfSegment, 02571 MMSECT); 02572 02573 if (NewSegment == NULL) { 02574 02575 // 02576 // The requested pool could not be allocated. 02577 // 02578 02579 ExFreePool (ControlArea); 02580 ExFreePool (NewControlArea); 02581 ExFreePool (OldSegment); 02582 Status = STATUS_INSUFFICIENT_RESOURCES; 02583 goto NeImage; 02584 } 02585 02586 *Segment = NewSegment; 02587 RtlMoveMemory (NewSegment, OldSegment, sizeof(SEGMENT)); 02588 02589 // 02590 // Align the prototype PTEs on the proper boundary. 02591 // 02592 02593 NewPointerPte = &NewSegment->ThePtes[0]; 02594 i = (ULONG) (((ULONG_PTR)NewPointerPte >> PTE_SHIFT) & 02595 ((MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - 1)); 02596 02597 if (i != 0) { 02598 i = (MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - i; 02599 } 02600 02601 NewSegment->PrototypePte = &NewSegment->ThePtes[i]; 02602 if (i != 0) { 02603 RtlZeroMemory (&NewSegment->ThePtes[0], sizeof(MMPTE) * i); 02604 } 02605 PointerPte = NewSegment->PrototypePte + 02606 (PointerPte - OldSegment->PrototypePte); 02607 02608 NewSegment->ControlArea = NewControlArea; 02609 NewSegment->ImageInformation = 02610 (PSECTION_IMAGE_INFORMATION)((PCHAR)NewSegment + sizeof(SEGMENT) + 02611 (sizeof(MMPTE) * (OrigNumberOfPtes + AdditionalPtes - 1))); 02612 NewSegment->TotalNumberOfPtes = OrigNumberOfPtes + AdditionalPtes; 02613 NewSegment->NonExtendedPtes = OrigNumberOfPtes + AdditionalPtes; 02614 NewSegment->SizeOfSegment = (ULONG_PTR)(OrigNumberOfPtes + AdditionalPtes) * PAGE_SIZE; 02615 02616 RtlMoveMemory (NewSegment->ImageInformation, 02617 OldSegment->ImageInformation, 02618 sizeof (SECTION_IMAGE_INFORMATION)); 02619 02620 // 02621 // Now change the fields in the subsections to account for the new 02622 // control area and the new segment. Also change the PTEs in the 02623 // newly allocated segment to point to the new subsections. 02624 // 02625 02626 NewControlArea->Segment = NewSegment; 02627 NewControlArea->PagedPoolUsage = EX_REAL_POOL_USAGE((sizeof(SEGMENT) + 02628 ((OrigNumberOfPtes + AdditionalPtes) * sizeof(MMPTE)))); 02629 02630 Subsection = (PSUBSECTION)(ControlArea + 1); 02631 NewSubsection = (PSUBSECTION)(NewControlArea + 1); 02632 NewSubsection->PtesInSubsection += AdditionalBasePtes; 02633 02634 for (i = 0; i < SubsectionsAllocated; i += 1) { 02635 02636 // 02637 // Note: SubsectionsAllocated is always 1 (for wx86), so this loop 02638 // is executed only once. 02639 // 02640 02641 NewSubsection->ControlArea = (PCONTROL_AREA) NewControlArea; 02642 02643 NewSubsection->SubsectionBase = NewSegment->PrototypePte + 02644 (Subsection->SubsectionBase - OldSegment->PrototypePte); 02645 02646 NewPointerPte = NewSegment->PrototypePte; 02647 OldPointerPte = OldSegment->PrototypePte; 02648 02649 TempPte.u.Long = MiGetSubsectionAddressForPte (NewSubsection); 02650 TempPte.u.Soft.Prototype = 1; 02651 02652 for (j = 0; j < OldSegment->TotalNumberOfPtes+AdditionalBasePtes; j += 1) { 02653 02654 if ((OldPointerPte->u.Soft.Prototype == 1) && 02655 (MiGetSubsectionAddress (OldPointerPte) == Subsection)) { 02656 OriginalProtection = MI_GET_PROTECTION_FROM_SOFT_PTE (OldPointerPte); 02657 TempPte.u.Soft.Protection = OriginalProtection; 02658 MI_WRITE_INVALID_PTE (NewPointerPte, TempPte); 02659 } 02660 else if (i == 0) { 02661 02662 // 02663 // Since the outer for loop is executed only once, there 02664 // is no need for the i == 0 above, but it is safer to 02665 // have it. If the code changes later and other sections 02666 // are added, their PTEs will get initialized here as 02667 // DemandZero and if they are not DemandZero, they will be 02668 // overwritten in a later iteration of the outer loop. 02669 // For now, this else if clause will be executed only 02670 // for DemandZero PTEs. 02671 // 02672 02673 OriginalProtection = MI_GET_PROTECTION_FROM_SOFT_PTE (OldPointerPte); 02674 TempPteDemandZero.u.Long = 0; 02675 TempPteDemandZero.u.Soft.Protection = OriginalProtection; 02676 MI_WRITE_INVALID_PTE (NewPointerPte, TempPteDemandZero); 02677 } 02678 02679 NewPointerPte += 1; 02680 // Stop incrementing the OldPointerPte at the last entry and use it 02681 // for the additional Base PTEs 02682 if (j < OldSegment->TotalNumberOfPtes-1) { 02683 OldPointerPte += 1; 02684 } 02685 } 02686 02687 Subsection += 1; 02688 NewSubsection += 1; 02689 } 02690 02691 02692 RtlZeroMemory (NewSubsection, 02693 sizeof(SUBSECTION) * AdditionalSubsections); 02694 02695 ExFreePool (OldSegment); 02696 ExFreePool (ControlArea); 02697 ControlArea = (PCONTROL_AREA) NewControlArea; 02698 02699 // 02700 // Adjust some variables that are used below. 02701 // PointerPte has already been set above before OldSegment was freed. 02702 // 02703 02704 SubsectionsAllocated = NewSubsectionsAllocated; 02705 Subsection = NewSubsection - 1; // Points to last used subsection. 02706 NumberOfPtes = AdditionalPtes; // # PTEs that haven't yet been used in 02707 // previous subsections. 02708 02709 // Additional Base PTEs have been added. Only continue if there are 02710 // additional subsections to process 02711 if (AdditionalSubsections == 0 || AdditionalPtes == 0) { 02712 // no shared data sections 02713 goto PeReturnSuccess; 02714 } 02715 } 02716 #endif 02717 02718 while (NumberOfSubsections > 0) { 02719 02720 #if defined (_ALPHA_) || defined(_IA64_) 02721 if (!InvalidAlignmentAllowed || 02722 ((SectionTableEntry->Characteristics & IMAGE_SCN_MEM_SHARED) && 02723 (!(SectionTableEntry->Characteristics & IMAGE_SCN_MEM_EXECUTE) || 02724 (SectionTableEntry->Characteristics & IMAGE_SCN_MEM_WRITE)))) { 02725 #endif 02726 02727 // 02728 // Handle case where virtual size is 0. 02729 // 02730 02731 if (SectionTableEntry->Misc.VirtualSize == 0) { 02732 SectionVirtualSize = SectionTableEntry->SizeOfRawData; 02733 } else { 02734 SectionVirtualSize = SectionTableEntry->Misc.VirtualSize; 02735 } 02736 02737 // 02738 // Fix for Borland linker problem. The SizeOfRawData can 02739 // be a zero, but the PointerToRawData is not zero. 02740 // Set it to zero. 02741 // 02742 02743 if (SectionTableEntry->SizeOfRawData == 0) { 02744 SectionTableEntry->PointerToRawData = 0; 02745 } 02746 02747 // 02748 // If the section information wraps return an error. 02749 // 02750 02751 if (SectionTableEntry->PointerToRawData + 02752 SectionTableEntry->SizeOfRawData < 02753 SectionTableEntry->PointerToRawData) { 02754 02755 goto BadPeImageSegment; 02756 } 02757 02758 02759 Subsection += 1; 02760 Subsection->ControlArea = ControlArea; 02761 Subsection->NextSubsection = (PSUBSECTION)NULL; 02762 Subsection->UnusedPtes = 0; 02763 02764 if (((NextVa != 02765 (PreferredImageBase + SectionTableEntry->VirtualAddress)) 02766 02767 #if defined (_ALPHA_) || defined(_IA64_) 02768 && !InvalidAlignmentAllowed 02769 #endif 02770 02771 ) || 02772 (SectionVirtualSize == 0)) { 02773 02774 // 02775 // The specified virtual address does not align 02776 // with the next prototype PTE. 02777 // 02778 02779 goto BadPeImageSegment; 02780 } 02781 02782 Subsection->PtesInSubsection = 02783 MI_ROUND_TO_SIZE (SectionVirtualSize, RoundingAlignment) 02784 >> PAGE_SHIFT; 02785 02786 if (Subsection->PtesInSubsection > NumberOfPtes) { 02787 02788 // 02789 // Inconsistent image, size does not agree with object tables. 02790 // 02791 02792 goto BadPeImageSegment; 02793 } 02794 NumberOfPtes -= Subsection->PtesInSubsection; 02795 02796 Subsection->u.LongFlags = 0; 02797 Subsection->StartingSector = 02798 SectionTableEntry->PointerToRawData >> MMSECTOR_SHIFT; 02799 02800 // 02801 // Align ending sector on file align boundary. 02802 // 02803 02804 EndingAddress = (SectionTableEntry->PointerToRawData + 02805 SectionTableEntry->SizeOfRawData + 02806 FileAlignment) & ~FileAlignment; 02807 02808 Subsection->NumberOfFullSectors = (ULONG) 02809 ((EndingAddress >> MMSECTOR_SHIFT) - 02810 Subsection->StartingSector); 02811 02812 Subsection->u.SubsectionFlags.SectorEndOffset = 02813 (ULONG) EndingAddress & MMSECTOR_MASK; 02814 02815 Subsection->SubsectionBase = PointerPte; 02816 02817 // 02818 // Build both a demand zero PTE and a PTE pointing to the 02819 // subsection. 02820 // 02821 TempPte.u.Long = 0; 02822 TempPteDemandZero.u.Long = 0; 02823 02824 TempPte.u.Long = MiGetSubsectionAddressForPte (Subsection); 02825 TempPte.u.Soft.Prototype = 1; 02826 ImageFileSize = SectionTableEntry->PointerToRawData + 02827 SectionTableEntry->SizeOfRawData; 02828 TempPte.u.Soft.Protection = 02829 MiGetImageProtection (SectionTableEntry->Characteristics); 02830 TempPteDemandZero.u.Soft.Protection = TempPte.u.Soft.Protection; 02831 02832 if (SectionTableEntry->PointerToRawData == 0) { 02833 TempPte = TempPteDemandZero; 02834 } 02835 02836 Subsection->u.SubsectionFlags.ReadOnly = 1; 02837 Subsection->u.SubsectionFlags.CopyOnWrite = 1; 02838 Subsection->u.SubsectionFlags.Protection = MI_GET_PROTECTION_FROM_SOFT_PTE (&TempPte); 02839 02840 if (TempPte.u.Soft.Protection & MM_PROTECTION_WRITE_MASK) { 02841 if ((TempPte.u.Soft.Protection & MM_COPY_ON_WRITE_MASK) 02842 == MM_COPY_ON_WRITE_MASK) { 02843 02844 // 02845 // This page is copy on write, charge ImageCommitment 02846 // for all pages in this subsection. 02847 // 02848 02849 ImageCommit = TRUE; 02850 } else { 02851 02852 // 02853 // This page is write shared, charge commitment when 02854 // the mapping completes. 02855 // 02856 02857 SectionCommit = TRUE; 02858 Subsection->u.SubsectionFlags.GlobalMemory = 1; 02859 ControlArea->u.Flags.GlobalMemory = 1; 02860 } 02861 } else { 02862 02863 // 02864 // Not writable, don't charge commitment at all. 02865 // 02866 02867 ImageCommit = FALSE; 02868 SectionCommit = FALSE; 02869 } 02870 02871 NewSegment->SegmentPteTemplate = TempPte; 02872 SectorOffset = 0; 02873 02874 for (i = 0; i < Subsection->PtesInSubsection; i += 1) { 02875 02876 // 02877 // Set all the prototype PTEs to refer to the control section. 02878 // 02879 02880 if (SectorOffset < SectionVirtualSize) { 02881 02882 // 02883 // Make PTE accessible. 02884 // 02885 02886 if (SectionCommit) { 02887 NewSegment->NumberOfCommittedPages += 1; 02888 } 02889 if (ImageCommit) { 02890 NewSegment->ImageCommitment += 1; 02891 } 02892 02893 if (SectorOffset < SectionTableEntry->SizeOfRawData) { 02894 02895 // 02896 // Data resides on the disk, use the subsection format PTE. 02897 // 02898 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 02899 } else { 02900 02901 // 02902 // Demand zero pages. 02903 // 02904 MI_WRITE_INVALID_PTE (PointerPte, TempPteDemandZero); 02905 } 02906 } else { 02907 02908 // 02909 // No access pages. 02910 // 02911 02912 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 02913 } 02914 SectorOffset += PAGE_SIZE; 02915 PointerPte += 1; 02916 NextVa += PAGE_SIZE; 02917 } 02918 02919 #if defined (_ALPHA_) || defined(_IA64_) 02920 } 02921 #endif 02922 02923 SectionTableEntry += 1; 02924 NumberOfSubsections -= 1; 02925 } 02926 02927 #if defined (_ALPHA_) || defined(_IA64_) 02928 if (!InvalidAlignmentAllowed) { 02929 #endif 02930 02931 // 02932 // Account for the number of subsections that really are mapped. 02933 // 02934 02935 ASSERT (ImageAlignment >= PAGE_SIZE); 02936 ControlArea->NumberOfSubsections += 1; 02937 02938 // 02939 // If the file size is not as big as the image claimed to be, 02940 // return an error. 02941 // 02942 02943 if (ImageFileSize > EndOfFile.LowPart) { 02944 02945 // 02946 // Invalid image size. 02947 // 02948 02949 KdPrint(("MMCREASECT: invalid image size - file size %lx - image size %lx\n %Z\n", 02950 EndOfFile.LowPart, ImageFileSize, &File->FileName)); 02951 goto BadPeImageSegment; 02952 } 02953 02954 // 02955 // The total number of PTEs was decremented as sections were built, 02956 // make sure that there are less than 64k's worth at this point. 02957 // 02958 02959 if (NumberOfPtes >= (ImageAlignment >> PAGE_SHIFT)) { 02960 02961 // 02962 // Inconsistent image, size does not agree with object tables. 02963 // 02964 02965 KdPrint(("MMCREASECT: invalid image - PTE left %lx\n image name %Z\n", 02966 NumberOfPtes, &File->FileName)); 02967 02968 goto BadPeImageSegment; 02969 } 02970 02971 // 02972 // Set any remaining PTEs to no access. 02973 // 02974 02975 while (NumberOfPtes != 0) { 02976 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 02977 PointerPte += 1; 02978 NumberOfPtes -= 1; 02979 } 02980 02981 // 02982 // Turn the image header page into a transition page within the 02983 // prototype PTEs. 02984 // 02985 02986 if ((ExtendedHeader == NULL) && (SizeOfHeaders < PAGE_SIZE)) { 02987 02988 // 02989 // Zero remaining portion of header. 02990 // 02991 02992 RtlZeroMemory ((PVOID)((PCHAR)Base + 02993 SizeOfHeaders), 02994 PAGE_SIZE - SizeOfHeaders); 02995 } 02996 02997 02998 #if defined (_ALPHA_) || defined(_IA64_) 02999 } 03000 #endif 03001 03002 if (NewSegment->NumberOfCommittedPages != 0) { 03003 03004 // 03005 // Commit the pages for the image section. 03006 // 03007 03008 if (MiChargeCommitment (NewSegment->NumberOfCommittedPages, NULL) == FALSE) { 03009 Status = STATUS_COMMITMENT_LIMIT; 03010 ExFreePool (NewSegment); 03011 ExFreePool (ControlArea); 03012 goto NeImage; 03013 } 03014 03015 MM_TRACK_COMMIT (MM_DBG_COMMIT_IMAGE, NewSegment->NumberOfCommittedPages); 03016 Status = STATUS_SUCCESS; 03017 03018 ExAcquireFastMutex (&MmSectionCommitMutex); 03019 MmSharedCommit += NewSegment->NumberOfCommittedPages; 03020 ExReleaseFastMutex (&MmSectionCommitMutex); 03021 } 03022 03023 PeReturnSuccess: 03024 03025 // 03026 // If this image is global per session, then allocate a large control 03027 // area. Note this doesn't need to be done for systemwide global control 03028 // areas or non-global control areas. 03029 // 03030 03031 if ((MiHydra == TRUE) && 03032 (ControlArea->u.Flags.GlobalMemory) && 03033 ((LoaderFlags & IMAGE_LOADER_FLAGS_SYSTEM_GLOBAL) == 0)) { 03034 03035 LargeControlArea = ExAllocatePoolWithTag(NonPagedPool, 03036 (ULONG)(sizeof(LARGE_CONTROL_AREA) + 03037 (sizeof(SUBSECTION) * 03038 SubsectionsAllocated)), 03039 'iCmM'); 03040 if (LargeControlArea == NULL) { 03041 03042 // 03043 // The requested pool could not be allocated. 03044 // 03045 03046 if (NewSegment->NumberOfCommittedPages != 0) { 03047 MiReturnCommitment (NewSegment->NumberOfCommittedPages); 03048 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_IMAGE_NO_LARGE_CA, NewSegment->NumberOfCommittedPages); 03049 ExAcquireFastMutex (&MmSectionCommitMutex); 03050 MmSharedCommit -= NewSegment->NumberOfCommittedPages; 03051 ExReleaseFastMutex (&MmSectionCommitMutex); 03052 } 03053 03054 ExFreePool (NewSegment); 03055 ExFreePool (ControlArea); 03056 03057 03058 Status = STATUS_INSUFFICIENT_RESOURCES; 03059 03060 goto NeImage; 03061 } 03062 03063 // 03064 // Copy the normal control area into our larger one, fix the linkages, 03065 // Fill in the additional fields in the new one and free the old one. 03066 // 03067 03068 RtlMoveMemory (LargeControlArea, ControlArea, sizeof(CONTROL_AREA)); 03069 LargeControlArea->NonPagedPoolUsage = EX_REAL_POOL_USAGE( 03070 sizeof(LARGE_CONTROL_AREA) + 03071 (sizeof(SUBSECTION) * 03072 SubsectionsAllocated)); 03073 03074 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 03075 03076 Subsection = (PSUBSECTION)(ControlArea + 1); 03077 NewSubsection = (PSUBSECTION)(LargeControlArea + 1); 03078 03079 for (i = 0; i < SubsectionsAllocated; i += 1) { 03080 RtlMoveMemory (NewSubsection, Subsection, sizeof(SUBSECTION)); 03081 NewSubsection->ControlArea = (PCONTROL_AREA) LargeControlArea; 03082 03083 PointerPte = NewSegment->PrototypePte; 03084 03085 TempPte.u.Long = MiGetSubsectionAddressForPte (NewSubsection); 03086 TempPte.u.Soft.Prototype = 1; 03087 03088 for (j = 0; j < NewSegment->TotalNumberOfPtes; j += 1) { 03089 03090 if ((PointerPte->u.Soft.Prototype == 1) && 03091 (MiGetSubsectionAddress (PointerPte) == Subsection)) { 03092 OriginalProtection = MI_GET_PROTECTION_FROM_SOFT_PTE (PointerPte); 03093 TempPte.u.Soft.Protection = OriginalProtection; 03094 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 03095 } 03096 PointerPte += 1; 03097 } 03098 03099 Subsection += 1; 03100 NewSubsection += 1; 03101 } 03102 03103 NewSegment->ControlArea = (PCONTROL_AREA) LargeControlArea; 03104 03105 LargeControlArea->u.Flags.GlobalOnlyPerSession = 1; 03106 03107 LargeControlArea->SessionId = 0; 03108 InitializeListHead (&LargeControlArea->UserGlobalList); 03109 03110 ExFreePool (ControlArea); 03111 03112 ControlArea = (PCONTROL_AREA) LargeControlArea; 03113 } 03114 03115 MiUnmapImageHeaderInHyperSpace (); 03116 03117 // 03118 // Set the PFN database entry for this page to look like a transition 03119 // page. 03120 // 03121 03122 PointerPte = NewSegment->PrototypePte; 03123 03124 MiUpdateImageHeaderPage (PointerPte, PageFrameNumber, ControlArea); 03125 if (ExtendedHeader != NULL) { 03126 ExFreePool (ExtendedHeader); 03127 } 03128 ExFreePool (InPageEvent); 03129 03130 return STATUS_SUCCESS; 03131 03132 03133 // 03134 // Error returns from image verification. 03135 // 03136 03137 BadPeImageSegment: 03138 03139 ExFreePool (NewSegment); 03140 ExFreePool (ControlArea); 03141 03142 //BadPeImage: 03143 Status = STATUS_INVALID_IMAGE_FORMAT; 03144 03145 NeImage: 03146 MiUnmapImageHeaderInHyperSpace (); 03147 03148 BadSection: 03149 MiRemoveImageHeaderPage(PageFrameNumber); 03150 if (ExtendedHeader != NULL) { 03151 ExFreePool (ExtendedHeader); 03152 } 03153 ExFreePool (InPageEvent); 03154 return Status; 03155 }

NTSTATUS MiCreatePagingFileMap OUT PSEGMENT Segment,
IN PUINT64  MaximumSize,
IN ULONG  ProtectionMask,
IN ULONG  AllocationAttributes
 

Definition at line 4018 of file creasect.c.

References BYTES_TO_PAGES, CONTROL_AREA, _SUBSECTION::ControlArea, EX_REAL_POOL_USAGE, ExAllocatePoolWithTag, ExFreePool(), FALSE, MI_WRITE_INVALID_PTE, MiChargeCommitment(), MiReturnCommitment(), MM_DBG_COMMIT_PAGEFILE_BACKED_SHMEM, MM_DBG_COMMIT_RETURN_PAGEFILE_BACKED_SHMEM, MM_PROTO_PTE_ALIGNMENT, MM_TRACK_COMMIT, MMCONTROL, MMSECT, MmSectionCommitMutex, MmSharedCommit, NonPagedPool, _CONTROL_AREA::NonPagedPoolUsage, NULL, _CONTROL_AREA::NumberOfSectionReferences, _CONTROL_AREA::NumberOfSubsections, _CONTROL_AREA::NumberOfUserReferences, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, PagedPool, _CONTROL_AREA::PagedPoolUsage, PTE_SHIFT, _SUBSECTION::PtesInSubsection, ROUND_TO_PAGES, _CONTROL_AREA::Segment, SEGMENT, SUBSECTION, _SUBSECTION::SubsectionBase, _CONTROL_AREA::u, _SUBSECTION::u, _MMPTE::u, and ZeroPte.

Referenced by MmCreateSection().

04027 : 04028 04029 This function creates the necessary structures to allow the mapping 04030 of a paging file. 04031 04032 Arguments: 04033 04034 Segment - Returns the segment object. 04035 04036 MaximumSize - Supplies the maximum size for the mapping. 04037 04038 ProtectionMask - Supplies the initial page protection. 04039 04040 AllocationAttributes - Supplies the allocation attributes for the 04041 mapping. 04042 04043 Return Value: 04044 04045 Returns the status value. 04046 04047 TBS 04048 04049 04050 --*/ 04051 04052 04053 { 04054 PFN_NUMBER NumberOfPtes; 04055 ULONG SizeOfSegment; 04056 ULONG i; 04057 PCONTROL_AREA ControlArea; 04058 PSEGMENT NewSegment; 04059 PMMPTE PointerPte; 04060 PSUBSECTION Subsection; 04061 MMPTE TempPte; 04062 LARGE_INTEGER SpecifiedSize; 04063 04064 PAGED_CODE(); 04065 04066 //******************************************************************* 04067 // Create a section backed by paging file. 04068 //******************************************************************* 04069 04070 if (*MaximumSize == 0) { 04071 return STATUS_INVALID_PARAMETER_4; 04072 } 04073 04074 // 04075 // Limit page file backed sections to the pagefile maximum size. 04076 // 04077 04078 #if defined (_WIN64) || defined (_X86PAE_) 04079 SpecifiedSize.QuadPart = (ROUND_TO_PAGES (*MaximumSize)) >> PAGE_SHIFT; 04080 04081 if (SpecifiedSize.HighPart != 0) 04082 #else 04083 if (*MaximumSize > (((ULONGLONG) 4 * 1024 * 1024 * 1024)) - (1024 * 1024)) 04084 #endif 04085 { 04086 return STATUS_SECTION_TOO_BIG; 04087 } 04088 04089 // 04090 // Create the segment object. 04091 // 04092 04093 // 04094 // Calculate the number of prototype PTEs to build for this segment. 04095 // 04096 04097 NumberOfPtes = BYTES_TO_PAGES (*MaximumSize); 04098 04099 if (AllocationAttributes & SEC_COMMIT) { 04100 04101 // 04102 // Commit the pages for the section. 04103 // 04104 04105 if (MiChargeCommitment (NumberOfPtes, NULL) == FALSE) { 04106 return STATUS_COMMITMENT_LIMIT; 04107 } 04108 MM_TRACK_COMMIT (MM_DBG_COMMIT_PAGEFILE_BACKED_SHMEM, NumberOfPtes); 04109 } 04110 04111 SizeOfSegment = sizeof(SEGMENT) + sizeof(MMPTE) * ((ULONG)NumberOfPtes - 1); 04112 04113 NewSegment = ExAllocatePoolWithTag (PagedPool, SizeOfSegment, MMSECT); 04114 04115 if (NewSegment == NULL) { 04116 04117 // 04118 // The requested pool could not be allocated. 04119 // 04120 04121 if (AllocationAttributes & SEC_COMMIT) { 04122 MiReturnCommitment (NumberOfPtes); 04123 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PAGEFILE_BACKED_SHMEM, NumberOfPtes); 04124 } 04125 return STATUS_INSUFFICIENT_RESOURCES; 04126 } 04127 04128 *Segment = NewSegment; 04129 04130 ControlArea = ExAllocatePoolWithTag (NonPagedPool, 04131 (ULONG)sizeof(CONTROL_AREA) + 04132 (ULONG)sizeof(SUBSECTION), 04133 MMCONTROL); 04134 04135 if (ControlArea == NULL) { 04136 04137 // 04138 // The requested pool could not be allocated. 04139 // 04140 04141 ExFreePool (NewSegment); 04142 04143 if (AllocationAttributes & SEC_COMMIT) { 04144 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PAGEFILE_BACKED_SHMEM, NumberOfPtes); 04145 MiReturnCommitment (NumberOfPtes); 04146 } 04147 return STATUS_INSUFFICIENT_RESOURCES; 04148 } 04149 04150 // 04151 // Zero control area and first subsection. 04152 // 04153 04154 RtlZeroMemory (ControlArea, 04155 sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 04156 04157 ControlArea->NonPagedPoolUsage = EX_REAL_POOL_USAGE(sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 04158 04159 ControlArea->Segment = NewSegment; 04160 ControlArea->NumberOfSectionReferences = 1; 04161 ControlArea->NumberOfUserReferences = 1; 04162 ControlArea->NumberOfSubsections = 1; 04163 04164 if (AllocationAttributes & SEC_BASED) { 04165 ControlArea->u.Flags.Based = 1; 04166 } 04167 04168 if (AllocationAttributes & SEC_RESERVE) { 04169 ControlArea->u.Flags.Reserve = 1; 04170 } 04171 04172 if (AllocationAttributes & SEC_COMMIT) { 04173 ControlArea->u.Flags.Commit = 1; 04174 } 04175 04176 Subsection = (PSUBSECTION)(ControlArea + 1); 04177 04178 Subsection->ControlArea = ControlArea; 04179 Subsection->PtesInSubsection = (ULONG)NumberOfPtes; 04180 Subsection->u.SubsectionFlags.Protection = ProtectionMask; 04181 04182 // 04183 // Align the prototype PTEs on the proper boundary. 04184 // 04185 04186 PointerPte = &NewSegment->ThePtes[0]; 04187 i = (ULONG) (((ULONG_PTR)PointerPte >> PTE_SHIFT) & 04188 ((MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - 1)); 04189 04190 if (i != 0) { 04191 i = (MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE) - i; 04192 } 04193 04194 // 04195 // Zero the segment header. 04196 // 04197 04198 RtlZeroMemory (NewSegment, sizeof(SEGMENT)); 04199 04200 NewSegment->PrototypePte = &NewSegment->ThePtes[i]; 04201 04202 NewSegment->ControlArea = ControlArea; 04203 04204 // 04205 // As size is limited to 2gb, ignore the high part. 04206 // 04207 04208 NewSegment->SizeOfSegment = (ULONG_PTR)NumberOfPtes * PAGE_SIZE; 04209 NewSegment->TotalNumberOfPtes = (ULONG)NumberOfPtes; 04210 NewSegment->NonExtendedPtes = (ULONG)NumberOfPtes; 04211 04212 ControlArea->PagedPoolUsage = EX_REAL_POOL_USAGE((sizeof(SEGMENT) + (NumberOfPtes * sizeof(MMPTE)))); 04213 04214 PointerPte = NewSegment->PrototypePte; 04215 Subsection->SubsectionBase = PointerPte; 04216 TempPte = ZeroPte; 04217 04218 if (AllocationAttributes & SEC_COMMIT) { 04219 TempPte.u.Soft.Protection = ProtectionMask; 04220 04221 // 04222 // Record commitment charging. 04223 // 04224 04225 NewSegment->NumberOfCommittedPages = NumberOfPtes; 04226 04227 ExAcquireFastMutex (&MmSectionCommitMutex); 04228 MmSharedCommit += NewSegment->NumberOfCommittedPages; 04229 ExReleaseFastMutex (&MmSectionCommitMutex); 04230 } 04231 04232 NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask; 04233 04234 for (i = 0; i < NumberOfPtes; i += 1) { 04235 04236 // 04237 // Set all the prototype PTEs to either no access or demand zero 04238 // depending on the commit flag. 04239 // 04240 04241 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 04242 PointerPte += 1; 04243 } 04244 04245 return STATUS_SUCCESS; 04246 }

PCONTROL_AREA MiFindImageSectionObject IN PFILE_OBJECT  File,
OUT PBOOLEAN  GlobalNeeded
 

Definition at line 4532 of file creasect.c.

References ASSERT, FALSE, File, MM_PFN_LOCK_ASSERT, NULL, PsGetCurrentProcess, _LARGE_CONTROL_AREA::SessionId, TRUE, _LARGE_CONTROL_AREA::u, _CONTROL_AREA::u, and _LARGE_CONTROL_AREA::UserGlobalList.

Referenced by MmCreateSection().

04539 : 04540 04541 This function searches the control area chains (if any) for an existing 04542 cache of the specified image file. For non-global control areas, there is 04543 no chain and the control area is shared for all callers and sessions. 04544 Likewise for systemwide global control areas. 04545 04546 However, for global PER-SESSION control areas, we must do the walk. 04547 04548 Arguments: 04549 04550 File - Supplies the file object for the image file. 04551 04552 GlobalNeeded - Supplies a pointer to store whether a global control area is 04553 required as a placeholder. This can only be set when there 04554 is already some global control area in the list - ie: our 04555 caller should only rely on this when this function returns 04556 NULL so the caller knows what kind of control area to 04557 insert. 04558 04559 Return Value: 04560 04561 Returns the matching control area or NULL if one does not exist. 04562 04563 Environment: 04564 04565 Must be holding the PFN lock. 04566 04567 --*/ 04568 04569 { 04570 PCONTROL_AREA ControlArea; 04571 PLARGE_CONTROL_AREA LargeControlArea; 04572 PLIST_ENTRY Head, Next; 04573 ULONG SessionId; 04574 04575 MM_PFN_LOCK_ASSERT(); 04576 04577 *GlobalNeeded = FALSE; 04578 04579 // 04580 // Get first (if any) control area pointer. 04581 // 04582 04583 ControlArea = (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject); 04584 04585 // 04586 // If no control area, or the control area is not session global, 04587 // then our job is easy. Note, however, that they each require different 04588 // return values as they represent different states. 04589 // 04590 04591 if (ControlArea == NULL) { 04592 return NULL; 04593 } 04594 04595 if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) { 04596 return ControlArea; 04597 } 04598 04599 LargeControlArea = (PLARGE_CONTROL_AREA) ControlArea; 04600 04601 // 04602 // Get the current session ID and search for a matching control area. 04603 // 04604 04605 SessionId = PsGetCurrentProcess()->SessionId; 04606 04607 if (LargeControlArea->SessionId == SessionId) { 04608 return (PCONTROL_AREA) LargeControlArea; 04609 } 04610 04611 // 04612 // Must search the control area list for a matching session ID. 04613 // 04614 04615 Head = &LargeControlArea->UserGlobalList; 04616 04617 for (Next = Head->Flink; Next != Head; Next = Next->Flink) { 04618 04619 LargeControlArea = CONTAINING_RECORD (Next, LARGE_CONTROL_AREA, UserGlobalList); 04620 04621 ASSERT (LargeControlArea->u.Flags.GlobalOnlyPerSession == 1); 04622 04623 if (LargeControlArea->SessionId == SessionId) { 04624 return (PCONTROL_AREA) LargeControlArea; 04625 } 04626 } 04627 04628 // 04629 // No match, so tell our caller to create a new global control area. 04630 // 04631 04632 *GlobalNeeded = TRUE; 04633 04634 return NULL; 04635 }

PCONTROL_AREA MiFindImageSectionObject IN PFILE_OBJECT  File,
IN PBOOLEAN  GlobalNeeded
 

VOID MiFlushDataSection IN PFILE_OBJECT  File  ) 
 

Definition at line 4999 of file creasect.c.

References CcFlushCache(), File, LOCK_PFN, MmFlushSection(), NULL, _CONTROL_AREA::NumberOfSystemCacheViews, TRUE, and UNLOCK_PFN.

Referenced by MiCreateImageFileMap(), and MmCreateSection().

05005 : 05006 05007 This routine flushes the data section if there is one. 05008 05009 Arguments: 05010 05011 File - Supplies the file object. 05012 05013 Return Value: 05014 05015 None. 05016 05017 Environment: 05018 05019 Kernel mode, APC_LEVEL and below. 05020 05021 --*/ 05022 05023 { 05024 KIRQL OldIrql; 05025 IO_STATUS_BLOCK IoStatus; 05026 PCONTROL_AREA ControlArea; 05027 05028 LOCK_PFN (OldIrql); 05029 05030 ControlArea = (PCONTROL_AREA) File->SectionObjectPointer->DataSectionObject; 05031 05032 if (ControlArea) { 05033 if (ControlArea->NumberOfSystemCacheViews) { 05034 UNLOCK_PFN (OldIrql); 05035 CcFlushCache (File->SectionObjectPointer, 05036 NULL, 05037 0, 05038 &IoStatus); 05039 05040 } else { 05041 UNLOCK_PFN (OldIrql); 05042 MmFlushSection (File->SectionObjectPointer, 05043 NULL, 05044 0, 05045 &IoStatus, 05046 TRUE); 05047 } 05048 } 05049 else { 05050 UNLOCK_PFN (OldIrql); 05051 } 05052 } }

CCHAR MiGetImageProtection IN ULONG  SectionCharacteristics  ) 
 

Definition at line 4334 of file creasect.c.

References Index, MmImageProtectionArray, and PAGED_CODE.

Referenced by MiCreateImageFileMap(), and MiGetWritablePagesInSection().

04340 : 04341 04342 This function takes a section characteristic mask from the 04343 image and converts it to an PTE protection mask. 04344 04345 Arguments: 04346 04347 SectionCharacteristics - Supplies the characteristics mask from the 04348 image. 04349 04350 Return Value: 04351 04352 Returns the protection mask for the PTE. 04353 04354 --*/ 04355 04356 { 04357 ULONG Index; 04358 PAGED_CODE(); 04359 04360 Index = 0; 04361 if (SectionCharacteristics & IMAGE_SCN_MEM_EXECUTE) { 04362 Index |= 1; 04363 } 04364 if (SectionCharacteristics & IMAGE_SCN_MEM_READ) { 04365 Index |= 2; 04366 } 04367 if (SectionCharacteristics & IMAGE_SCN_MEM_WRITE) { 04368 Index |= 4; 04369 } 04370 if (SectionCharacteristics & IMAGE_SCN_MEM_SHARED) { 04371 Index |= 8; 04372 } 04373 04374 return MmImageProtectionArray[Index]; 04375 }

PFN_NUMBER MiGetPageForHeader VOID   ) 
 

Definition at line 4378 of file creasect.c.

References CONSISTENCY_UNLOCK_PFN, LOCK_PFN, MI_PAGE_COLOR_VA_PROCESS, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiEnsureAvailablePageOrWait(), MiRemoveAnyPage(), _EPROCESS::NextPageColor, NULL, _MMPFN::OriginalPte, PsGetCurrentProcess, _MMPFN::PteAddress, _MMPFN::u3, UNLOCK_PFN, X64K, and ZeroPte.

Referenced by MiCheckForCrashDump(), and MiCreateImageFileMap().

04384 : 04385 04386 This non-pagable function acquires the PFN lock, removes 04387 a page and updates the PFN database as though the page was 04388 ready to be deleted if the reference count is decremented. 04389 04390 Arguments: 04391 04392 None. 04393 04394 Return Value: 04395 04396 Returns the physical page frame number. 04397 04398 --*/ 04399 04400 { 04401 KIRQL OldIrql; 04402 PFN_NUMBER PageFrameNumber; 04403 PMMPFN Pfn1; 04404 PEPROCESS Process; 04405 ULONG PageColor; 04406 04407 Process = PsGetCurrentProcess(); 04408 PageColor = MI_PAGE_COLOR_VA_PROCESS ((PVOID)X64K, 04409 &Process->NextPageColor); 04410 04411 // 04412 // Lock the PFN database and get a page. 04413 // 04414 04415 LOCK_PFN (OldIrql); 04416 04417 MiEnsureAvailablePageOrWait (NULL, NULL); 04418 04419 // 04420 // Remove page for 64k alignment. 04421 // 04422 04423 PageFrameNumber = MiRemoveAnyPage (PageColor); 04424 04425 // 04426 // Increment the reference count for the page so the 04427 // paging I/O will work, and so this page cannot be stolen from us. 04428 // 04429 04430 Pfn1 = MI_PFN_ELEMENT (PageFrameNumber); 04431 Pfn1->u3.e2.ReferenceCount += 1; 04432 04433 #ifndef PFN_CONSISTENCY 04434 // 04435 // Don't need the PFN lock for the fields below... 04436 // 04437 UNLOCK_PFN (OldIrql); 04438 #endif 04439 04440 Pfn1->OriginalPte = ZeroPte; 04441 Pfn1->PteAddress = (PVOID) (ULONG_PTR)X64K; 04442 MI_SET_PFN_DELETED (Pfn1); 04443 04444 CONSISTENCY_UNLOCK_PFN (OldIrql); 04445 04446 return PageFrameNumber; 04447 }

NTSTATUS MiGetWritablePagesInSection IN PSECTION  Section,
OUT PULONG  WritablePages
 

Definition at line 4868 of file creasect.c.

References ASSERT, MI_ROUND_TO_SIZE, MiGetImageProtection(), MM_PROTECTION_WRITE_MASK, MmMapViewOfSection(), MmUnmapViewOfSection(), NT_SUCCESS, NTSTATUS(), NULL, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, PsGetCurrentProcess, and Status.

Referenced by MiSessionWideReserveImageAddress().

04875 : 04876 04877 This routine calculates the number of writable pages in the image. 04878 04879 Arguments: 04880 04881 Section - Supplies the section for the image. 04882 04883 WritablePages - Supplies a pointer to fill with the 04884 number of writable pages. 04885 04886 Return Value: 04887 04888 STATUS_SUCCESS if all went well, otherwise various NTSTATUS error codes. 04889 04890 Environment: 04891 04892 Kernel mode, APC_LEVEL and below, MmSystemLoadLock held. 04893 04894 --*/ 04895 04896 { 04897 NTSTATUS Status; 04898 PVOID ViewBase; 04899 SIZE_T ViewSize; 04900 ULONG PagesInSubsection; 04901 ULONG Protection; 04902 ULONG NumberOfSubsections; 04903 ULONG OffsetToSectionTable; 04904 ULONG SectionVirtualSize; 04905 PEPROCESS Process; 04906 LARGE_INTEGER SectionOffset; 04907 PIMAGE_DOS_HEADER DosHeader; 04908 PIMAGE_NT_HEADERS NtHeader; 04909 PIMAGE_SECTION_HEADER SectionTableEntry; 04910 04911 PAGED_CODE(); 04912 04913 ViewBase = NULL; 04914 ViewSize = 0; 04915 SectionOffset.QuadPart = 0; 04916 04917 *WritablePages = 0; 04918 04919 Process = PsGetCurrentProcess(); 04920 04921 Status = MmMapViewOfSection (Section, 04922 Process, 04923 &ViewBase, 04924 0, 04925 0, 04926 &SectionOffset, 04927 &ViewSize, 04928 ViewUnmap, 04929 0, 04930 PAGE_EXECUTE); 04931 04932 if (!NT_SUCCESS(Status)) { 04933 return Status; 04934 } 04935 04936 // 04937 // The DLL is mapped as a data file not as an image. Pull apart the 04938 // executable header. The security checks have already been 04939 // done as part of creating the section in the first place. 04940 // 04941 04942 DosHeader = (PIMAGE_DOS_HEADER) ViewBase; 04943 04944 ASSERT (DosHeader->e_magic == IMAGE_DOS_SIGNATURE); 04945 04946 #ifndef i386 04947 ASSERT (((ULONG)DosHeader->e_lfanew & 3) == 0); 04948 #endif 04949 04950 ASSERT ((ULONG)DosHeader->e_lfanew <= ViewSize); 04951 04952 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)DosHeader + 04953 (ULONG)DosHeader->e_lfanew); 04954 04955 OffsetToSectionTable = sizeof(ULONG) + 04956 sizeof(IMAGE_FILE_HEADER) + 04957 NtHeader->FileHeader.SizeOfOptionalHeader; 04958 04959 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 04960 OffsetToSectionTable); 04961 04962 NumberOfSubsections = NtHeader->FileHeader.NumberOfSections; 04963 04964 while (NumberOfSubsections > 0) { 04965 04966 Protection = MiGetImageProtection (SectionTableEntry->Characteristics); 04967 04968 if (Protection & MM_PROTECTION_WRITE_MASK) { 04969 04970 // 04971 // Handle the case where the virtual size is 0. 04972 // 04973 04974 if (SectionTableEntry->Misc.VirtualSize == 0) { 04975 SectionVirtualSize = SectionTableEntry->SizeOfRawData; 04976 } else { 04977 SectionVirtualSize = SectionTableEntry->Misc.VirtualSize; 04978 } 04979 04980 PagesInSubsection = 04981 MI_ROUND_TO_SIZE (SectionVirtualSize, PAGE_SIZE) >> PAGE_SHIFT; 04982 04983 *WritablePages += PagesInSubsection; 04984 } 04985 04986 SectionTableEntry += 1; 04987 NumberOfSubsections -= 1; 04988 } 04989 04990 Status = MmUnmapViewOfSection (Process, ViewBase); 04991 04992 ASSERT (NT_SUCCESS(Status)); 04993 04994 return Status; 04995 }

VOID MiInsertImageSectionObject IN PFILE_OBJECT  File,
IN PCONTROL_AREA  ControlArea
 

Definition at line 4638 of file creasect.c.

References ASSERT, File, MM_PFN_LOCK_ASSERT, NULL, PsGetCurrentProcess, _LARGE_CONTROL_AREA::SessionId, _LARGE_CONTROL_AREA::u, and _LARGE_CONTROL_AREA::UserGlobalList.

Referenced by MmCreateSection().

04645 : 04646 04647 This function inserts the control area into the file's section object 04648 pointers. For non-global control areas, there is no chain and the 04649 control area is shared for all callers and sessions. 04650 Likewise for systemwide global control areas. 04651 04652 However, for global PER-SESSION control areas, we must do a list insertion. 04653 04654 Arguments: 04655 04656 File - Supplies the file object for the image file. 04657 04658 InputControlArea - Supplies the control area to insert. 04659 04660 Return Value: 04661 04662 None. 04663 04664 Environment: 04665 04666 Must be holding the PFN lock. 04667 04668 --*/ 04669 04670 { 04671 PLIST_ENTRY Head; 04672 PLARGE_CONTROL_AREA ControlArea; 04673 PLARGE_CONTROL_AREA FirstControlArea; 04674 #if DBG 04675 PLIST_ENTRY Next; 04676 PLARGE_CONTROL_AREA NextControlArea; 04677 #endif 04678 04679 MM_PFN_LOCK_ASSERT(); 04680 04681 ControlArea = (PLARGE_CONTROL_AREA) InputControlArea; 04682 04683 // 04684 // If this is not a global-per-session control area or just a placeholder 04685 // control area (with no chain already in place) then just put it in. 04686 // 04687 04688 FirstControlArea = (PLARGE_CONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject); 04689 04690 if (FirstControlArea == NULL) { 04691 if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) { 04692 (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject) = 04693 (PCONTROL_AREA) ControlArea; 04694 return; 04695 } 04696 } 04697 04698 // 04699 // A per-session control area needs to be inserted... 04700 // 04701 04702 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 1); 04703 04704 ControlArea->SessionId = PsGetCurrentProcess()->SessionId; 04705 04706 // 04707 // If the control area list is empty, just initialize links for this entry. 04708 // 04709 04710 if (File->SectionObjectPointer->ImageSectionObject == NULL) { 04711 InitializeListHead (&ControlArea->UserGlobalList); 04712 } 04713 else { 04714 04715 // 04716 // Insert new entry before the current first entry. The control area 04717 // must be in the midst of creation/deletion or have a valid session 04718 // ID to be inserted. 04719 // 04720 04721 ASSERT (ControlArea->u.Flags.BeingDeleted || 04722 ControlArea->u.Flags.BeingCreated || 04723 ControlArea->SessionId != (ULONG)-1); 04724 04725 FirstControlArea = (PLARGE_CONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject); 04726 04727 Head = &FirstControlArea->UserGlobalList; 04728 04729 #if DBG 04730 // 04731 // Ensure no duplicate session IDs exist in the list. 04732 // 04733 04734 for (Next = Head->Flink; Next != Head; Next = Next->Flink) { 04735 NextControlArea = CONTAINING_RECORD (Next, LARGE_CONTROL_AREA, UserGlobalList); 04736 ASSERT (NextControlArea->SessionId != (ULONG)-1 && 04737 NextControlArea->SessionId != ControlArea->SessionId); 04738 } 04739 #endif 04740 04741 InsertTailList (Head, &ControlArea->UserGlobalList); 04742 } 04743 04744 // 04745 // Update first control area pointer. 04746 // 04747 04748 (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject) = 04749 (PCONTROL_AREA) ControlArea; 04750 }

VOID MiRemoveImageHeaderPage IN PFN_NUMBER  PageFrameNumber  ) 
 

Definition at line 4501 of file creasect.c.

References LOCK_PFN, MiDecrementReferenceCount(), and UNLOCK_PFN.

Referenced by MiCheckForCrashDump(), and MiCreateImageFileMap().

04507 : 04508 04509 This non-pagable function acquires the PFN lock, and decrements 04510 the reference count thereby causing the physical page to 04511 be deleted. 04512 04513 Arguments: 04514 04515 PageFrameNumber - Supplies the PFN to decrement. 04516 04517 Return Value: 04518 04519 None. 04520 04521 --*/ 04522 { 04523 KIRQL OldIrql; 04524 04525 LOCK_PFN (OldIrql); 04526 MiDecrementReferenceCount (PageFrameNumber); 04527 UNLOCK_PFN (OldIrql); 04528 return; 04529 }

VOID MiRemoveImageSectionObject IN PFILE_OBJECT  File,
IN PCONTROL_AREA  InputControlArea
 

Definition at line 4753 of file creasect.c.

References ASSERT, File, MM_PFN_LOCK_ASSERT, NULL, _LARGE_CONTROL_AREA::u, and _LARGE_CONTROL_AREA::UserGlobalList.

Referenced by MiCheckControlArea(), MiCheckForControlAreaDeletion(), MiCleanSection(), and MmCreateSection().

04760 : 04761 04762 This function searches the control area chains (if any) for an existing 04763 cache of the specified image file. For non-global control areas, there is 04764 no chain and the control area is shared for all callers and sessions. 04765 Likewise for systemwide global control areas. 04766 04767 However, for global PER-SESSION control areas, we must do the walk. 04768 04769 Upon finding the specified control area, we unlink it. 04770 04771 Arguments: 04772 04773 File - Supplies the file object for the image file. 04774 04775 InputControlArea - Supplies the control area to remove. 04776 04777 Return Value: 04778 04779 None. 04780 04781 Environment: 04782 04783 Must be holding the PFN lock. 04784 04785 --*/ 04786 04787 { 04788 PLIST_ENTRY Head, Next; 04789 PLARGE_CONTROL_AREA ControlArea; 04790 PLARGE_CONTROL_AREA FirstControlArea; 04791 PLARGE_CONTROL_AREA NextControlArea; 04792 04793 MM_PFN_LOCK_ASSERT(); 04794 04795 ControlArea = (PLARGE_CONTROL_AREA) InputControlArea; 04796 04797 FirstControlArea = (PLARGE_CONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject); 04798 04799 // 04800 // Get a pointer to the first control area. If this is not a 04801 // global-per-session control area, then there is no list, so we're done. 04802 // 04803 04804 if (FirstControlArea->u.Flags.GlobalOnlyPerSession == 0) { 04805 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 04806 04807 (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject) = NULL; 04808 return; 04809 } 04810 04811 // 04812 // A list may exist. Walk it as necessary and delete the requested entry. 04813 // 04814 04815 if (FirstControlArea == ControlArea) { 04816 04817 // 04818 // The first entry is the one to remove. If it is the only entry 04819 // in the list, then the new first entry pointer will be NULL. 04820 // Otherwise, get a pointer to the next entry and unlink the current. 04821 // 04822 04823 if (IsListEmpty (&FirstControlArea->UserGlobalList)) { 04824 NextControlArea = NULL; 04825 } else { 04826 Next = FirstControlArea->UserGlobalList.Flink; 04827 RemoveEntryList (&FirstControlArea->UserGlobalList); 04828 NextControlArea = CONTAINING_RECORD (Next, 04829 LARGE_CONTROL_AREA, 04830 UserGlobalList); 04831 04832 ASSERT (NextControlArea->u.Flags.GlobalOnlyPerSession == 1); 04833 } 04834 04835 (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject) = 04836 (PCONTROL_AREA) NextControlArea; 04837 return; 04838 } 04839 04840 // 04841 // Remove the entry, note that the ImageSectionObject need not be updated 04842 // as the entry is not at the head. 04843 // 04844 04845 #if DBG 04846 Head = &FirstControlArea->UserGlobalList; 04847 04848 for (Next = Head->Flink; Next != Head; Next = Next->Flink) { 04849 04850 NextControlArea = CONTAINING_RECORD (Next, 04851 LARGE_CONTROL_AREA, 04852 UserGlobalList); 04853 04854 ASSERT (NextControlArea->u.Flags.GlobalOnlyPerSession == 1); 04855 04856 if (NextControlArea == ControlArea) { 04857 break; 04858 } 04859 } 04860 ASSERT (Next != Head); 04861 #endif 04862 04863 RemoveEntryList (&ControlArea->UserGlobalList); 04864 }

VOID MiUpdateImageHeaderPage IN PMMPTE  PointerPte,
IN PFN_NUMBER  PageFrameNumber,
IN PCONTROL_AREA  ControlArea
 

Definition at line 4450 of file creasect.c.

References LOCK_PFN, MiDecrementReferenceCount(), MiInitializeTransitionPfn(), MiMakeSystemAddressValidPfn(), and UNLOCK_PFN.

Referenced by MiCheckForCrashDump(), and MiCreateImageFileMap().

04458 : 04459 04460 This non-pagable function acquires the PFN lock, and 04461 turns the specified prototype PTE into a transition PTE 04462 referring to the specified physical page. It then 04463 decrements the reference count causing the page to 04464 be placed on the standby or modified list. 04465 04466 Arguments: 04467 04468 PointerPte - Supplies the PTE to set into the transition state. 04469 04470 PageFrameNumber - Supplies the physical page. 04471 04472 ControlArea - Supplies the control area for the prototype PTEs. 04473 04474 Return Value: 04475 04476 None. 04477 04478 --*/ 04479 04480 { 04481 KIRQL OldIrql; 04482 04483 LOCK_PFN (OldIrql); 04484 04485 MiMakeSystemAddressValidPfn (PointerPte); 04486 04487 MiInitializeTransitionPfn (PageFrameNumber, PointerPte, 0xFFFFFFFF); 04488 ControlArea->NumberOfPfnReferences += 1; 04489 04490 // 04491 // Add the page to the standby list. 04492 // 04493 04494 MiDecrementReferenceCount (PageFrameNumber); 04495 04496 UNLOCK_PFN (OldIrql); 04497 return; 04498 }

NTSTATUS MiVerifyImageHeader IN PIMAGE_NT_HEADERS  NtHeader,
IN PIMAGE_DOS_HEADER  DosHeader,
IN ULONG  NtHeaderSize
 

Definition at line 3295 of file creasect.c.

References MiCheckDosCalls(), PAGE_SIZE, PAGED_CODE, PCONFIGPHARLAP, PUSHORT, _PHARLAP_CONFIG::uchCopyRight, USHORT, _PHARLAP_CONFIG::usSign, and VALIDATE_NTHEADER.

Referenced by MiCreateImageFileMap().

03303 : 03304 03305 03306 Arguments: 03307 03308 Return Value: 03309 03310 Returns the status value. 03311 03312 TBS 03313 03314 --*/ 03315 03316 03317 03318 { 03319 PCONFIGPHARLAP PharLapConfigured; 03320 PUCHAR pb; 03321 LONG pResTableAddress; 03322 03323 PAGED_CODE(); 03324 03325 if (NtHeader->Signature != IMAGE_NT_SIGNATURE) { 03326 if ((USHORT)NtHeader->Signature == (USHORT)IMAGE_OS2_SIGNATURE) { 03327 03328 // 03329 // Check to see if this is a win-16 image. 03330 // 03331 03332 if ((!MiCheckDosCalls ((PIMAGE_OS2_HEADER)NtHeader, NtHeaderSize)) && 03333 ((((PIMAGE_OS2_HEADER)NtHeader)->ne_exetyp == 2) 03334 || 03335 ((((PIMAGE_OS2_HEADER)NtHeader)->ne_exetyp == 0) && 03336 (((((PIMAGE_OS2_HEADER)NtHeader)->ne_expver & 0xff00) == 03337 0x200) || 03338 ((((PIMAGE_OS2_HEADER)NtHeader)->ne_expver & 0xff00) == 03339 0x300))))) { 03340 03341 // 03342 // This is a win-16 image. 03343 // 03344 03345 return STATUS_INVALID_IMAGE_WIN_16; 03346 } 03347 03348 // The following OS/2 headers types go to NTDOS 03349 // 03350 // - exetype == 5 means binary is for Dos 4.0. 03351 // e.g Borland Dos extender type 03352 // 03353 // - OS/2 apps which have no import table entries 03354 // cannot be meant for the OS/2 ss. 03355 // e.g. QuickC for dos binaries 03356 // 03357 // - "old" Borland Dosx BC++ 3.x, Paradox 4.x 03358 // exe type == 1 03359 // DosHeader->e_cs * 16 + DosHeader->e_ip + 0x200 - 10 03360 // contains the string " mode EXE$" 03361 // but import table is empty, so we don't make special check 03362 // 03363 03364 if (((PIMAGE_OS2_HEADER)NtHeader)->ne_exetyp == 5 || 03365 ((PIMAGE_OS2_HEADER)NtHeader)->ne_enttab == 03366 ((PIMAGE_OS2_HEADER)NtHeader)->ne_imptab ) 03367 { 03368 return STATUS_INVALID_IMAGE_PROTECT; 03369 } 03370 03371 03372 // 03373 // Borland Dosx types: exe type 1 03374 // 03375 // - "new" Borland Dosx BP7.0 03376 // exe type == 1 03377 // DosHeader + 0x200 contains the string "16STUB" 03378 // 0x200 happens to be e_parhdr*16 03379 // 03380 03381 if (((PIMAGE_OS2_HEADER)NtHeader)->ne_exetyp == 1 && 03382 RtlEqualMemory((PUCHAR)DosHeader + 0x200, "16STUB", 6) ) 03383 { 03384 return STATUS_INVALID_IMAGE_PROTECT; 03385 } 03386 03387 // 03388 // Check for PharLap extended header which we run as a dos app. 03389 // The PharLap config block is pointed to by the SizeofHeader 03390 // field in the DosHdr. 03391 // The following algorithm for detecting a pharlap exe 03392 // was recommended by PharLap Software Inc. 03393 // 03394 03395 PharLapConfigured =(PCONFIGPHARLAP) ((PCHAR)DosHeader + 03396 ((ULONG)DosHeader->e_cparhdr << 4)); 03397 03398 if ((PCHAR)PharLapConfigured < 03399 (PCHAR)DosHeader + PAGE_SIZE - sizeof(CONFIGPHARLAP)) { 03400 if (RtlEqualMemory(&PharLapConfigured->uchCopyRight[0x18], 03401 "Phar Lap Software, Inc.", 24) && 03402 (PharLapConfigured->usSign == 0x4b50 || // stub loader type 2 03403 PharLapConfigured->usSign == 0x4f50 || // bindable 286|DosExtender 03404 PharLapConfigured->usSign == 0x5650 )) // bindable 286|DosExtender (Adv) 03405 { 03406 return STATUS_INVALID_IMAGE_PROTECT; 03407 } 03408 } 03409 03410 03411 03412 // 03413 // Check for Rational extended header which we run as a dos app. 03414 // We look for the rational copyright at: 03415 // wCopyRight = *(DosHeader->e_cparhdr*16 + 30h) 03416 // pCopyRight = wCopyRight + DosHeader->e_cparhdr*16 03417 // "Copyright (C) Rational Systems, Inc." 03418 // 03419 03420 pb = ((PUCHAR)DosHeader + ((ULONG)DosHeader->e_cparhdr << 4)); 03421 03422 if ((ULONG_PTR)pb < (ULONG_PTR)DosHeader + PAGE_SIZE - 0x30 - sizeof(USHORT)) { 03423 pb += *(PUSHORT)(pb + 0x30); 03424 if ( (ULONG_PTR)pb < (ULONG_PTR)DosHeader + PAGE_SIZE - 36 && 03425 RtlEqualMemory(pb, 03426 "Copyright (C) Rational Systems, Inc.", 03427 36) ) 03428 { 03429 return STATUS_INVALID_IMAGE_PROTECT; 03430 } 03431 } 03432 03433 // 03434 // Check for lotus 123 family of applications. Starting 03435 // with 123 3.0 (till recently shipped 123 3.4), every 03436 // exe header is bound but is meant for DOS. This can 03437 // be checked via, a string signature in the extended 03438 // header. <len byte>"1-2-3 Preloader" is the string 03439 // at ne_nrestab offset. 03440 // 03441 03442 pResTableAddress = ((PIMAGE_OS2_HEADER)NtHeader)->ne_nrestab; 03443 if (pResTableAddress > DosHeader->e_lfanew && 03444 ((ULONG)((pResTableAddress+16) - DosHeader->e_lfanew) < 03445 NtHeaderSize) && 03446 RtlEqualMemory( 03447 ((PUCHAR)NtHeader + 1 + 03448 (ULONG)(pResTableAddress - DosHeader->e_lfanew)), 03449 "1-2-3 Preloader", 03450 15) ) { 03451 return STATUS_INVALID_IMAGE_PROTECT; 03452 } 03453 03454 return STATUS_INVALID_IMAGE_NE_FORMAT; 03455 } 03456 03457 if ((USHORT)NtHeader->Signature == (USHORT)IMAGE_OS2_SIGNATURE_LE) { 03458 03459 // 03460 // This is a LE (OS/2) image. We don't support it, so give it to 03461 // DOS subsystem. There are cases (Rbase.exe) which have a LE 03462 // header but actually it is suppose to run under DOS. When we 03463 // do support LE format, some work needs to be done here to 03464 // decide whether to give it to VDM or OS/2. 03465 // 03466 03467 return STATUS_INVALID_IMAGE_PROTECT; 03468 } 03469 return STATUS_INVALID_IMAGE_PROTECT; 03470 } 03471 03472 if ((NtHeader->FileHeader.Machine == 0) && 03473 (NtHeader->FileHeader.SizeOfOptionalHeader == 0)) { 03474 03475 // 03476 // This is a bogus DOS app which has a 32-bit portion 03477 // masquerading as a PE image. 03478 // 03479 03480 return STATUS_INVALID_IMAGE_PROTECT; 03481 } 03482 03483 if (!(NtHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) { 03484 return STATUS_INVALID_IMAGE_FORMAT; 03485 } 03486 03487 #ifdef i386 03488 03489 // 03490 // Make sure the image header is aligned on a Long word boundary. 03491 // 03492 03493 if (((ULONG_PTR)NtHeader & 3) != 0) { 03494 return STATUS_INVALID_IMAGE_FORMAT; 03495 } 03496 #endif 03497 03498 #define VALIDATE_NTHEADER(Hdr) { \ 03499 /* File alignment must be multiple of 512 and power of 2. */ \ 03500 if (((((Hdr)->OptionalHeader).FileAlignment & 511) != 0) && \ 03501 (((Hdr)->OptionalHeader).FileAlignment != \ 03502 ((Hdr)->OptionalHeader).SectionAlignment)) { \ 03503 return STATUS_INVALID_IMAGE_FORMAT; \ 03504 } \ 03505 \ 03506 if (((Hdr)->OptionalHeader).FileAlignment == 0) { \ 03507 return STATUS_INVALID_IMAGE_FORMAT; \ 03508 } \ 03509 \ 03510 if (((((Hdr)->OptionalHeader).FileAlignment - 1) & \ 03511 ((Hdr)->OptionalHeader).FileAlignment) != 0) { \ 03512 return STATUS_INVALID_IMAGE_FORMAT; \ 03513 } \ 03514 \ 03515 if (((Hdr)->OptionalHeader).SectionAlignment < ((Hdr)->OptionalHeader).FileAlignment) { \ 03516 return STATUS_INVALID_IMAGE_FORMAT; \ 03517 } \ 03518 \ 03519 if (((Hdr)->OptionalHeader).SizeOfImage > MM_SIZE_OF_LARGEST_IMAGE) { \ 03520 return STATUS_INVALID_IMAGE_FORMAT; \ 03521 } \ 03522 \ 03523 if ((Hdr)->FileHeader.NumberOfSections > MM_MAXIMUM_IMAGE_SECTIONS) { \ 03524 return STATUS_INVALID_IMAGE_FORMAT; \ 03525 } \ 03526 } 03527 03528 if (NtHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) { 03529 // 03530 // Image doesn't have the right magic value in its optional header 03531 // 03532 #if defined (_WIN64) 03533 if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 03534 // 03535 // PE32 image. Validate it as such. 03536 // 03537 PIMAGE_NT_HEADERS32 NtHeader32 = (PIMAGE_NT_HEADERS32)NtHeader; 03538 03539 VALIDATE_NTHEADER(NtHeader32); 03540 return STATUS_SUCCESS; 03541 } 03542 #endif 03543 return STATUS_INVALID_IMAGE_FORMAT; 03544 } 03545 03546 VALIDATE_NTHEADER(NtHeader); 03547 #undef VALIDATE_NTHEADER 03548 03549 return STATUS_SUCCESS; 03550 }

NTSTATUS MmCreateSection OUT PVOID *  SectionObject,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
IN PLARGE_INTEGER  InputMaximumSize,
IN ULONG  SectionPageProtection,
IN ULONG  AllocationAttributes,
IN HANDLE FileHandle  OPTIONAL,
IN PFILE_OBJECT FileObject  OPTIONAL
 

Definition at line 390 of file creasect.c.

References ASSERT, CONTROL_AREA, _SEGMENT::ControlArea, DbgPrint, _CONTROL_AREA::DereferenceList, Event(), EX_REAL_POOL_USAGE, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), FALSE, File, _CONTROL_AREA::FilePointer, FSRTL_FSP_TOP_LEVEL_IRP, FsRtlAcquireFileExclusive(), FsRtlGetFileSize(), FsRtlReleaseFile(), _SECTION::InitialPageProtection, IoFileObjectType, IoSetTopLevelIrp(), KernelMode, KeSetEvent(), KeWaitForSingleObject(), KPROCESSOR_MODE, LARGE_CONTROL_AREA, LOCK_PFN, MI_UNUSED_SEGMENTS_REMOVE_CHARGE, MiCheckControlArea(), MiCreateDataFileMap(), MiCreateImageFileMap(), MiCreatePagingFileMap(), MiFindEmptySectionBaseDown(), MiFindImageSectionObject(), MiFlushDataSection(), MiFreeEventCounter(), MiGetEventCounter(), MiHydra, MiInsertBasedSection(), MiInsertImageSectionObject(), MiMakeProtectionMask(), MiRemoveImageSectionObject(), MM_DBG_SECTIONS, MM_DBG_SHOW_NT_CALLS, MMCONTROL, MmExtendSection(), MmHighSectionBase, MmMakeFileAccess, MmSectionBasedMutex, MmSectionBasedRoot, MmSectionObjectType, _CONTROL_AREA::ModifiedWriteCount, NonPagedPool, _CONTROL_AREA::NonPagedPoolUsage, NT_SUCCESS, NTSTATUS(), NULL, _CONTROL_AREA::NumberOfMappedViews, _CONTROL_AREA::NumberOfSectionReferences, _CONTROL_AREA::NumberOfSubsections, _CONTROL_AREA::NumberOfUserReferences, ObCreateObject(), ObDereferenceObject, ObjectAttributes, ObReferenceObject, ObReferenceObjectByHandle(), PERFINFO_SECTION_CREATE, PSECTION, SECTION, _CONTROL_AREA::Segment, _SECTION::Segment, _SECTION::SizeOfSection, _SEGMENT::SizeOfSegment, Status, SUBSECTION, _SEGMENT::TotalNumberOfPtes, TRUE, _SECTION::u, _CONTROL_AREA::u, UNLOCK_PFN, _CONTROL_AREA::WaitingForDeletion, and WrVirtualMemory.

Referenced by CcInitializeCacheMap(), MiCrashDumpWorker(), and NtCreateSection().

00403 : 00404 00405 This function creates a section object and opens a handle to the object 00406 with the specified desired access. 00407 00408 Arguments: 00409 00410 Section - A pointer to a variable that will 00411 receive the section object address. 00412 00413 DesiredAccess - The desired types of access for the section. 00414 00415 DesiredAccess Flags 00416 00417 EXECUTE - Execute access to the section is desired. 00418 00419 READ - Read access to the section is desired. 00420 00421 WRITE - Write access to the section is desired. 00422 00423 ObjectAttributes - Supplies a pointer to an object attributes structure. 00424 00425 InputMaximumSize - Supplies the maximum size of the section in bytes. 00426 This value is rounded up to the host page size and 00427 specifies the size of the section (page file 00428 backed section) or the maximum size to which a 00429 file can be extended or mapped (file backed 00430 section). 00431 00432 SectionPageProtection - Supplies the protection to place on each page 00433 in the section. One of PAGE_READ, PAGE_READWRITE, 00434 PAGE_EXECUTE, or PAGE_WRITECOPY and, optionally, 00435 PAGE_NOCACHE may be specified. 00436 00437 AllocationAttributes - Supplies a set of flags that describe the 00438 allocation attributes of the section. 00439 00440 AllocationAttributes Flags 00441 00442 SEC_BASED - The section is a based section and will be 00443 allocated at the same virtual address in each process 00444 address space that receives the section. This does not 00445 imply that addresses are reserved for based sections. 00446 Rather if the section cannot be mapped at the based address 00447 an error is returned. 00448 00449 SEC_RESERVE - All pages of the section are set to the 00450 reserved state. 00451 00452 SEC_COMMIT - All pages of the section are set to the commit state. 00453 00454 SEC_IMAGE - The file specified by the file handle is an 00455 executable image file. 00456 00457 SEC_FILE - The file specified by the file handle is a mapped 00458 file. If a file handle is supplied and neither 00459 SEC_IMAGE or SEC_FILE is supplied, SEC_FILE is 00460 assumed. 00461 00462 FileHandle - Supplies an optional handle of an open file object. 00463 If the value of this handle is null, then the 00464 section will be backed by a paging file. Otherwise 00465 the section is backed by the specified data file. 00466 00467 FileObject - Supplies an optional pointer to the file object. If this 00468 value is NULL and the FileHandle is NULL, then there is 00469 no file to map (image or mapped file). If this value 00470 is specified, then the File is to be mapped as a MAPPED FILE 00471 and NO file size checking will be performed. 00472 00473 ONLY THE SYSTEM CACHE SHOULD PROVIDE A FILE OBJECT WITH THE 00474 CALL!! as this is optimized to not check the size, only do 00475 data mapping, no protection check, etc. 00476 00477 Note - Only one of FileHandle or File should be specified! 00478 00479 Return Value: 00480 00481 Returns the relevant NTSTATUS code. 00482 00483 --*/ 00484 00485 { 00486 SECTION Section; 00487 PSECTION NewSection; 00488 PSEGMENT Segment; 00489 PSEGMENT NewSegment; 00490 KPROCESSOR_MODE PreviousMode; 00491 KIRQL OldIrql; 00492 NTSTATUS Status; 00493 PCONTROL_AREA ControlArea; 00494 PCONTROL_AREA NewControlArea; 00495 PCONTROL_AREA SegmentControlArea; 00496 ACCESS_MASK FileDesiredAccess; 00497 PFILE_OBJECT File; 00498 PEVENT_COUNTER Event; 00499 ULONG IgnoreFileSizing; 00500 ULONG ProtectionMask; 00501 ULONG ProtectMaskForAccess; 00502 ULONG FileAcquired; 00503 PEVENT_COUNTER SegmentEvent; 00504 BOOLEAN FileSizeChecked; 00505 LARGE_INTEGER TempSectionSize; 00506 UINT64 EndOfFile; 00507 ULONG IncrementedRefCount; 00508 ULONG ControlAreaSize; 00509 PUINT64 MaximumSize; 00510 PMMADDRESS_NODE *SectionBasedRoot; 00511 BOOLEAN GlobalNeeded; 00512 PFILE_OBJECT ChangeFileReference; 00513 #if DBG 00514 PVOID PreviousSectionPointer; 00515 #endif //DBG 00516 00517 DesiredAccess; 00518 00519 IgnoreFileSizing = FALSE; 00520 FileAcquired = FALSE; 00521 FileSizeChecked = FALSE; 00522 IncrementedRefCount = FALSE; 00523 ChangeFileReference = NULL; 00524 00525 MaximumSize = (PUINT64) InputMaximumSize; 00526 00527 #if DBG 00528 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00529 if ( !MmWatchProcess ) { 00530 DbgPrint("crea sect access mask %lx maxsize %I64X page prot %lx\n", 00531 DesiredAccess, *MaximumSize, SectionPageProtection); 00532 DbgPrint(" allocation attributes %lx file handle %lx\n", 00533 AllocationAttributes, FileHandle); 00534 } 00535 } 00536 #endif 00537 00538 // 00539 // Check allocation attributes flags. 00540 // 00541 00542 File = (PFILE_OBJECT)NULL; 00543 00544 ASSERT ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 00545 SEC_IMAGE | SEC_NOCACHE | SEC_NO_CHANGE)) == 0); 00546 00547 ASSERT ((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0); 00548 00549 ASSERT (!((AllocationAttributes & SEC_IMAGE) && 00550 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | 00551 SEC_NOCACHE | SEC_NO_CHANGE)))); 00552 00553 ASSERT (!((AllocationAttributes & SEC_COMMIT) && 00554 (AllocationAttributes & SEC_RESERVE))); 00555 00556 ASSERT (!((SectionPageProtection & PAGE_NOCACHE) || 00557 (SectionPageProtection & PAGE_GUARD) || 00558 (SectionPageProtection & PAGE_NOACCESS))); 00559 00560 if (AllocationAttributes & SEC_NOCACHE) { 00561 SectionPageProtection |= PAGE_NOCACHE; 00562 } 00563 00564 // 00565 // Check the protection field. This could raise an exception. 00566 // 00567 00568 try { 00569 ProtectionMask = MiMakeProtectionMask (SectionPageProtection); 00570 } except (EXCEPTION_EXECUTE_HANDLER) { 00571 return GetExceptionCode(); 00572 } 00573 00574 ProtectMaskForAccess = ProtectionMask & 0x7; 00575 00576 FileDesiredAccess = MmMakeFileAccess[ProtectMaskForAccess]; 00577 00578 // 00579 // Get previous processor mode and probe output arguments if necessary. 00580 // 00581 00582 PreviousMode = KeGetPreviousMode(); 00583 00584 Section.InitialPageProtection = SectionPageProtection; 00585 Section.Segment = (PSEGMENT)NULL; 00586 00587 if (ARGUMENT_PRESENT(FileHandle) || ARGUMENT_PRESENT(FileObject)) { 00588 00589 if (ARGUMENT_PRESENT(FileObject)) { 00590 IgnoreFileSizing = TRUE; 00591 File = FileObject; 00592 00593 // 00594 // Quick check to see if a control area already exists. 00595 // 00596 00597 if (File->SectionObjectPointer->DataSectionObject) { 00598 00599 LOCK_PFN (OldIrql); 00600 ControlArea = 00601 (PCONTROL_AREA)(File->SectionObjectPointer->DataSectionObject); 00602 00603 if ((ControlArea != NULL) && 00604 (!ControlArea->u.Flags.BeingDeleted) && 00605 (!ControlArea->u.Flags.BeingCreated)) { 00606 00607 // 00608 // Control area exists and is not being deleted, 00609 // reference it. 00610 // 00611 00612 NewSegment = ControlArea->Segment; 00613 if ((ControlArea->NumberOfSectionReferences == 0) && 00614 (ControlArea->NumberOfMappedViews == 0) && 00615 (ControlArea->ModifiedWriteCount == 0)) { 00616 00617 // 00618 // Dereference the current file object and 00619 // reference this one. 00620 // 00621 00622 ChangeFileReference = ControlArea->FilePointer; 00623 ControlArea->FilePointer = FileObject; 00624 00625 // 00626 // This dereference is purposely at DPC_LEVEL 00627 // so the object manager queues it to another 00628 // thread thereby eliminating deadlocks with 00629 // the redirector. 00630 // 00631 00632 ObDereferenceObject (ChangeFileReference); 00633 } 00634 ControlArea->u.Flags.Accessed = 1; 00635 ControlArea->NumberOfSectionReferences += 1; 00636 if (ControlArea->DereferenceList.Flink != NULL) { 00637 00638 // 00639 // Remove this from the list of unused segments. 00640 // 00641 00642 RemoveEntryList (&ControlArea->DereferenceList); 00643 00644 MI_UNUSED_SEGMENTS_REMOVE_CHARGE (ControlArea); 00645 00646 ControlArea->DereferenceList.Flink = NULL; 00647 ControlArea->DereferenceList.Blink = NULL; 00648 } 00649 UNLOCK_PFN (OldIrql); 00650 IncrementedRefCount = TRUE; 00651 Section.SizeOfSection.QuadPart = (LONGLONG)*MaximumSize; 00652 00653 goto ReferenceObject; 00654 } 00655 UNLOCK_PFN (OldIrql); 00656 } 00657 00658 ObReferenceObject (FileObject); 00659 00660 } else { 00661 00662 // 00663 // Only one of FileHandle or FileObject should be supplied 00664 // if a FileObject is supplied, this must be from the 00665 // file system and therefore the file's size should not 00666 // be checked. 00667 // 00668 00669 Status = ObReferenceObjectByHandle ( FileHandle, 00670 FileDesiredAccess, 00671 IoFileObjectType, 00672 PreviousMode, 00673 (PVOID *)&File, 00674 NULL ); 00675 if (!NT_SUCCESS(Status)) { 00676 return Status; 00677 } 00678 00679 // 00680 // If this file doesn't have a section object pointer, 00681 // return an error. 00682 // 00683 00684 if (File->SectionObjectPointer == NULL) { 00685 ObDereferenceObject (File); 00686 return STATUS_INVALID_FILE_FOR_SECTION; 00687 } 00688 } 00689 00690 // 00691 // Check to see if the specified file already has a section. 00692 // If not, indicate in the file object's pointer to an FCB that 00693 // a section is being built. This synchronizes segment creation 00694 // for the file. 00695 // 00696 00697 if (MiHydra == TRUE && (AllocationAttributes & SEC_IMAGE)) { 00698 00699 // 00700 // This control area is always just a place holder - the real one 00701 // is allocated in MiCreateImageFileMap and will be allocated 00702 // with the correct size and this one freed in a short while. 00703 // 00704 // This place holder must always be allocated as a large control 00705 // area so that it can be chained for the per-session case. 00706 // 00707 // This may need revisiting for wx86. 00708 // 00709 00710 ControlAreaSize = (ULONG)sizeof(LARGE_CONTROL_AREA) + 00711 (ULONG)sizeof(SUBSECTION); 00712 } 00713 else { 00714 ControlAreaSize = (ULONG)sizeof(CONTROL_AREA) + 00715 (ULONG)sizeof(SUBSECTION); 00716 } 00717 00718 NewControlArea = ExAllocatePoolWithTag (NonPagedPool, 00719 ControlAreaSize, 00720 MMCONTROL); 00721 00722 if (NewControlArea == NULL) { 00723 ObDereferenceObject (File); 00724 return STATUS_INSUFFICIENT_RESOURCES; 00725 } 00726 00727 RtlZeroMemory (NewControlArea, ControlAreaSize); 00728 00729 NewControlArea->NonPagedPoolUsage = EX_REAL_POOL_USAGE(ControlAreaSize); 00730 00731 NewSegment = (PSEGMENT)NULL; 00732 00733 // 00734 // We only need the file resource if the was a user request, i.e. not 00735 // a call from the cache manager or file system. 00736 // 00737 00738 if (ARGUMENT_PRESENT(FileHandle)) { 00739 00740 FsRtlAcquireFileExclusive (File); 00741 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 00742 FileAcquired = TRUE; 00743 } 00744 00745 LOCK_PFN (OldIrql); 00746 00747 // 00748 // Allocate an event to wait on in case the segment is in the 00749 // process of being deleted. This event cannot be allocated 00750 // with the PFN database locked as pool expansion would deadlock. 00751 // 00752 00753 ReallocateandcheckSegment: 00754 00755 SegmentEvent = MiGetEventCounter(); 00756 00757 if (SegmentEvent == NULL) { 00758 UNLOCK_PFN (OldIrql); 00759 if (FileAcquired) { 00760 IoSetTopLevelIrp((PIRP)NULL); 00761 FsRtlReleaseFile (File); 00762 } 00763 ExFreePool (NewControlArea); 00764 ObDereferenceObject (File); 00765 return STATUS_INSUFFICIENT_RESOURCES; 00766 } 00767 00768 RecheckSegment: 00769 00770 if (AllocationAttributes & SEC_IMAGE) { 00771 00772 if (MiHydra == TRUE) { 00773 ControlArea = MiFindImageSectionObject (File, &GlobalNeeded); 00774 } 00775 else { 00776 ControlArea = 00777 (PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject); 00778 } 00779 } else { 00780 ControlArea = 00781 (PCONTROL_AREA)(File->SectionObjectPointer->DataSectionObject); 00782 } 00783 00784 if (ControlArea != NULL) { 00785 00786 // 00787 // A segment already exists for this file. Make sure that it 00788 // is not in the process of being deleted, or being created. 00789 // 00790 00791 00792 if ((ControlArea->u.Flags.BeingDeleted) || 00793 (ControlArea->u.Flags.BeingCreated)) { 00794 00795 // 00796 // The segment object is in the process of being deleted or 00797 // created. 00798 // Check to see if another thread is waiting for the deletion, 00799 // otherwise create an event object to wait upon. 00800 // 00801 00802 if (ControlArea->WaitingForDeletion == NULL) { 00803 00804 // 00805 // Initialize an event and put its address in the control area. 00806 // 00807 00808 ControlArea->WaitingForDeletion = SegmentEvent; 00809 Event = SegmentEvent; 00810 SegmentEvent = NULL; 00811 } else { 00812 Event = ControlArea->WaitingForDeletion; 00813 Event->RefCount += 1; 00814 } 00815 00816 // 00817 // Release the pfn lock, the file lock, and wait for the event. 00818 // 00819 00820 UNLOCK_PFN (OldIrql); 00821 if (FileAcquired) { 00822 IoSetTopLevelIrp((PIRP)NULL); 00823 FsRtlReleaseFile (File); 00824 } 00825 00826 KeWaitForSingleObject(&Event->Event, 00827 WrVirtualMemory, 00828 KernelMode, 00829 FALSE, 00830 (PLARGE_INTEGER)NULL); 00831 00832 if (FileAcquired) { 00833 FsRtlAcquireFileExclusive (File); 00834 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 00835 } 00836 00837 LOCK_PFN (OldIrql); 00838 MiFreeEventCounter (Event, TRUE); 00839 00840 if (SegmentEvent == NULL) { 00841 00842 // 00843 // The event was freed from pool, allocate another 00844 // event in case we have to synchronize one more time. 00845 // 00846 00847 goto ReallocateandcheckSegment; 00848 } 00849 goto RecheckSegment; 00850 00851 } else { 00852 00853 // 00854 // There is already a segment for this file, have 00855 // this section refer to that segment. 00856 // No need to reference the file object any more. 00857 // 00858 00859 NewSegment = ControlArea->Segment; 00860 ControlArea->u.Flags.Accessed = 1; 00861 ControlArea->NumberOfSectionReferences += 1; 00862 if (ControlArea->DereferenceList.Flink != NULL) { 00863 00864 // 00865 // Remove this from the list of unused segments. 00866 // 00867 00868 RemoveEntryList (&ControlArea->DereferenceList); 00869 00870 MI_UNUSED_SEGMENTS_REMOVE_CHARGE (ControlArea); 00871 00872 ControlArea->DereferenceList.Flink = NULL; 00873 ControlArea->DereferenceList.Blink = NULL; 00874 } 00875 IncrementedRefCount = TRUE; 00876 00877 // 00878 // If this reference was not from the cache manager 00879 // up the count of user references. 00880 // 00881 00882 if (IgnoreFileSizing == FALSE) { 00883 ControlArea->NumberOfUserReferences += 1; 00884 } 00885 } 00886 } else { 00887 00888 // 00889 // There is no segment associated with this file object. 00890 // Set the file object to refer to the new control area. 00891 // 00892 00893 ControlArea = NewControlArea; 00894 ControlArea->u.Flags.BeingCreated = 1; 00895 00896 if (AllocationAttributes & SEC_IMAGE) { 00897 if (MiHydra == TRUE) { 00898 if (GlobalNeeded == TRUE) { 00899 ControlArea->u.Flags.GlobalOnlyPerSession = 1; 00900 } 00901 00902 MiInsertImageSectionObject (File, ControlArea); 00903 } 00904 else { 00905 ((PCONTROL_AREA)((File->SectionObjectPointer->ImageSectionObject))) = 00906 ControlArea; 00907 } 00908 } else { 00909 #if DBG 00910 PreviousSectionPointer = File->SectionObjectPointer; 00911 #endif //DBG 00912 ((PCONTROL_AREA)((File->SectionObjectPointer->DataSectionObject))) = 00913 ControlArea; 00914 } 00915 } 00916 00917 if (SegmentEvent != NULL) { 00918 MiFreeEventCounter (SegmentEvent, TRUE); 00919 } 00920 00921 UNLOCK_PFN (OldIrql); 00922 00923 if (NewSegment != (PSEGMENT)NULL) { 00924 00925 // 00926 // Whether we created a segment or not, flush the data section 00927 // if there is one. 00928 // 00929 00930 if (AllocationAttributes & SEC_IMAGE) { 00931 MiFlushDataSection (File); 00932 } 00933 00934 // 00935 // A segment already exists for this file object. 00936 // Deallocate the new control area as it is no longer required. 00937 // Dereference the file object later when we're done with it. 00938 // 00939 00940 ExFreePool (NewControlArea); 00941 00942 // 00943 // The section is in paged pool, this can't be set until 00944 // the PFN mutex has been released. 00945 // 00946 00947 if ((!IgnoreFileSizing) && (ControlArea->u.Flags.Image == 0)) { 00948 00949 // 00950 // The file size in the segment may not match the current 00951 // file size, query the file system and get the file 00952 // size. 00953 // 00954 00955 Status = FsRtlGetFileSize (File, (PLARGE_INTEGER)&EndOfFile ); 00956 00957 if (!NT_SUCCESS (Status)) { 00958 00959 if (FileAcquired) { 00960 IoSetTopLevelIrp((PIRP)NULL); 00961 FsRtlReleaseFile (File); 00962 FileAcquired = FALSE; 00963 } 00964 00965 ObDereferenceObject (File); 00966 goto UnrefAndReturn; 00967 } 00968 00969 if (EndOfFile == 0 && *MaximumSize == 0) { 00970 00971 // 00972 // Can't map a zero length without specifying the maximum 00973 // size as non-zero. 00974 // 00975 00976 Status = STATUS_MAPPED_FILE_SIZE_ZERO; 00977 00978 if (FileAcquired) { 00979 IoSetTopLevelIrp((PIRP)NULL); 00980 FsRtlReleaseFile (File); 00981 FileAcquired = FALSE; 00982 } 00983 00984 ObDereferenceObject (File); 00985 goto UnrefAndReturn; 00986 } 00987 } else { 00988 00989 // 00990 // The size is okay in the segment. 00991 // 00992 00993 EndOfFile = (UINT64) NewSegment->SizeOfSegment; 00994 } 00995 00996 if (FileAcquired) { 00997 IoSetTopLevelIrp((PIRP)NULL); 00998 FsRtlReleaseFile (File); 00999 FileAcquired = FALSE; 01000 } 01001 01002 ObDereferenceObject (File); 01003 01004 if (*MaximumSize == 0) { 01005 01006 Section.SizeOfSection.QuadPart = (LONGLONG)EndOfFile; 01007 FileSizeChecked = TRUE; 01008 01009 } else if (EndOfFile >= *MaximumSize) { 01010 01011 // 01012 // EndOfFile is greater than the MaximumSize, 01013 // use the specified maximum size. 01014 // 01015 01016 Section.SizeOfSection.QuadPart = (LONGLONG)*MaximumSize; 01017 FileSizeChecked = TRUE; 01018 01019 } else { 01020 01021 // 01022 // Need to extend the section, make sure the file was 01023 // opened for write access. 01024 // 01025 01026 if (((SectionPageProtection & PAGE_READWRITE) | 01027 (SectionPageProtection & PAGE_EXECUTE_READWRITE)) == 0) { 01028 01029 Status = STATUS_SECTION_TOO_BIG; 01030 goto UnrefAndReturn; 01031 } 01032 Section.SizeOfSection.QuadPart = (LONGLONG)*MaximumSize; 01033 } 01034 01035 } else { 01036 01037 // 01038 // The file does not have an associated segment, create a segment 01039 // object. 01040 // 01041 01042 if (AllocationAttributes & SEC_IMAGE) { 01043 01044 Status = MiCreateImageFileMap (File, &Segment); 01045 01046 } else { 01047 01048 Status = MiCreateDataFileMap (File, 01049 &Segment, 01050 MaximumSize, 01051 SectionPageProtection, 01052 AllocationAttributes, 01053 IgnoreFileSizing ); 01054 ASSERT (PreviousSectionPointer == File->SectionObjectPointer); 01055 } 01056 01057 if (!NT_SUCCESS(Status)) { 01058 01059 // 01060 // Lock the PFN database and check to see if another thread has 01061 // tried to create a segment to the file object at the same 01062 // time. 01063 // 01064 01065 LOCK_PFN (OldIrql); 01066 01067 Event = ControlArea->WaitingForDeletion; 01068 ControlArea->WaitingForDeletion = NULL; 01069 ASSERT (ControlArea->u.Flags.FilePointerNull == 0); 01070 ControlArea->u.Flags.FilePointerNull = 1; 01071 01072 if (AllocationAttributes & SEC_IMAGE) { 01073 if (MiHydra == TRUE) { 01074 MiRemoveImageSectionObject (File, ControlArea); 01075 } 01076 else { 01077 (PCONTROL_AREA)((File->SectionObjectPointer->ImageSectionObject)) = 01078 NULL; 01079 } 01080 } else { 01081 (PCONTROL_AREA)((File->SectionObjectPointer->DataSectionObject)) = 01082 NULL; 01083 } 01084 ControlArea->u.Flags.BeingCreated = 0; 01085 01086 UNLOCK_PFN (OldIrql); 01087 01088 if (FileAcquired) { 01089 IoSetTopLevelIrp((PIRP)NULL); 01090 FsRtlReleaseFile (File); 01091 } 01092 01093 ExFreePool (NewControlArea); 01094 01095 ObDereferenceObject (File); 01096 01097 if (Event != NULL) { 01098 01099 // 01100 // Signal any waiters that the segment structure exists. 01101 // 01102 01103 KeSetEvent (&Event->Event, 0, FALSE); 01104 } 01105 01106 return Status; 01107 } 01108 01109 // 01110 // If the size was specified as zero, set the section size 01111 // from the created segment size. This solves problems with 01112 // race conditions when multiple sections 01113 // are created for the same mapped file with varying sizes. 01114 // 01115 01116 if (*MaximumSize == 0) { 01117 Section.SizeOfSection.QuadPart = (LONGLONG)Segment->SizeOfSegment; 01118 } else { 01119 Section.SizeOfSection.QuadPart = (LONGLONG)*MaximumSize; 01120 } 01121 } 01122 01123 } else { 01124 01125 // 01126 // No file handle exists, this is a page file backed section. 01127 // 01128 01129 if (AllocationAttributes & SEC_IMAGE) { 01130 return STATUS_INVALID_FILE_FOR_SECTION; 01131 } 01132 01133 Status = MiCreatePagingFileMap ( &NewSegment, 01134 MaximumSize, 01135 ProtectionMask, 01136 AllocationAttributes); 01137 01138 if (!NT_SUCCESS(Status)) { 01139 return Status; 01140 } 01141 01142 // 01143 // Set the section size from the created segment size. This 01144 // solves problems with race conditions when multiple sections 01145 // are created for the same mapped file with varying sizes. 01146 // 01147 01148 Section.SizeOfSection.QuadPart = (LONGLONG)NewSegment->SizeOfSegment; 01149 ControlArea = NewSegment->ControlArea; 01150 } 01151 01152 #if DBG 01153 if (MmDebug & MM_DBG_SECTIONS) { 01154 if (NewSegment == (PSEGMENT)NULL) { 01155 DbgPrint("inserting segment %lx control %lx\n",Segment, 01156 Segment->ControlArea); 01157 } else { 01158 DbgPrint("inserting segment %lx control %lx\n",NewSegment, 01159 NewSegment->ControlArea); 01160 } 01161 } 01162 #endif 01163 01164 01165 if (NewSegment == (PSEGMENT)NULL) { 01166 NewSegment = Segment; 01167 01168 // 01169 // Lock the PFN database and check to see if another thread has 01170 // tried to create a segment to the file object at the same time. 01171 // 01172 01173 SegmentControlArea = Segment->ControlArea; 01174 01175 ASSERT (File != NULL); 01176 01177 LOCK_PFN (OldIrql); 01178 01179 Event = ControlArea->WaitingForDeletion; 01180 ControlArea->WaitingForDeletion = NULL; 01181 01182 if (AllocationAttributes & SEC_IMAGE) { 01183 01184 // 01185 // Change the control area in the file object pointer. 01186 // 01187 01188 if (MiHydra == TRUE) { 01189 MiRemoveImageSectionObject (File, NewControlArea); 01190 MiInsertImageSectionObject (File, SegmentControlArea); 01191 } 01192 else { 01193 ((PCONTROL_AREA)(File->SectionObjectPointer->ImageSectionObject)) = 01194 SegmentControlArea; 01195 } 01196 01197 ControlArea = SegmentControlArea; 01198 } 01199 01200 ControlArea->u.Flags.BeingCreated = 0; 01201 01202 UNLOCK_PFN (OldIrql); 01203 01204 if (AllocationAttributes & SEC_IMAGE) { 01205 01206 // 01207 // Deallocate the pool used for the original control area. 01208 // 01209 01210 ExFreePool (NewControlArea); 01211 } 01212 01213 if (Event != NULL) { 01214 01215 // 01216 // Signal any waiters that the segment structure exists. 01217 // 01218 01219 KeSetEvent (&Event->Event, 0, FALSE); 01220 } 01221 01222 PERFINFO_SECTION_CREATE(ControlArea); 01223 } 01224 01225 // 01226 // Being created has now been cleared allowing other threads 01227 // to reference the segment. Release the resource on the file. 01228 // 01229 01230 if (FileAcquired) { 01231 IoSetTopLevelIrp((PIRP)NULL); 01232 FsRtlReleaseFile (File); 01233 FileAcquired = FALSE; 01234 } 01235 01236 ReferenceObject: 01237 01238 if (ChangeFileReference) { 01239 ObReferenceObject (FileObject); 01240 } 01241 01242 // 01243 // Now that the segment object is created, make the section object 01244 // refer to the segment object. 01245 // 01246 01247 Section.Segment = NewSegment; 01248 Section.u.LongFlags = ControlArea->u.LongFlags; 01249 01250 // 01251 // Create the section object now. The section object is created 01252 // now so that the error handling when the section object cannot 01253 // be created is simplified. 01254 // 01255 01256 Status = ObCreateObject (PreviousMode, 01257 MmSectionObjectType, 01258 ObjectAttributes, 01259 PreviousMode, 01260 NULL, 01261 sizeof(SECTION), 01262 sizeof(SECTION) + 01263 NewSegment->TotalNumberOfPtes * sizeof(MMPTE), 01264 sizeof(CONTROL_AREA) + 01265 NewSegment->ControlArea->NumberOfSubsections * 01266 sizeof(SUBSECTION), 01267 (PVOID *)&NewSection); 01268 01269 if (!NT_SUCCESS(Status)) { 01270 goto UnrefAndReturn; 01271 } 01272 01273 RtlMoveMemory (NewSection, &Section, sizeof(SECTION)); 01274 NewSection->Address.StartingVpn = 0; 01275 01276 if (!IgnoreFileSizing) { 01277 01278 // 01279 // Indicate that the cache manager is not the owner of this 01280 // section. 01281 // 01282 01283 NewSection->u.Flags.UserReference = 1; 01284 01285 if (AllocationAttributes & SEC_NO_CHANGE) { 01286 01287 // 01288 // Indicate that once the section is mapped, no protection 01289 // changes or freeing the mapping is allowed. 01290 // 01291 01292 NewSection->u.Flags.NoChange = 1; 01293 } 01294 01295 if (((SectionPageProtection & PAGE_READWRITE) | 01296 (SectionPageProtection & PAGE_EXECUTE_READWRITE)) == 0) { 01297 01298 // 01299 // This section does not support WRITE access, indicate 01300 // that changing the protection to WRITE results in COPY_ON_WRITE. 01301 // 01302 01303 NewSection->u.Flags.CopyOnWrite = 1; 01304 } 01305 01306 if (AllocationAttributes & SEC_BASED) { 01307 01308 NewSection->u.Flags.Based = 1; 01309 01310 SectionBasedRoot = &MmSectionBasedRoot; 01311 01312 // 01313 // Get the allocation base mutex. 01314 // 01315 01316 ExAcquireFastMutex (&MmSectionBasedMutex); 01317 01318 // 01319 // This section is based at a unique address system wide. 01320 // 01321 01322 try { 01323 NewSection->Address.StartingVpn = (ULONG_PTR)MiFindEmptySectionBaseDown ( 01324 NewSection->SizeOfSection.LowPart, 01325 MmHighSectionBase); 01326 01327 } except (EXCEPTION_EXECUTE_HANDLER) { 01328 ExReleaseFastMutex (&MmSectionBasedMutex); 01329 ObDereferenceObject (NewSection); 01330 return Status; 01331 } 01332 01333 NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + 01334 NewSection->SizeOfSection.LowPart - 1; 01335 01336 MiInsertBasedSection (NewSection); 01337 ExReleaseFastMutex (&MmSectionBasedMutex); 01338 } 01339 } 01340 01341 // 01342 // If the cache manager is creating the section, set the was 01343 // purged flag as the file size can change. 01344 // 01345 01346 ControlArea->u.Flags.WasPurged |= IgnoreFileSizing; 01347 01348 // 01349 // Check to see if the section is for a data file and the size 01350 // of the section is greater than the current size of the 01351 // segment. 01352 // 01353 01354 if (((ControlArea->u.Flags.WasPurged == 1) && (!IgnoreFileSizing)) && 01355 (!FileSizeChecked) 01356 || 01357 ((UINT64)NewSection->SizeOfSection.QuadPart > 01358 NewSection->Segment->SizeOfSegment)) { 01359 01360 TempSectionSize = NewSection->SizeOfSection; 01361 01362 NewSection->SizeOfSection.QuadPart = (LONGLONG)NewSection->Segment->SizeOfSegment; 01363 01364 // 01365 // Even if the caller didn't specify extension rights, we enable it here 01366 // temporarily to make the section correct. Use a temporary section 01367 // instead of temporarily editing the real section to avoid opening 01368 // a security window that other concurrent threads could exploit. 01369 // 01370 01371 if (((NewSection->InitialPageProtection & PAGE_READWRITE) | 01372 (NewSection->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) { 01373 SECTION WritableSection; 01374 01375 *(PSECTION)&WritableSection = *NewSection; 01376 01377 Status = MmExtendSection (&WritableSection, 01378 &TempSectionSize, 01379 IgnoreFileSizing); 01380 01381 NewSection->SizeOfSection = WritableSection.SizeOfSection; 01382 } 01383 else { 01384 Status = MmExtendSection (NewSection, 01385 &TempSectionSize, 01386 IgnoreFileSizing); 01387 } 01388 01389 if (!NT_SUCCESS(Status)) { 01390 ObDereferenceObject (NewSection); 01391 return Status; 01392 } 01393 } 01394 01395 *SectionObject = (PVOID)NewSection; 01396 01397 return Status; 01398 01399 UnrefAndReturn: 01400 01401 // 01402 // Unreference the control area, if it was referenced and return 01403 // the error status. 01404 // 01405 01406 if (FileAcquired) { 01407 IoSetTopLevelIrp((PIRP)NULL); 01408 FsRtlReleaseFile (File); 01409 } 01410 01411 if (IncrementedRefCount) { 01412 LOCK_PFN (OldIrql); 01413 ControlArea->NumberOfSectionReferences -= 1; 01414 if (!IgnoreFileSizing) { 01415 ASSERT ((LONG)ControlArea->NumberOfUserReferences > 0); 01416 ControlArea->NumberOfUserReferences -= 1; 01417 } 01418 MiCheckControlArea (ControlArea, NULL, OldIrql); 01419 } 01420 return Status; 01421 }

NTSTATUS NtCreateSection OUT PHANDLE  SectionHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
IN PLARGE_INTEGER MaximumSize  OPTIONAL,
IN ULONG  SectionPageProtection,
IN ULONG  AllocationAttributes,
IN HANDLE FileHandle  OPTIONAL
 

Definition at line 134 of file creasect.c.

References ASSERT, CcZeroEndOfLastPage(), _SEGMENT::ControlArea, DbgPrint, DISPATCH_LEVEL, EXCEPTION_EXECUTE_HANDLER, FALSE, _CONTROL_AREA::FilePointer, Handle, KeDelayExecutionThread(), KernelMode, MM_DBG_SECTIONS, MM_DBG_SHOW_NT_CALLS, MmCreateSection(), MmHalfSecond, NT_SUCCESS, NTSTATUS(), NULL, ObInsertObject(), ObjectAttributes, ProbeForRead, ProbeForWriteHandle, PSECTION, _CONTROL_AREA::Segment, Status, and ZERO_LARGE.

Referenced by CreateConsoleBitmap(), CsrpConnectToServer(), LdrLoadAlternateResourceModule(), LdrpCheckForLoadedDll(), LdrpCreateDllSection(), LdrVerifyImageMatchesChecksum(), main(), MapViewOfSection(), NapCreateDataSection(), PropertiesDlgShow(), RtlCreateQueryDebugBuffer(), ServerHandleConnectionRequest(), and TestParent().

00146 : 00147 00148 This function creates a section object and opens a handle to the object 00149 with the specified desired access. 00150 00151 Arguments: 00152 00153 SectionHandle - A pointer to a variable that will 00154 receive the section object handle value. 00155 00156 DesiredAccess - The desired types of access for the section. 00157 00158 DesiredAccess Flags 00159 00160 EXECUTE - Execute access to the section is 00161 desired. 00162 00163 READ - Read access to the section is desired. 00164 00165 WRITE - Write access to the section is desired. 00166 00167 00168 ObjectAttributes - Supplies a pointer to an object attributes structure. 00169 00170 MaximumSize - Supplies the maximum size of the section in bytes. 00171 This value is rounded up to the host page size and 00172 specifies the size of the section (page file 00173 backed section) or the maximum size to which a 00174 file can be extended or mapped (file backed 00175 section). 00176 00177 SectionPageProtection - Supplies the protection to place on each page 00178 in the section. One of PAGE_READ, PAGE_READWRITE, PAGE_EXECUTE, 00179 or PAGE_WRITECOPY and, optionally, PAGE_NOCACHE may be specified. 00180 00181 AllocationAttributes - Supplies a set of flags that describe the 00182 allocation attributes of the section. 00183 00184 AllocationAttributes Flags 00185 00186 SEC_BASED - The section is a based section and will be 00187 allocated at the same virtual address in each process 00188 address space that receives the section. This does not 00189 imply that addresses are reserved for based sections. 00190 Rather if the section cannot be mapped at the based address 00191 an error is returned. 00192 00193 00194 SEC_RESERVE - All pages of the section are set to the 00195 reserved state. 00196 00197 SEC_COMMIT - All pages of the section are set to the commit 00198 state. 00199 00200 SEC_IMAGE - The file specified by the file handle is an 00201 executable image file. 00202 00203 SEC_FILE - The file specified by the file handle is a mapped 00204 file. If a file handle is supplied and neither 00205 SEC_IMAGE or SEC_FILE is supplied, SEC_FILE is 00206 assumed. 00207 00208 SEC_NO_CHANGE - Once the file is mapped, the protection cannot 00209 be changed nor can the view be unmapped. The 00210 view is unmapped when the process is deleted. 00211 Cannot be used with SEC_IMAGE. 00212 00213 FileHandle - Supplies an optional handle of an open file object. 00214 If the value of this handle is null, then the 00215 section will be backed by a paging file. Otherwise 00216 the section is backed by the specified data file. 00217 00218 Return Value: 00219 00220 Returns the status of the operation. 00221 00222 TBS 00223 00224 --*/ 00225 00226 { 00227 NTSTATUS Status; 00228 PVOID Section; 00229 HANDLE Handle; 00230 LARGE_INTEGER LargeSize; 00231 LARGE_INTEGER CapturedSize; 00232 ULONG RetryCount; 00233 00234 if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 00235 SEC_IMAGE | SEC_NOCACHE | SEC_NO_CHANGE)) != 0) { 00236 return STATUS_INVALID_PARAMETER_6; 00237 } 00238 00239 if ((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) == 0) { 00240 return STATUS_INVALID_PARAMETER_6; 00241 } 00242 00243 if ((AllocationAttributes & SEC_IMAGE) && 00244 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | 00245 SEC_NOCACHE | SEC_NO_CHANGE))) { 00246 00247 return STATUS_INVALID_PARAMETER_6; 00248 } 00249 00250 if ((AllocationAttributes & SEC_COMMIT) && 00251 (AllocationAttributes & SEC_RESERVE)) { 00252 return STATUS_INVALID_PARAMETER_6; 00253 } 00254 00255 // 00256 // Check the SectionProtection Flag. 00257 // 00258 00259 if ((SectionPageProtection & PAGE_NOCACHE) || 00260 (SectionPageProtection & PAGE_GUARD) || 00261 (SectionPageProtection & PAGE_NOACCESS)) { 00262 00263 // 00264 // No cache is only specified through SEC_NOCACHE option in the 00265 // allocation attributes. 00266 // 00267 00268 return STATUS_INVALID_PAGE_PROTECTION; 00269 } 00270 00271 00272 if (KeGetPreviousMode() != KernelMode) { 00273 try { 00274 ProbeForWriteHandle(SectionHandle); 00275 00276 if (ARGUMENT_PRESENT (MaximumSize)) { 00277 00278 // 00279 // Note we only probe for byte alignment because prior to NT 5, 00280 // we never probed at all. We don't want to break user apps 00281 // that had bad alignment if they worked before. 00282 // 00283 00284 ProbeForRead(MaximumSize, sizeof(LARGE_INTEGER), sizeof(UCHAR)); 00285 LargeSize = *MaximumSize; 00286 } else { 00287 ZERO_LARGE (LargeSize); 00288 } 00289 00290 } except (EXCEPTION_EXECUTE_HANDLER) { 00291 return GetExceptionCode(); 00292 } 00293 } else { 00294 if (ARGUMENT_PRESENT (MaximumSize)) { 00295 LargeSize = *MaximumSize; 00296 } else { 00297 ZERO_LARGE (LargeSize); 00298 } 00299 } 00300 00301 RetryCount = 0; 00302 00303 retry: 00304 00305 CapturedSize = LargeSize; 00306 00307 ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); 00308 Status = MmCreateSection ( &Section, 00309 DesiredAccess, 00310 ObjectAttributes, 00311 &CapturedSize, 00312 SectionPageProtection, 00313 AllocationAttributes, 00314 FileHandle, 00315 NULL ); 00316 00317 00318 ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); 00319 if (!NT_SUCCESS(Status)) { 00320 if ((Status == STATUS_FILE_LOCK_CONFLICT) && 00321 (RetryCount < 3)) { 00322 00323 // 00324 // The file system may have prevented this from working 00325 // due to log file flushing. Delay and try again. 00326 // 00327 00328 RetryCount += 1; 00329 00330 KeDelayExecutionThread (KernelMode, 00331 FALSE, 00332 &MmHalfSecond); 00333 00334 goto retry; 00335 00336 } 00337 return Status; 00338 } 00339 00340 #if DBG 00341 if (MmDebug & MM_DBG_SECTIONS) { 00342 DbgPrint("inserting section %lx control %lx\n",Section, 00343 ((PSECTION)Section)->Segment->ControlArea); 00344 } 00345 #endif 00346 00347 { 00348 PCONTROL_AREA ControlArea; 00349 ControlArea = ((PSECTION)Section)->Segment->ControlArea; 00350 if ((ControlArea != NULL) && (ControlArea->FilePointer != NULL)) { 00351 CcZeroEndOfLastPage (ControlArea->FilePointer); 00352 } 00353 } 00354 00355 // 00356 // Note if the insertion fails, Ob will dereference the object for us. 00357 // 00358 00359 Status = ObInsertObject (Section, 00360 NULL, 00361 DesiredAccess, 00362 0, 00363 (PVOID *)NULL, 00364 &Handle); 00365 00366 if (NT_SUCCESS(Status)) { 00367 try { 00368 *SectionHandle = Handle; 00369 } except (EXCEPTION_EXECUTE_HANDLER) { 00370 00371 // 00372 // If the write attempt fails, then do not report an error. 00373 // When the caller attempts to access the handle value, 00374 // an access violation will occur. 00375 // 00376 } 00377 } 00378 00379 #if DBG 00380 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00381 if ( !MmWatchProcess ) 00382 DbgPrint("return creasect handle %lx status %lx\n",Handle, Status); 00383 } 00384 #endif 00385 00386 return Status; 00387 }

NTSTATUS NtOpenSection OUT PHANDLE  SectionHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES  ObjectAttributes
 

Definition at line 4250 of file creasect.c.

References EXCEPTION_EXECUTE_HANDLER, Handle, KernelMode, KPROCESSOR_MODE, MmSectionObjectType, NTSTATUS(), NULL, ObjectAttributes, ObOpenObjectByName(), PAGED_CODE, ProbeForWriteHandle, and Status.

Referenced by LdrpCheckForKnownDll().

04258 : 04259 04260 This function opens a handle to a section object with the specified 04261 desired access. 04262 04263 Arguments: 04264 04265 04266 Sectionhandle - Supplies a pointer to a variable that will 04267 receive the section object handle value. 04268 04269 DesiredAccess - Supplies the desired types of access for the 04270 section. 04271 04272 DesiredAccess Flags 04273 04274 EXECUTE - Execute access to the section is desired. 04275 04276 READ - Read access to the section is desired. 04277 04278 WRITE - Write access to the section is desired. 04279 04280 ObjectAttributes - Supplies a pointer to an object attributes structure. 04281 04282 Return Value: 04283 04284 Returns the status 04285 04286 TBS 04287 04288 04289 --*/ 04290 04291 { 04292 HANDLE Handle; 04293 KPROCESSOR_MODE PreviousMode; 04294 NTSTATUS Status; 04295 04296 PAGED_CODE(); 04297 // 04298 // Get previous processor mode and probe output arguments if necessary. 04299 // 04300 04301 PreviousMode = KeGetPreviousMode(); 04302 if (PreviousMode != KernelMode) { 04303 try { 04304 ProbeForWriteHandle(SectionHandle); 04305 } except (EXCEPTION_EXECUTE_HANDLER) { 04306 return GetExceptionCode(); 04307 } 04308 } 04309 04310 // 04311 // Open handle to the section object with the specified desired 04312 // access. 04313 // 04314 04315 Status = ObOpenObjectByName (ObjectAttributes, 04316 MmSectionObjectType, 04317 PreviousMode, 04318 NULL, 04319 DesiredAccess, 04320 NULL, 04321 &Handle 04322 ); 04323 04324 try { 04325 *SectionHandle = Handle; 04326 } except (EXCEPTION_EXECUTE_HANDLER) { 04327 return Status; 04328 } 04329 04330 return Status; 04331 }


Variable Documentation

POBJECT_TYPE IoFileObjectType
 

Definition at line 50 of file creasect.c.

ULONG MMCONTROL = 'aCmM'
 

Definition at line 25 of file creasect.c.

Referenced by MiCreateImageFileMap(), MiCreatePagingFileMap(), MiSectionInitialization(), and MmCreateSection().

CCHAR MmImageProtectionArray[16]
 

Initial value:

Definition at line 52 of file creasect.c.

Referenced by MiGetImageProtection().

ULONG MMSECT = 'tSmM'
 

Definition at line 27 of file creasect.c.

Referenced by MiAllocateSpecialPool(), MiCreateDataFileMap(), MiCreateImageFileMap(), and MiCreatePagingFileMap().

ULONG MMTEMPORARY = 'xxmM'
 

Definition at line 26 of file creasect.c.

Referenced by MiCreateImageFileMap().


Generated on Sat May 15 19:43:18 2004 for test by doxygen 1.3.7