Commit in reactos/ntoskrnl/mm on ELF_support
i386/page.c+4-41.77.2.3 -> 1.77.2.4
pe.c+132-1271.1.2.3 -> 1.1.2.4
section.c+695-761.166.2.3 -> 1.166.2.4
+831-207
3 modified files
 - ntoskrnl/mm/i386/page.c: now more flexible in converting the protection flags into page flags - the protection may be one of the PAGE_XXX_WRITECOPY ones, if it comes from a section segment.
 - ntoskrnl/mm/pe.c: relaxed several restrictions to make just about any real-world executable load. Also fixed some embarassing errors in the utility functions for address alignment (really, how can you get THAT wrong?). Also, output some explanation for failure, and move the default values for stack reserve, stack commit, ecc. to mm/section.c. Finally, use the new style of ReadFile callback, which is IoPageRead-ready.
 - ntoskrnl/mm/section.c: the usual clusterfuck, only it doesn't even compile ATM. I'm just committing it because I'm too afraid of myself - right now I feel very much like deleting everything, throwing my computer from the window and curling up in a corner of the room. Our Mm/Cc state is THAT sorry. The result of a week of work is a boot sequence that goes up to autochk.exe and then crashes because of unexplicable and unpredictable memory corruption. One step forward and two backwards.

reactos/ntoskrnl/mm/i386
page.c 1.77.2.3 -> 1.77.2.4
diff -u -r1.77.2.3 -r1.77.2.4
--- page.c	13 Dec 2004 16:18:13 -0000	1.77.2.3
+++ page.c	18 Dec 2004 02:36:08 -0000	1.77.2.4
@@ -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: page.c,v 1.77.2.3 2004/12/13 16:18:13 hyperion Exp $
+/* $Id: page.c,v 1.77.2.4 2004/12/18 02:36:08 hyperion Exp $
  *
  * PROJECT:     ReactOS kernel
  * FILE:        ntoskrnl/mm/i386/page.c
@@ -146,11 +146,11 @@
    {
       Attributes = 0;
    }
-   else if (flProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
+   else if (flProtect & PAGE_IS_WRITABLE)
    {
       Attributes = PA_PRESENT | PA_READWRITE;
    }
-   else if (flProtect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
+   else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
    {
       Attributes = PA_PRESENT;
    }
@@ -160,7 +160,7 @@
       KEBUGCHECK(0);
    }
    if (Ke386NoExecute && 
-       !(flProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE)))
+       !(flProtect & PAGE_IS_EXECUTABLE))
    {
       Attributes = Attributes | 0x80000000;
    }

reactos/ntoskrnl/mm
pe.c 1.1.2.3 -> 1.1.2.4
diff -u -r1.1.2.3 -r1.1.2.4
--- pe.c	13 Dec 2004 05:55:32 -0000	1.1.2.3
+++ pe.c	18 Dec 2004 02:36:09 -0000	1.1.2.4
@@ -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: pe.c,v 1.1.2.3 2004/12/13 05:55:32 hyperion Exp $
+/* $Id: pe.c,v 1.1.2.4 2004/12/18 02:36:09 hyperion Exp $
  *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/mm/pe.c
@@ -31,7 +31,7 @@
 
 #include <ntoskrnl.h>
 
-#define NDEBUG
+/*#define NDEBUG*/
 #include <internal/debug.h>
 
 #include <reactos/exeformat.h>
@@ -188,7 +188,7 @@
 ULONG FASTCALL GetExcess(IN ULONG Address, IN ULONG Alignment)
 {
  ASSERT(IsPowerOf2(Alignment));
- return Address & ~(Alignment - 1);
+ return Address & (Alignment - 1);
 }
 
 BOOLEAN FASTCALL IsAligned(IN ULONG Address, IN ULONG Alignment)
@@ -203,12 +203,15 @@
  IN ULONG Alignment
 )
 {
- return Intsafe_AddULong32
- (
-  AlignedAddress,
-  Address,
-  Alignment - GetExcess(Address, Alignment)
- );
+ ULONG nExcess = GetExcess(Address, Alignment);
+
+ if(nExcess == 0)
+ {
+  *AlignedAddress = Address;
+  return nExcess == 0;
+ }
+ else
+  return Intsafe_AddULong32(AlignedAddress, Address, Alignment - nExcess);
 }
 
 /*
@@ -259,6 +262,8 @@
  ASSERT(FileHeaderSize >= sizeof(IMAGE_DOS_HEADER));
  ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
 
+#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
+
  pBuffer = NULL;
  pidhDosHeader = FileHeader;
 
@@ -267,17 +272,17 @@
 
  /* no MZ signature */
  if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
