reactos/ntoskrnl/mm
diff -u -r1.168 -r1.169
--- section.c 24 Dec 2004 17:06:59 -0000 1.168
+++ section.c 30 Dec 2004 08:05:11 -0000 1.169
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: section.c,v 1.168 2004/12/24 17:06:59 navaraf Exp $
+/* $Id: section.c,v 1.169 2004/12/30 08:05:11 hyperion Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/section.c
@@ -32,6 +32,8 @@
#define NDEBUG
#include <internal/debug.h>
+#include <reactos/exeformat.h>
+
/* TYPES *********************************************************************/
typedef struct
@@ -156,6 +158,7 @@
}
MmFreePageTablesSectionSegment(&SectionSegments[i]);
}
+ ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
FileObject->SectionObjectPointer->ImageSectionObject = NULL;
}
@@ -2228,7 +2231,6 @@
ExInitializeFastMutex(&Segment->Lock);
Segment->FileOffset = 0;
Segment->Protection = SectionPageProtection;
- Segment->Attributes = AllocationAttributes;
Segment->RawLength = MaximumSize.u.LowPart;
Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
Segment->Flags = MM_PAGEFILE_SEGMENT;
@@ -2442,7 +2444,6 @@
Segment->FileOffset = 0;
Segment->Protection = SectionPageProtection;
- Segment->Attributes = 0;
Segment->Flags = MM_DATAFILE_SEGMENT;
Segment->Characteristics = 0;
Segment->WriteCopy = FALSE;
@@ -2455,7 +2456,7 @@
Segment->RawLength = MaximumSize.u.LowPart;
Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
}
- Segment->VirtualAddress = NULL;
+ Segment->VirtualAddress = 0;
RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
}
else
@@ -2487,25 +2488,653 @@
return(STATUS_SUCCESS);
}
-static ULONG SectionCharacteristicsToProtect[16] =
+/*
+ TODO: not that great (declaring loaders statically, having to declare all of
+ them, having to keep them extern, etc.), will fix in the future
+*/
+extern NTSTATUS NTAPI PeFmtCreateSection
+(
+ IN CONST VOID * FileHeader,
+ IN SIZE_T FileHeaderSize,
+ IN PVOID File,
+ OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ OUT PULONG Flags,
+ IN PEXEFMT_CB_READ_FILE ReadFileCb,
+ IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
+);
+
+extern NTSTATUS NTAPI ElfFmtCreateSection
+(
+ IN CONST VOID * FileHeader,
+ IN SIZE_T FileHeaderSize,
+ IN PVOID File,
+ OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ OUT PULONG Flags,
+ IN PEXEFMT_CB_READ_FILE ReadFileCb,
+ IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
+);
+
+/* TODO: this is a standard DDK/PSDK macro */
+#ifndef RTL_NUMBER_OF
+#define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
+#endif
+
+static PEXEFMT_LOADER ExeFmtpLoaders[] =
+{
+ PeFmtCreateSection,
+ ElfFmtCreateSection
+};
+
+static
+PMM_SECTION_SEGMENT
+NTAPI
+ExeFmtpAllocateSegments(IN ULONG NrSegments)
+{
+ SIZE_T SizeOfSegments;
+ PMM_SECTION_SEGMENT Segments;
+
+ /* TODO: check for integer overflow */
+ SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
+
+ Segments = ExAllocatePoolWithTag(NonPagedPool,
+ SizeOfSegments,
+ TAG_MM_SECTION_SEGMENT);
+
+ if(Segments)
+ RtlZeroMemory(Segments, SizeOfSegments);
+
+ return Segments;
+}
+
+static
+NTSTATUS
+NTAPI
+ExeFmtpReadFile(IN PVOID File,
+ IN PLARGE_INTEGER Offset,
+ IN ULONG Length,
+ OUT PVOID * Data,
+ OUT PVOID * AllocBase,
+ OUT PULONG ReadSize)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ ULONG AdjustOffset;
+ ULONG OffsetAdjustment;
+ ULONG BufferSize;
+ ULONG UsedSize;
+ PVOID Buffer;
+
+ ASSERT_IRQL_LESS(DISPATCH_LEVEL);
+
+ if(Length == 0)
+ {
+ KEBUGCHECK(STATUS_INVALID_PARAMETER_4);
+ }
+
+ FileOffset = *Offset;
+
+ /* Negative/special offset: it cannot be used in this context */
+ if(FileOffset.u.HighPart < 0)
+ {
+ KEBUGCHECK(STATUS_INVALID_PARAMETER_5);
+ }
+
+ ASSERT(PAGE_SIZE <= MAXULONG);
+ AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
+ OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
+ FileOffset.u.LowPart = AdjustOffset;
+
+ BufferSize = Length + OffsetAdjustment;
+ BufferSize = PAGE_ROUND_UP(BufferSize);
+
+ /*
+ * It's ok to use paged pool, because this is a temporary buffer only used in
+ * the loading of executables. The assumption is that MmCreateSection is
+ * always called at low IRQLs and that these buffers don't survive a brief
+ * initialization phase
+ */
+ Buffer = ExAllocatePoolWithTag(PagedPool,
+ BufferSize,
+ TAG('M', 'm', 'X', 'r'));
+
+ UsedSize = 0;
+
+#if 0
+ Status = MmspPageRead(File,
+ Buffer,
+ BufferSize,
+ &FileOffset,
+ &UsedSize);
+#else
+/*
+ * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
+ * nothing will work. But using ZwReadFile is wrong, and using its side effects
+ * to initialize internal state is even worse. Our cache manager is in need of
+ * professional help
+ */
+ {
+ IO_STATUS_BLOCK Iosb;
+
+ Status = ZwReadFile(File,
+ NULL,
+ NULL,
+ NULL,
+ &Iosb,
+ Buffer,
+ BufferSize,
+ &FileOffset,
+ NULL);
+
+ if(NT_SUCCESS(Status))
+ {
+ UsedSize = Iosb.Information;
+ }
+ }
+#endif
+
+ if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
+ {
+ Status = STATUS_IN_PAGE_ERROR;
+ ASSERT(!NT_SUCCESS(Status));
+ }
+
+ if(NT_SUCCESS(Status))
+ {
+ *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
+ *AllocBase = Buffer;
+ *ReadSize = UsedSize - OffsetAdjustment;
+ }
+ else
+ {
+ ExFreePool(Buffer);
+ }
+
+ return Status;
+}
+
+#ifdef NASSERT
+# define MmspAssertSegmentsSorted(OBJ_) ((void)0)
+# define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
+# define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
+#else
+static
+VOID
+NTAPI
+MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+ ULONG i;
+
+ for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+ ImageSectionObject->Segments[i - 1].VirtualAddress);
+ }
+}
+
+static
+VOID
+NTAPI
+MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+ ULONG i;
+
+ MmspAssertSegmentsSorted(ImageSectionObject);
+
+ for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ ASSERT(ImageSectionObject->Segments[i].Length > 0);
+
+ if(i > 0)
+ {
+ ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+ (ImageSectionObject->Segments[i - 1].VirtualAddress +
+ ImageSectionObject->Segments[i - 1].Length));
+ }
+ }
+}
+
+static
+VOID
+NTAPI
+MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+ ULONG i;
+
+ for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
- PAGE_NOACCESS, // 0 = NONE
- PAGE_NOACCESS, // 1 = SHARED
- PAGE_EXECUTE, // 2 = EXECUTABLE
- PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
- PAGE_READONLY, // 4 = READABLE
- PAGE_READONLY, // 5 = READABLE, SHARED
- PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
- PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
- PAGE_READWRITE, // 8 = WRITABLE
- PAGE_READWRITE, // 9 = WRITABLE, SHARED
- PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
- PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
- PAGE_READWRITE, // 12 = WRITABLE, READABLE
- PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
- PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
- PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
- };
+ ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
+ ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
+ }
+}
+#endif
+
+static
+int
+__cdecl
+MmspCompareSegments(const void * x,
+ const void * y)
+{
+ PMM_SECTION_SEGMENT Segment1 = (PMM_SECTION_SEGMENT)x;
+ PMM_SECTION_SEGMENT Segment2 = (PMM_SECTION_SEGMENT)y;
+
+ return
+ (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
+ ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
+}
+
+/*
+ * Ensures an image section's segments are sorted in memory
+ */
+static
+VOID
+NTAPI
+MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ IN ULONG Flags)
+{
+ if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
+ {
+ MmspAssertSegmentsSorted(ImageSectionObject);
+ }
+ else
+ {
+ qsort(ImageSectionObject->Segments,
+ ImageSectionObject->NrSegments,
+ sizeof(ImageSectionObject->Segments[0]),
+ MmspCompareSegments);
+ }
+}
+
+
+/*
+ * Ensures an image section's segments don't overlap in memory and don't have
+ * gaps and don't have a null size. We let them map to overlapping file regions,
+ * though - that's not necessarily an error
+ */
+static
+BOOLEAN
+NTAPI
+MmspCheckSegmentBounds
+(
+ IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ IN ULONG Flags
+)
+{
+ ULONG i;
+
+ if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
+ {
+ MmspAssertSegmentsNoOverlap(ImageSectionObject);
+ return TRUE;
+ }
+
+ ASSERT(ImageSectionObject->NrSegments >= 1);
+
+ for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ if(ImageSectionObject->Segments[i].Length == 0)
+ {
+ return FALSE;
+ }
+
+ if(i > 0)
+ {
+ /*
+ * TODO: relax the limitation on gaps. For example, gaps smaller than a
+ * page could be OK (Windows seems to be OK with them), and larger gaps
+ * could lead to image sections spanning several discontiguous regions
+ * (NtMapViewOfSection could then refuse to map them, and they could
+ * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
+ */
+ if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
+ ImageSectionObject->Segments[i - 1].Length) !=
+ ImageSectionObject->Segments[i].VirtualAddress)
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Merges and pads an image section's segments until they all are page-aligned
+ * and have a size that is a multiple of the page size
+ */
+static
+BOOLEAN
+NTAPI
+MmspPageAlignSegments
+(
+ IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ IN ULONG Flags
+)
+{
+ ULONG i;
+ ULONG LastSegment;
+ BOOLEAN Initialized;
+
+ if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
+ {
+ MmspAssertSegmentsPageAligned(ImageSectionObject);
+ return TRUE;
+ }
+
+ Initialized = FALSE;
+ LastSegment = 0;
+
+ for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ PMM_SECTION_SEGMENT EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+ /*
+ * The first segment requires special handling
+ */
+ if (i == 0)
+ {
+ ULONG_PTR VirtualAddress;
+ ULONG_PTR VirtualOffset;
+
+ VirtualAddress = EffectiveSegment->VirtualAddress;
+
+ /* Round down the virtual address to the nearest page */
+ EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
+
+ /* Round up the virtual size to the nearest page */
+ EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
+ EffectiveSegment->VirtualAddress;
+
+ /* Adjust the raw address and size */
+ VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
+
+ if (EffectiveSegment->FileOffset < VirtualOffset)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Garbage in, garbage out: unaligned base addresses make the file
+ * offset point in curious and odd places, but that's what we were
+ * asked for
+ */
+ EffectiveSegment->FileOffset -= VirtualOffset;
+ EffectiveSegment->RawLength += VirtualOffset;
+ }
+ else
+ {
+ PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
+ ULONG_PTR EndOfEffectiveSegment;
+
+ EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
+ ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
+
+ /*
+ * The current segment begins exactly where the current effective
+ * segment ended, therefore beginning a new effective segment
+ */
+ if (EndOfEffectiveSegment == Segment->VirtualAddress)
+ {
+ LastSegment ++;
+ ASSERT(LastSegment <= i);
+ ASSERT(LastSegment < ImageSectionObject->NrSegments);
+
+ EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+ /*
+ * Copy the current segment. If necessary, the effective segment
+ * will be expanded later
+ */
+ *EffectiveSegment = *Segment;
+
+ /*
+ * Page-align the virtual size. We know for sure the virtual address
+ * already is
+ */
+ ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
+ EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
+ }
+ /*
+ * The current segment is still part of the current effective segment:
+ * extend the effective segment to reflect this
+ */
+ else if (EndOfEffectiveSegment > Segment->VirtualAddress)
+ {
+ static const ULONG FlagsToProtection[16] =
+ {
+ PAGE_NOACCESS,
+ PAGE_READONLY,
+ PAGE_READWRITE,
+ PAGE_READWRITE,
+ PAGE_EXECUTE_READ,
+ PAGE_EXECUTE_READ,
+ PAGE_EXECUTE_READWRITE,
+ PAGE_EXECUTE_READWRITE,
+ PAGE_WRITECOPY,
+ PAGE_WRITECOPY,
+ PAGE_WRITECOPY,
+ PAGE_WRITECOPY,
+ PAGE_EXECUTE_WRITECOPY,
+ PAGE_EXECUTE_WRITECOPY,
+ PAGE_EXECUTE_WRITECOPY,
+ PAGE_EXECUTE_WRITECOPY
+ };
+
+ unsigned ProtectionFlags;
+
+ /*
+ * Extend the file size
+ */
+
+ /* Unaligned segments must be contiguous within the file */
+ if (Segment->FileOffset != (EffectiveSegment->FileOffset +
+ EffectiveSegment->RawLength))
+ {
+ return FALSE;
+ }
+
+ EffectiveSegment->RawLength += Segment->RawLength;
+
+ /*
+ * Extend the virtual size
+ */
+ ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) > EndOfEffectiveSegment);
+
+ EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
+ EffectiveSegment->VirtualAddress;
+
+ /*
+ * Merge the protection
+ */
+ EffectiveSegment->Protection |= Segment->Protection;
+
+ /* Clean up redundance */
+ ProtectionFlags = 0;
+
+ if(EffectiveSegment->Protection & PAGE_IS_READABLE)
+ ProtectionFlags |= 1 << 0;
+
+ if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
+ ProtectionFlags |= 1 << 1;
+
+ if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
+ ProtectionFlags |= 1 << 2;
+
+ if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
+ ProtectionFlags |= 1 << 3;
+
+ ASSERT(ProtectionFlags < 16);
+ EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
+
+ /* If a segment was required to be shared and cannot, fail */
+ if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
+ EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
+ {
+ return FALSE;
+ }
+ }
+ /*
+ * We assume no holes between segments at this point
+ */
+ else
+ {
+ ASSERT(FALSE);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+NTSTATUS
+ExeFmtpCreateImageSection(HANDLE FileHandle,
+ PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+ LARGE_INTEGER Offset;
+ PVOID FileHeader;
+ PVOID FileHeaderBuffer;
+ ULONG FileHeaderSize;
+ ULONG Flags;
+ ULONG OldNrSegments;
+ NTSTATUS Status;
+ ULONG i;
+
+ /*
+ * Read the beginning of the file (2 pages). Should be enough to contain
+ * all (or most) of the headers
+ */
+ Offset.QuadPart = 0;
+
+ /* FIXME: use FileObject instead of FileHandle */
+ Status = ExeFmtpReadFile (FileHandle,
+ &Offset,
+ PAGE_SIZE * 2,
+ &FileHeader,
+ &FileHeaderBuffer,
+ &FileHeaderSize);
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ if (FileHeaderSize == 0)
+ {
+ ExFreePool(FileHeaderBuffer);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ * Look for a loader that can handle this executable
+ */
+ for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
+ {
+ RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
+ Flags = 0;
+
+ /* FIXME: use FileObject instead of FileHandle */
+ Status = ExeFmtpLoaders[i](FileHeader,
+ FileHeaderSize,
+ FileHandle,
+ ImageSectionObject,
+ &Flags,
+ ExeFmtpReadFile,
+ ExeFmtpAllocateSegments);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (ImageSectionObject->Segments)
+ {
+ ExFreePool(ImageSectionObject->Segments);
+ ImageSectionObject->Segments = NULL;
+ }
+ }
+
+ if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+ break;
+ }
+
+ ExFreePool(FileHeaderBuffer);
+
+ /*
+ * No loader handled the format
+ */
+ if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+ {
+ Status = STATUS_INVALID_IMAGE_FORMAT;
+ ASSERT(!NT_SUCCESS(Status));
+ }
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ ASSERT(ImageSectionObject->Segments != NULL);
+
+ /*
+ * Some defaults
+ */
+ /* FIXME? are these values platform-dependent? */
+ if(ImageSectionObject->StackReserve == 0)
+ ImageSectionObject->StackReserve = 0x40000;
+
+ if(ImageSectionObject->StackCommit == 0)
+ ImageSectionObject->StackCommit = 0x1000;
+
+ if(ImageSectionObject->ImageBase == 0)
+ {
+ if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
+ ImageSectionObject->ImageBase = 0x10000000;
+ else
+ ImageSectionObject->ImageBase = 0x00400000;
+ }
+
+ /*
+ * And now the fun part: fixing the segments
+ */
+
+ /* Sort them by virtual address */
+ MmspSortSegments(ImageSectionObject, Flags);
+
+ /* Ensure they don't overlap in memory */
+ if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
+ return STATUS_INVALID_IMAGE_FORMAT;
+
+ /* Ensure they are aligned */
+ OldNrSegments = ImageSectionObject->NrSegments;
+
+ if (!MmspPageAlignSegments(ImageSectionObject, Flags))
+ return STATUS_INVALID_IMAGE_FORMAT;
+
+ /* Trim them if the alignment phase merged some of them */
+ if (ImageSectionObject->NrSegments < OldNrSegments)
+ {
+ PMM_SECTION_SEGMENT Segments;
+ SIZE_T SizeOfSegments;
+
+ SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
+
+ Segments = ExAllocatePoolWithTag(NonPagedPool,
+ SizeOfSegments,
+ TAG_MM_SECTION_SEGMENT);
+
+ if (Segments == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
+ ExFreePool(ImageSectionObject->Segments);
+ ImageSectionObject->Segments = Segments;
+ }
+
+ /* And finish their initialization */
+ for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
+ ImageSectionObject->Segments[i].ReferenceCount = 1;
+
+ RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
+ sizeof(ImageSectionObject->Segments[i].PageDirectory));
+ }
+
+ ASSERT(NT_SUCCESS(Status));
+ return Status;
+}
NTSTATUS
MmCreateImageSection(PSECTION_OBJECT *SectionObject,
@@ -2519,16 +3148,9 @@
PSECTION_OBJECT Section;
NTSTATUS Status;
PFILE_OBJECT FileObject;
- IMAGE_DOS_HEADER DosHeader;
- IO_STATUS_BLOCK Iosb;
- LARGE_INTEGER Offset;
- IMAGE_NT_HEADERS PEHeader;
PMM_SECTION_SEGMENT SectionSegments;
- ULONG NrSegments;
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
ULONG i;
- ULONG Size;
- ULONG Characteristics;
ULONG FileAccess = 0;
/*
@@ -2540,6 +3162,19 @@
}
/*
+ * Check file access required
+ */
+ if (SectionPageProtection & PAGE_READWRITE ||
+ SectionPageProtection & PAGE_EXECUTE_READWRITE)
+ {
+ FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
+ }
+ else
+ {
+ FileAccess = FILE_READ_DATA;
+ }
+
+ /*
* Reference the file handle
*/
Status = ObReferenceObjectByHandle(FileHandle,
@@ -2554,6 +3189,32 @@
}
/*
+ * Create the section
+ */
+ Status = ObCreateObject (ExGetPreviousMode(),
+ MmSectionObjectType,
+ ObjectAttributes,
+ ExGetPreviousMode(),
+ NULL,
+ sizeof(SECTION_OBJECT),
+ 0,
+ 0,
+ (PVOID*)(PVOID)&Section);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(FileObject);
+ return(Status);
+ }
+
+ /*
+ * Initialize it
+ */
+ Section->SectionPageProtection = SectionPageProtection;
+ Section->AllocationAttributes = AllocationAttributes;
+ InitializeListHead(&Section->ViewListHead);
+ KeInitializeSpinLock(&Section->ViewListLock);
+
+ /*
* Initialized caching for this file object if previously caching
* was initialized for the same on disk file
*/
@@ -2561,322 +3222,68 @@
if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
{
- PIMAGE_SECTION_HEADER ImageSections;
- /*
- * Read the dos header and check the DOS signature
- */
- Offset.QuadPart = 0;
- Status = ZwReadFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &Iosb,
- &DosHeader,
- sizeof(DosHeader),
- &Offset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(FileObject);
- return(Status);
- }
-
- /*
- * Check the DOS signature
- */
- if (Iosb.Information != sizeof(DosHeader) ||
- DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
- {
- ObDereferenceObject(FileObject);
- return(STATUS_INVALID_IMAGE_FORMAT);
- }
-
- /*
- * Read the PE header
- */
- Offset.QuadPart = DosHeader.e_lfanew;
- Status = ZwReadFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &Iosb,
- &PEHeader,
- sizeof(PEHeader),
- &Offset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(FileObject);
- return(Status);
- }
-
- /*
- * Check the signature
- */
- if (Iosb.Information != sizeof(PEHeader) ||
- PEHeader.Signature != IMAGE_NT_SIGNATURE)
- {
- ObDereferenceObject(FileObject);
- return(STATUS_INVALID_IMAGE_FORMAT);
- }
+ NTSTATUS StatusExeFmt;
- /*
- * Read in the section headers
- */
- Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
- ImageSections = ExAllocatePool(NonPagedPool,
- PEHeader.FileHeader.NumberOfSections *
- sizeof(IMAGE_SECTION_HEADER));
- if (ImageSections == NULL)
+ ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
+ if (ImageSectionObject == NULL)
{
ObDereferenceObject(FileObject);
+ ObDereferenceObject(Section);
return(STATUS_NO_MEMORY);
}
- Status = ZwReadFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &Iosb,
- ImageSections,
- PEHeader.FileHeader.NumberOfSections *
- sizeof(IMAGE_SECTION_HEADER),
- &Offset,
- 0);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(Status);
- }
- if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
- {
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(STATUS_INVALID_IMAGE_FORMAT);
- }
+ StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
- /*
- * Create the section
- */
- Status = ObCreateObject (ExGetPreviousMode(),
- MmSectionObjectType,
- ObjectAttributes,
- ExGetPreviousMode(),
- NULL,
- sizeof(SECTION_OBJECT),
- 0,
- 0,
- (PVOID*)(PVOID)&Section);
- if (!NT_SUCCESS(Status))
+ if (!NT_SUCCESS(StatusExeFmt))
{
+ if(ImageSectionObject->Segments != NULL)
+ ExFreePool(ImageSectionObject->Segments);
+
+ ExFreePool(ImageSectionObject);
+ ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(Status);
+ return(StatusExeFmt);
}
- /*
- * Initialize it
- */
- Section->SectionPageProtection = SectionPageProtection;
- Section->AllocationAttributes = AllocationAttributes;
- Section->ImageSection = NULL;
- InitializeListHead(&Section->ViewListHead);
- KeInitializeSpinLock(&Section->ViewListLock);
-
- /*
- * Check file access required
- */
- if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
- {
- FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
- }
- else
- {
- FileAccess = FILE_READ_DATA;
- }
+ Section->ImageSection = ImageSectionObject;
+ ASSERT(ImageSectionObject->Segments);
/*
* Lock the file
*/
Status = MmspWaitForFileLock(FileObject);
- if (Status != STATUS_SUCCESS)
+ if (!NT_SUCCESS(Status))
{
+ ExFreePool(ImageSectionObject->Segments);
+ ExFreePool(ImageSectionObject);
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
return(Status);
}
- /*
- * allocate the section segments to describe the mapping
- */
- NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
- Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
- ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
- if (ImageSectionObject == NULL)
- {
- KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
- ObDereferenceObject(Section);
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(STATUS_NO_MEMORY);
- }
- Section->ImageSection = ImageSectionObject;
- ImageSectionObject->NrSegments = NrSegments;
- ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
- ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
- ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
- ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
- ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
- ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
- ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
- ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
- ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
- ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
-
- SectionSegments = ImageSectionObject->Segments;
- SectionSegments[0].FileOffset = 0;
- SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
- SectionSegments[0].Protection = PAGE_READONLY;
- SectionSegments[0].RawLength = PAGE_SIZE;
- SectionSegments[0].Length = PAGE_SIZE;
- SectionSegments[0].Flags = 0;
- SectionSegments[0].ReferenceCount = 1;
- SectionSegments[0].VirtualAddress = 0;
[truncated at 1000 lines; 195 more skipped]