-  goto l_Return;
+  DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
 
  /* not a Windows executable */
  if(pidhDosHeader->e_lfanew <= 0)
-  goto l_Return;
+  DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
 
  /* NT HEADER */
  nStatus = STATUS_INVALID_IMAGE_FORMAT;
 
  if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
-  goto l_Return;
+  DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
 
  if(FileHeaderSize < cbFileHeaderOffsetSize)
   pinhNtHeader = NULL;
@@ -307,63 +312,58 @@
  )
  {
   SIZE_T cbNtHeaderSize;
-  SIZE_T cbReadSize;
+  ULONG cbReadSize;
+  PVOID pData;
 
 l_ReadHeaderFromFile:
-
-  nStatus = STATUS_INSUFFICIENT_RESOURCES;
-
-  /* allocate the buffer. We use the largest size (IMAGE_NT_HEADERS64) */
-  pBuffer = ExAllocatePoolWithTag
-  (
-   NonPagedPool,
-   sizeof(IMAGE_NT_HEADERS64),
-   TAG('P', 'e', 'F', 'm')
-  );
-
-  if(pBuffer == NULL)
-   goto l_Return;
-
   lnOffset.QuadPart = pidhDosHeader->e_lfanew;
 
   /* read the header from the file */
   nStatus = ReadFileCb
   (
    File,
-   pBuffer,
-   sizeof(IMAGE_NT_HEADERS64),
    &lnOffset,
+   sizeof(IMAGE_NT_HEADERS64),
+   &pData,
+   &pBuffer,
    &cbReadSize
   );
 
   if(!NT_SUCCESS(nStatus))
-   goto l_Return;
-
-  nStatus = STATUS_UNSUCCESSFUL;
+   DIE(("ReadFile failed, status %08X\n", nStatus));
 
-  if(cbReadSize == 0)
-   goto l_Return;
+  ASSERT(pData);
+  ASSERT(pBuffer);
+  ASSERT(cbReadSize > 0);
 
   nStatus = STATUS_INVALID_IMAGE_FORMAT;
 
   /* the buffer doesn't contain the file header */
   if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
-   goto l_Return;
+   DIE(("The file doesn't contain the PE file header"));
+
+  pinhNtHeader = pData;
 
-  pinhNtHeader = pBuffer;
+  /* object still not aligned: copy it to the beginning of the buffer */
+  if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
+  {
+   ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
+   RtlMoveMemory(pBuffer, pData, cbReadSize);
+   pinhNtHeader = pBuffer;
+  }
 
   /* invalid NT header */
   if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
-   goto l_Return;
+   DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
 
   if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
-   goto l_Return;
+   DIE(("The full NT header is too large\n"));
 
   nStatus = STATUS_UNSUCCESSFUL;
 
   /* the buffer doesn't contain the whole NT header */
   if(cbReadSize < cbNtHeaderSize)
-   goto l_Return;
+   DIE(("The file doesn't contain the full NT header\n"));
  }
  else
  {
@@ -373,13 +373,13 @@
 
   /* don't trust an invalid NT header */
   if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
-   goto l_Return;
+   DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
   
   if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
-   goto l_Return;
+   DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
 
   if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
-   goto l_Return;
+   DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
 
   /* the buffer doesn't contain the whole NT header: read it from the file */
   if(cbOptHeaderOffsetSize > FileHeaderSize)
@@ -393,7 +393,7 @@
  nStatus = STATUS_INVALID_IMAGE_FORMAT;
 
  if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
-  goto l_Return;
+  DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
 
  /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
 
@@ -404,7 +404,7 @@
    break;
   
   default:
-   goto l_Return;
+   DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
  }
 
  if
@@ -417,16 +417,16 @@
   if(piohOptHeader->SectionAlignment < PAGE_SIZE)
   {
    if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
-    goto l_Return;
+    DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
   }
   else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
-   goto l_Return;
+   DIE(("The section alignment is smaller than the file alignment\n"));
 
   nSectionAlignment = piohOptHeader->SectionAlignment;
   nFileAlignment = piohOptHeader->FileAlignment;
 
   if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
-   goto l_Return;
+   DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
  }
  else
  {
@@ -442,9 +442,6 @@
   /* PE32 */
   case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
   {
-   if(cbOptHeaderSize > sizeof(IMAGE_OPTIONAL_HEADER32))
-    goto l_Return;
-
    if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
     ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
 
@@ -462,15 +459,12 @@
   {
    PIMAGE_OPTIONAL_HEADER64 pioh64OptHeader;
 
-   if(cbOptHeaderSize > sizeof(IMAGE_OPTIONAL_HEADER64))
-    goto l_Return;
-
    pioh64OptHeader = (PIMAGE_OPTIONAL_HEADER64)piohOptHeader;
 
    if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
    {
     if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
-     goto l_Return;
+     DIE(("ImageBase exceeds the address space\n"));
 
     ImageSectionObject->ImageBase = pioh64OptHeader->ImageBase;
    }
@@ -478,7 +472,7 @@
    if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
    {
     if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
-     goto l_Return;
+     DIE(("SizeOfStackReserve exceeds the address space\n"));
 
     ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
    }
@@ -486,7 +480,7 @@
    if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
    {
     if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
-     goto l_Return;
+     DIE(("SizeOfStackCommit exceeds the address space\n"));
 
     ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
    }
@@ -495,26 +489,9 @@
   }
  }
 
-#if 0
- /* some defaults */
- if(ImageSectionObject->StackReserve == 0)
-  ImageSectionObject->StackReserve = 0x40000;
-
- if(ImageSectionObject->StackCommit == 0)
-  ImageSectionObject->StackCommit = 0x1000;
-
- if(ImageSectionObject->ImageBase == NULL)
- {
-  if(pinhNtHeader->FileHeader.Characteristics & IMAGE_FILE_DLL)
-   ImageSectionObject->ImageBase = (PVOID)0x10000000;
-  else
-   ImageSectionObject->ImageBase = (PVOID)0x00400000;
- }
-#endif
-
  /* [1], section 3.4.2 */
  if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
-  goto l_Return;
+  DIE(("ImageBase is not aligned on a 64KB boundary"));
 
  /*
   ASSUME: all the fields used here have the same offset and size in both
@@ -551,7 +528,7 @@
 
  /* see [1], section 3.3 */
  if(pinhNtHeader->FileHeader.NumberOfSections > 96)
-  goto l_Return;
+  DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
 
  /*
   the additional segment is for the file's headers. They need to be present for
@@ -562,31 +539,31 @@
 
  /* file offset for the section headers */
  if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
-  goto l_Return;
+  DIE(("Offset overflow\n"));
 
  if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
-  goto l_Return;
+  DIE(("Offset overflow\n"));
 
  /* size of the section headers */
  ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
  cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
 
  if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
-  goto l_Return;
+  DIE(("Section headers too large\n"));
 
  /* size of the executable's headers */
  if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
  {
   if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
-   goto l_Return;
+   DIE(("SizeOfHeaders is not aligned\n"));
 
   if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
-   goto l_Return;
+   DIE(("The section headers overflow SizeOfHeaders\n"));
 
   cbHeadersSize = piohOptHeader->SizeOfHeaders;
  }
  else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
-  goto l_Return;
+  DIE(("Overflow aligning the size of headers\n"));
 
  if(pBuffer)
  {
@@ -619,20 +596,8 @@
   (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0
  )
  {
-  SIZE_T cbReadSize;
-
-  nStatus = STATUS_INSUFFICIENT_RESOURCES;
-
-  /* allocate the buffer */
-  pBuffer = ExAllocatePoolWithTag
-  (
-   NonPagedPool,
-   cbSectionHeadersSize,
-   TAG('P', 'e', 'F', 'm')
-  );
-
-  if(pBuffer == NULL)
-   goto l_Return;
+  PVOID pData;
+  ULONG cbReadSize;
 
   lnOffset.QuadPart = cbSectionHeadersOffset;
 
@@ -640,20 +605,35 @@
   nStatus = ReadFileCb
   (
    File,
-   pBuffer,
-   cbSectionHeadersSize,
    &lnOffset,
+   cbSectionHeadersSize,
+   &pData,
+   &pBuffer,
    &cbReadSize
   );
 
   if(!NT_SUCCESS(nStatus))
-   goto l_Return;
+   DIE(("ReadFile failed with status %08X\n", nStatus));
 
-  nStatus = STATUS_UNSUCCESSFUL;
+  ASSERT(pData);
+  ASSERT(pBuffer);
+  ASSERT(cbReadSize > 0);
+
+  nStatus = STATUS_INVALID_IMAGE_FORMAT;
 
   /* the buffer doesn't contain all the section headers */
   if(cbReadSize < cbSectionHeadersSize)
-   goto l_Return;
+   DIE(("The file doesn't contain all of the section headers\n"));
+
+  pishSectionHeaders = pData;
+
+  /* object still not aligned: copy it to the beginning of the buffer */
+  if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
+  {
+   ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
+   RtlMoveMemory(pBuffer, pData, cbReadSize);
+   pishSectionHeaders = pBuffer;
+  }
  }
 
  /* SEGMENTS */
@@ -662,15 +642,18 @@
  ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
 
  if(ImageSectionObject->Segments == NULL)
-  goto l_Return;
+  DIE(("AllocateSegments failed\n"));
 
  /* initialize the headers segment */
  pssSegments = ImageSectionObject->Segments;
 
  ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
 
+ if(!AlignUp(&nPrevFileEndOfSegment, cbHeadersSize, nFileAlignment))
+  DIE(("Cannot align the size of the section headers\n"));
+
  if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
-  goto l_Return;
+  DIE(("Cannot align the size of the section headers\n"));
 
  pssSegments[0].FileOffset = 0;
  pssSegments[0].Protection = PAGE_READONLY;
@@ -690,27 +673,36 @@
   ULONG nCharacteristics;
 
   /* validate the alignment */
-  if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
-   goto l_Return;
-
-  if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
-   goto l_Return;
-
-  if(!IsAligned(pishSectionHeaders[i].Misc.VirtualSize, nSectionAlignment))
-   goto l_Return;
-
   if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
-   goto l_Return;
+   DIE(("VirtualAddress[%u] is not aligned\n", i));
 
   /* sections must be contiguous, ordered by base address and non-overlapping */
-  if(pishSectionHeaders[i].PointerToRawData != nPrevFileEndOfSegment)
-   goto l_Return;
-
   if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
-   goto l_Return;
+   DIE(("Memory gap between section %u and the previous\n", i));
 
-  /* conversion */
-  pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
+  /* ignore explicit BSS sections */
+  if(pishSectionHeaders[i].SizeOfRawData != 0)
+  {
+   /* validate the alignment */
+   if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
+    DIE(("SizeOfRawData[%u] is not aligned\n", i));
+
+   if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
+    DIE(("PointerToRawData[%u] is not aligned\n", i));
+
+   /* sections must be contiguous, ordered by base address and non-overlapping */
+   if(pishSectionHeaders[i].PointerToRawData != nPrevFileEndOfSegment)
+    DIE(("File gap between section %u and the previous\n", i));
+
+   /* conversion */
+   pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
+   pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
+  }
+  else
+  {
+   ASSERT(pssSegments[i].FileOffset == 0);
+   ASSERT(pssSegments[i].RawLength == 0);
+  }
 
   nCharacteristics = pishSectionHeaders[i].Characteristics;
 
@@ -730,12 +722,16 @@
   /* see table above */
   pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
 
-  pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
-
-  if(pishSectionHeaders[i].Misc.VirtualSize != 0)
-   pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
-  else
+  if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
    pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
+  else
+   pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
+
+  if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
+   DIE(("Cannot align the virtual size of section %u\n", i));
+
+  if(pssSegments[i].Length == 0)
+   DIE(("Virtual size of section %u is null\n", i));
 
   /* ExInitializeFastMutex(&pssSegments[i].Lock); */
   /* pssSegments[i].ReferenceCount = 1; */
@@ -743,12 +739,21 @@
   pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
   pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
 
-  /* ensure the image is no larger than 4GB */
-  if(!Intsafe_AddULong32(&nPrevFileEndOfSegment, pssSegments[i].FileOffset, pssSegments[i].RawLength))
-   goto l_Return;
+  /* ensure the executable is no larger than 4GB */
+  if(pssSegments[i].RawLength != 0)
+  {
+   if(!Intsafe_AddULong32(&nPrevFileEndOfSegment, pssSegments[i].FileOffset, pssSegments[i].RawLength))
+    DIE(("The executable is larger than 4GB\n"));
+  }
 
+  /* ensure the memory image is no larger than 4GB */
   if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
-   goto l_Return;
+   DIE(("The image is larger than 4GB\n"));
+
+  DPRINT("FileOffset    [%u] = %lX\n", i, (ULONG)pssSegments[i].FileOffset);
+  DPRINT("RawLength     [%u] = %lX\n", i, pssSegments[i].RawLength);
+  DPRINT("VirtualAddress[%u] = %lX\n", i, pssSegments[i].VirtualAddress);
+  DPRINT("Length        [%u] = %lX\n", i, pssSegments[i].Length);
  }
 
  /* spare our caller some work in validating the segments */

reactos/ntoskrnl/mm
section.c 1.166.2.3 -> 1.166.2.4
diff -u -r1.166.2.3 -r1.166.2.4
--- section.c	13 Dec 2004 05:55:32 -0000	1.166.2.3
+++ section.c	18 Dec 2004 02:36:09 -0000	1.166.2.4
@@ -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.166.2.3 2004/12/13 05:55:32 hyperion Exp $
+/* $Id: section.c,v 1.166.2.4 2004/12/18 02:36:09 hyperion Exp $
  *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/mm/section.c
@@ -137,15 +137,19 @@
 {
    NTSTATUS Status;
    KEVENT Event;
-   MDL Mdl;
+   PMDL Mdl;
    IO_STATUS_BLOCK Iosb;
 
+   Mdl = IoAllocateMdl(Buffer, BufferSize, FALSE, FALSE, NULL);
+
+   if(Mdl == NULL)
+      return STATUS_INSUFFICIENT_RESOURCES;
+
+   MmBuildMdlForNonPagedPool(Mdl);
    KeInitializeEvent(&Event, NotificationEvent, FALSE);
-   MmInitializeMdl(&Mdl, Buffer, BufferSize);
-   MmBuildMdlForNonPagedPool(&Mdl);
 
    Status = IoPageRead(FileObject,
-                       &Mdl,
+                       Mdl,
                        Offset,
                        &Event,
                        &Iosb);
@@ -157,6 +161,65 @@
    return Iosb.Status;
 }
 
+extern
+NTSTATUS
+NTAPI
+IopReadFile(IN PFILE_OBJECT FileObject,
+            IN KPROCESSOR_MODE AccessMode,
+	    IN PKEVENT EventObject OPTIONAL,
+	    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+	    IN PVOID ApcContext OPTIONAL,
+	    OUT PIO_STATUS_BLOCK IoStatusBlock,
+	    OUT PVOID Buffer,
+	    IN ULONG Length,
+	    IN PLARGE_INTEGER ByteOffset OPTIONAL,
+	    IN PULONG Key OPTIONAL);
+
+/*
+ * This is, basically, a hack. We "touch" the file with an 1-byte read so
+ * caching is enabled for the file. This is wrong, wrong, WRONG: it moves the
+ * file pointer (and I'm NOT hiding the bug by moving it back), it's subject to
+ * whatever mode the file was opened in (synchronous vs asynchronous, cached vs
+ * non-cached, etc.) and in real Windows this is never necessary, but we get
+ * caching and memory mapping TOTALLY WRONG and BACKWARDS, with Mm calling Cc
+ * instead of the other way around. But it isn't "more wrong" than the previous
+ * implementation, so I'm leaving it this way. You're in for one hell of a ride,
+ * should this break something and should you need to fix it...
+ *   [KJK::Hyperion - 2004-12-17]
+ */
+static
+NTSTATUS
+NTAPI
+MmspInitializeFileCache(IN PFILE_OBJECT FileObject)
+{
+   /*
+    * FIXME HACK HACK HORRIBLE HACK PLEASE LET ME DIE:
+    * Since the function can return too soon in case the file was opened for
+    * asyncronous I/O (this is the same behavior as before, when ZwReadFile was
+    * used), we at least limit the damage and pass static buffers. PLEASE, if
+    * you come across this comment, FIX THIS, because it means I still haven't.
+    * IopReadFile itself is a HACK, in kernel mode we should use completion
+    * routines, because any other notification mechanism is tailored towards
+    * consumption from user mode (e.g. EventObject can't be a bare KEVENT)
+    */
+   static UCHAR Buffer[1];
+   static IO_STATUS_BLOCK Iosb;
+   static LARGE_INTEGER FileOffset;
+
+   FileOffset.QuadPart = 0;
+
+   return IopReadFile(FileObject,
+                      KernelMode,
+                      NULL,
+                      NULL,
+                      NULL,
+                      &Iosb,
+                      Buffer,
+                      1,
+                      &FileOffset,
+                      NULL);
+}
+
 VOID
 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
 {
@@ -176,14 +239,14 @@
 VOID
 MmFreeSectionSegments(PFILE_OBJECT FileObject)
 {
-   if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
    {
       PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
       PMM_SECTION_SEGMENT SectionSegments;
       ULONG NrSegments;
       ULONG i;
 
-      ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
       NrSegments = ImageSectionObject->NrSegments;
       SectionSegments = ImageSectionObject->Segments;
       for (i = 0; i < NrSegments; i++)
@@ -198,13 +261,13 @@
       }
       ExFreePool(ImageSectionObject->Segments);
       ExFreePool(ImageSectionObject);
-      FileObject->SectionObjectPointer->ImageSectionObject = NULL;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);FileObject->SectionObjectPointer->ImageSectionObject = NULL;
    }
-   if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
    {
       PMM_SECTION_SEGMENT Segment;
 
-      Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
                 DataSectionObject;
 
       if (Segment->ReferenceCount != 0)
@@ -214,7 +277,7 @@
       }
       MmFreePageTablesSectionSegment(Segment);
       ExFreePool(Segment);
-      FileObject->SectionObjectPointer->DataSectionObject = NULL;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);FileObject->SectionObjectPointer->DataSectionObject = NULL;
    }
 }
 
@@ -374,7 +437,7 @@
                (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
          {
             NTSTATUS Status;
-            Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+            if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
             IsDirectMapped = TRUE;
             Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
             if (!NT_SUCCESS(Status))
@@ -494,7 +557,7 @@
    ULONG Length;
 
    FileObject = MemoryArea->Data.SectionData.Section->FileObject;
-   Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
    RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
    FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
    IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
@@ -1399,7 +1462,7 @@
    if (FileObject != NULL &&
        !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
    {
-      Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
 
       /*
        * If the file system is letting us go directly to the cache and the
@@ -1743,7 +1806,7 @@
    if (FileObject != NULL &&
          !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
    {
-      Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
 
       /*
        * If the file system is letting us go directly to the cache and the
@@ -2059,22 +2122,26 @@
          return;
 
       SectionSegments = Section->ImageSection->Segments;
-      NrSegments = Section->ImageSection->NrSegments;
-
-      for (i = 0; i < NrSegments; i++)
+      
+      if (SectionSegments)
       {
-         if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
-         {
-            MmLockSectionSegment(&SectionSegments[i]);
-         }
-         RefCount = InterlockedDecrement(&SectionSegments[i].ReferenceCount);
-         if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
+         NrSegments = Section->ImageSection->NrSegments;
+   
+         for (i = 0; i < NrSegments; i++)
          {
-            if (RefCount == 0)
+            if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
             {
-               MmpFreePageFileSegment(&SectionSegments[i]);
+               MmLockSectionSegment(&SectionSegments[i]);
+            }
+            RefCount = InterlockedDecrement(&SectionSegments[i].ReferenceCount);
+            if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
+            {
+               if (RefCount == 0)
+               {
+                  MmpFreePageFileSegment(&SectionSegments[i]);
+               }
+               MmUnlockSectionSegment(&SectionSegments[i]);
             }
-            MmUnlockSectionSegment(&SectionSegments[i]);
          }
       }
    }
@@ -2410,7 +2477,7 @@
       }
    }
 
-   if (FileObject->SectionObjectPointer == NULL ||
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (FileObject->SectionObjectPointer == NULL ||
          FileObject->SectionObjectPointer->SharedCacheMap == NULL)
    {
       /*
@@ -2434,7 +2501,7 @@
          ObDereferenceObject(FileObject);
          return(Status);
       }
-      if (FileObject->SectionObjectPointer == NULL ||
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (FileObject->SectionObjectPointer == NULL ||
             FileObject->SectionObjectPointer->SharedCacheMap == NULL)
       {
          /* FIXME: handle this situation */
@@ -2459,7 +2526,7 @@
     * If this file hasn't been mapped as a data file before then allocate a
     * section segment to describe the data file mapping
     */
-   if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
    {
       Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
                                       TAG_MM_SECTION_SEGMENT);
@@ -2477,7 +2544,7 @@
        * Set the lock before assigning the segment to the file object
        */
       ExAcquireFastMutex(&Segment->Lock);
-      FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
 
       Segment->FileOffset = 0;
       Segment->Protection = SectionPageProtection;
@@ -2501,7 +2568,7 @@
        * If the file is already mapped as a data file then we may need
        * to extend it
        */
-      Segment =
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Segment =
          (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
          DataSectionObject;
       Section->Segment = Segment;
@@ -2549,11 +2616,437 @@
  PeFmtCreateSection
 };
 
-static PMM_SECTION_SEGMENT NTAPI MmspAllocateSegments(IN ULONG NrSegments)
+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 PFILE_OBJECT FileObject,
+                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;
+
+   Status = MmspPageRead(FileObject,
+                         Buffer,
+                         BufferSize,
+                         &FileOffset,
+                         &UsedSize);
+
+   if(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 )
+   {
+      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
+)
 {
- return ExAllocatePoolWithTag(NonPagedPool,
-                              sizeof(MM_SECTION_SEGMENT) * NrSegments,
-                              TAG_MM_SECTION_SEGMENT);
+   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
@@ -2597,9 +3090,9 @@
     */
    Section->SectionPageProtection = SectionPageProtection;
    Section->AllocationAttributes = AllocationAttributes;
+   Section->ImageSection = NULL;
    InitializeListHead(&Section->ViewListHead);
    KeInitializeSpinLock(&Section->ViewListLock);
-   Section->FileObject = FileObject;
 
    /*
     * Initialized caching for this file object if previously caching
@@ -2607,12 +3100,21 @@
     */
    Status = CcTryToInitializeFileCache(FileObject);
 
-   if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
+   if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
    {
       LARGE_INTEGER Offset;
       PVOID FileHeader;
       ULONG FileHeaderSize;
       ULONG Flags;
+      ULONG OldNrSegments;
+      NTSTATUS StatusExeFmt;
+
+      Status = MmspInitializeFileCache(FileObject);
+
+      if (!NT_SUCCESS(Status))
+      {
+         goto l_DereferenceSection;
+      }
 
       /*
        * Allocate the image section object
@@ -2675,43 +3177,100 @@
       {
          ImageSectionObject->Segments = NULL;
 
-         Status = ExeFmtpLoaders[i](FileHeader,
-                                    FileHeaderSize,
-                                    FileObject,
-                                    ImageSectionObject,
-                                    &Flags,
-                                    MmspPageRead,
-                                    MmspAllocateSegments);
+         StatusExeFmt = ExeFmtpLoaders[i](FileHeader,
+                                          FileHeaderSize,
+                                          FileObject,
+                                          ImageSectionObject,
+                                          &Flags,
+                                          ExeFmtpReadFile,
+                                          ExeFmtpAllocateSegments);
 
-         if (!NT_SUCCESS(Status))
+         if (!NT_SUCCESS(StatusExeFmt))
          {
             if (ImageSectionObject->Segments)
+            {
                ExFreePool(ImageSectionObject->Segments);
+               ImageSectionObject->Segments = NULL;
+            }
          }
 
-         if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+         if (StatusExeFmt != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
             break;
       }
 
       /*
        * No loader handled the format
        */
-      if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+      if (StatusExeFmt == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
+      {
          Status = STATUS_INVALID_IMAGE_FORMAT;
+         ASSERT(!NT_SUCCESS(Status));
+      }
+      else
+      {
+         Status = StatusExeFmt;
+      }
 
       ExFreePool(FileHeader);
 
       if (!NT_SUCCESS(Status))
+      {
          goto l_UnlockFile;
+      }
 
       /*
        * And now the fun part: fixing the segments
        */
-      if (!(Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_OK))
+
+      /* Sort them by virtual address */
+      MmspSortSegments(ImageSectionObject, Flags);
+
+      Status = STATUS_INVALID_IMAGE_FORMAT;
+
+      /* Ensure they don't overlap in memory */
+      if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
+      {
+         goto l_UnlockFile;
+      }
+
+      /* Ensure they are aligned */
+      OldNrSegments = ImageSectionObject->NrSegments;
+
+      if (!MmspPageAlignSegments(ImageSectionObject, Flags))
+      {
+         goto l_UnlockFile;
+      }
+
+      /* 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;
+
+         Status = STATUS_INSUFFICIENT_RESOURCES;
+
+         Segments = ExAllocatePoolWithTag(NonPagedPool,
+                                          SizeOfSegments,
+                                          TAG_MM_SECTION_SEGMENT);
+
+         if (Segments == NULL)
+            goto l_UnlockFile;
+
+         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;
       }
 
-      if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
                                           (LONG)ImageSectionObject, 0))
       {
          /*
@@ -2719,7 +3278,7 @@
           */
          ExFreePool(ImageSectionObject->Segments);
          ExFreePool(ImageSectionObject);
-         ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
+         if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
          Section->ImageSection = ImageSectionObject;
 
          for (i = 0; i < ImageSectionObject->NrSegments; i++)
@@ -2728,12 +3287,24 @@
          }
       }
 
+      ASSERT(NT_SUCCESS(StatusExeFmt));
+      Status = StatusExeFmt;
       goto l_Success;
 
-l_UnlockFile:         MmspReleaseFileLock(FileObject);
-l_FreeImageSection:   ExFreePool(ImageSectionObject);
-l_DereferenceSection: ObDereferenceObject(Section);
-                      return Status;
+l_UnlockFile:
+      MmspReleaseFileLock(FileObject);
+
+l_FreeImageSection:
+      if (ImageSectionObject->Segments)
+         ExFreePool(ImageSectionObject->Segments);
+
+      ExFreePool(ImageSectionObject);
+      Section->ImageSection = NULL;
+
+l_DereferenceSection:
+      ObDereferenceObject(Section);
+
+      return Status;
 
 l_Success:
       (void)0;
@@ -2750,7 +3321,7 @@
          return(Status);
       }
 
-      ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
+      if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
       Section->ImageSection = ImageSectionObject;
 
       /*
@@ -2764,6 +3335,7 @@
       Status = STATUS_SUCCESS;
    }
 
+   Section->FileObject = FileObject;
    CcRosReferenceCache(FileObject);
    MmspReleaseFileLock(FileObject);
    *SectionObject = Section;
@@ -3080,7 +3652,7 @@
       if (Page == PFN_FROM_SSE(Entry) && Dirty)
       {
          FileObject = MemoryArea->Data.SectionData.Section->FileObject;
-         Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+         if(FileObject->SectionObjectPointer == (PVOID)0xCCCCCCCC) KEBUGCHECK(0);Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
          CcRosMarkDirtyCacheSegment(Bcb, Offset);
          ASSERT(SwapEntry == 0);
       }
@@ -3999,36 +4571,83 @@
                  IN ULONG   SectionPageProtection,
                  IN ULONG   AllocationAttributes,
                  IN HANDLE   FileHandle   OPTIONAL,
-                 IN PFILE_OBJECT  File      OPTIONAL)
+                 IN PFILE_OBJECT  FileObject    OPTIONAL)
 {
-   if (AllocationAttributes & SEC_IMAGE)
+   NTSTATUS Status;
+   ACCESS_MASK DesiredFileAccess = 0;
+
+   /*
+    * If both are NULL, we create a paging file section. Otherwise, FileObject 
+    * takes precedence
+    */
+   if(FileObject == NULL && FileHandle != NULL)
    {
-      return(MmCreateImageSection(SectionObject,
-                                  DesiredAccess,
-                                  ObjectAttributes,
-                                  MaximumSize,
-                                  SectionPageProtection,
-                                  AllocationAttributes,
-                                  FileHandle));
+      if(SectionPageProtection & PAGE_IS_READABLE)
+         DesiredFileAccess |= FILE_READ_DATA;
+   
+      if(SectionPageProtection & PAGE_IS_WRITABLE)
+      {
+         if(SectionPageProtection & PAGE_IS_WRITECOPY)
+            DesiredFileAccess |= FILE_READ_DATA;
+         else
+            DesiredFileAccess |= FILE_READ_DATA | FILE_WRITE_DATA;
+      }
+   
+      if(SectionPageProtection & PAGE_IS_EXECUTABLE)
+         DesiredFileAccess |= FILE_EXECUTE;
+   
+      Status = ObReferenceObjectByHandle(FileHandle,
+                                         DesiredFileAccess,
+                                         IoFileObjectType,
+                                         ExGetPreviousMode(),
+                                         (PVOID *)&FileObject,
+                                         NULL);
+
+      if(!NT_SUCCESS(Status))
+         return Status;
+
+      ASSERT(FileObject);
    }
 
-   if (FileHandle != NULL)
+   if (AllocationAttributes & SEC_IMAGE)
    {
-      return(MmCreateDataFileSection(SectionObject,
+      Status = MmCreateImageSection(SectionObject,
+                                    DesiredAccess,
+                                    ObjectAttributes,
+                                    MaximumSize,
+                                    SectionPageProtection,
+                                    AllocationAttributes,
+                                    FileObject);
+   }
+   /*
+    * TODO: MmCreateDataFileSection is too tied to the use of a handle to change
+    * it now. Note to self: change it later
+    */
+   else if (FileHandle != NULL)
+   /* else if (FileObject != NULL) */
+   {
+      Status = MmCreateDataFileSection(SectionObject,
+                                       DesiredAccess,
+                                       ObjectAttributes,
+                                       MaximumSize,
+                                       SectionPageProtection,
+                                       AllocationAttributes,
+                                       FileHandle);
+   }
+   else
+   {
+      return MmCreatePageFileSection(SectionObject,
                                      DesiredAccess,
[truncated at 1000 lines; 21 more skipped]
CVSspam 0.2.8