-/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+/* $Id$
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * You should have received a copy of the GNU General Public License
- * 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 $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/section.c
* PURPOSE: Implements section objects
- * PROGRAMMER: David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- * Created 22/05/98
+ *
+ * PROGRAMMERS: Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Hartmut Birr
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include <internal/debug.h>
+#include <reactos/exeformat.h>
+
/* TYPES *********************************************************************/
typedef struct
STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
SECTION_ALL_ACCESS};
-#define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
-#define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
-
#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
#define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
#define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
+static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
+{
+ ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
+ ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
+};
+
/* FUNCTIONS *****************************************************************/
/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
}
VOID
+NTAPI
MmFreeSectionSegments(PFILE_OBJECT FileObject)
{
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
}
MmFreePageTablesSectionSegment(&SectionSegments[i]);
}
+ ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
FileObject->SectionObjectPointer->ImageSectionObject = NULL;
}
}
VOID
+NTAPI
MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
{
ExAcquireFastMutex(&Segment->Lock);
}
VOID
+NTAPI
MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
{
ExReleaseFastMutex(&Segment->Lock);
}
VOID
+NTAPI
MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
ULONG Offset,
ULONG Entry)
{
Table =
Segment->PageDirectory.PageTables[DirectoryOffset] =
- ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
+ ExAllocatePoolWithTag(PagedPool, sizeof(SECTION_PAGE_TABLE),
TAG_SECTION_PAGE_TABLE);
if (Table == NULL)
{
ULONG
+NTAPI
MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
ULONG Offset)
{
}
VOID
+NTAPI
MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
ULONG Offset)
{
}
BOOLEAN
+NTAPI
MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
PMM_SECTION_SEGMENT Segment,
ULONG Offset,
Page = PFN_FROM_SSE(Entry);
FileObject = Section->FileObject;
if (FileObject != NULL &&
- !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
if ((FileOffset % PAGE_SIZE) == 0 &&
{
if (!PageOut &&
((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
- (Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)))
+ (Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
{
/*
* FIXME:
else
{
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
- (Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ (Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
if (!PageOut)
{
{
/*
* FIXME:
- * We hold all locks. Nobody can do something with the current
+ * We hold all locks. Nobody can do something with the current
* process and the current segment (also not within an other process).
*/
NTSTATUS Status;
BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
ULONG SegOffset)
{
- if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
PBCB Bcb;
PCACHE_SEGMENT CacheSeg;
}
NTSTATUS
+NTAPI
MiReadPage(PMEMORY_AREA MemoryArea,
ULONG SegOffset,
PPFN_TYPE Page)
*/
if ((FileOffset % PAGE_SIZE) == 0 &&
(SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
- !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
/*
return Status;
}
}
- PageAddr = ExAllocatePageWithPhysPage(*Page);
+ PageAddr = MmCreateHyperspaceMapping(*Page);
CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
Length = RawLength - SegOffset;
if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
&CacheSeg);
if (!NT_SUCCESS(Status))
{
- ExUnmapPage(PageAddr);
+ MmDeleteHyperspaceMapping(PageAddr);
return(Status);
}
if (!UptoDate)
if (!NT_SUCCESS(Status))
{
CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
- ExUnmapPage(PageAddr);
+ MmDeleteHyperspaceMapping(PageAddr);
return Status;
}
}
}
}
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
- ExUnmapPage(PageAddr);
+ MmDeleteHyperspaceMapping(PageAddr);
}
return(STATUS_SUCCESS);
}
NTSTATUS
+NTAPI
MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
ULONG Offset;
PFN_TYPE Page;
NTSTATUS Status;
- ULONG PAddress;
+ PVOID PAddress;
PSECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
ULONG Entry;
return(STATUS_SUCCESS);
}
- PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
- Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
+ PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+ Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
Segment = MemoryArea->Data.SectionData.Segment;
Section = MemoryArea->Data.SectionData.Section;
- Region = MmFindRegion(MemoryArea->BaseAddress,
+ Region = MmFindRegion(MemoryArea->StartingAddress,
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
/*
/*
* Get or create a page operation descriptor
*/
- PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
+ PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
if (PageOp == NULL)
{
DPRINT1("MmGetPageOp failed\n");
if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
{
/*
- * The page was a private page in another or in our address space
+ * The page was a private page in another or in our address space
*/
MmUnlockSectionSegment(Segment);
MmspCompleteAndReleasePageOp(PageOp);
MmSharePageEntrySectionSegment(Segment, Offset);
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
+ * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
+ */
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
Attributes,
&Page,
DbgPrint("Unable to create virtual mapping\n");
KEBUGCHECK(0);
}
- MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
+ MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
}
if (Locked)
{
/*
* Just map the desired physical page
*/
- Page = (Offset + MemoryArea->Data.SectionData.ViewOffset) >> PAGE_SHIFT;
- Status = MmCreateVirtualMapping(AddressSpace->Process,
- Address,
- Region->Protect,
- &Page,
- 1);
+ Page = Offset >> PAGE_SHIFT;
+ Status = MmCreateVirtualMappingUnsafe(AddressSpace->Process,
+ Address,
+ Region->Protect,
+ &Page,
+ 1);
if (!NT_SUCCESS(Status))
{
- DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
+ DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
KEBUGCHECK(0);
return(Status);
}
*/
if (Locked)
{
- MmLockPage(Page);
+ MmLockPageUnsafe(Page);
}
/*
/*
* Map anonymous memory for BSS sections
*/
- if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
+ if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
{
MmUnlockSectionSegment(Segment);
Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
/*
* Get the entry corresponding to the offset within the section
*/
- Offset += MemoryArea->Data.SectionData.ViewOffset;
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry == 0)
}
NTSTATUS
+NTAPI
MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
PSECTION_OBJECT Section;
PFN_TYPE OldPage;
PFN_TYPE NewPage;
- PVOID NewAddress;
NTSTATUS Status;
- ULONG PAddress;
+ PVOID PAddress;
ULONG Offset;
PMM_PAGEOP PageOp;
PMM_REGION Region;
/*
* Find the offset of the page
*/
- PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
- Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
+ PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+ Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
Segment = MemoryArea->Data.SectionData.Segment;
Section = MemoryArea->Data.SectionData.Section;
- Region = MmFindRegion(MemoryArea->BaseAddress,
+ Region = MmFindRegion(MemoryArea->StartingAddress,
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
/*
PFN_FROM_SSE(Entry) != OldPage)
{
/* This is a private page. We must only change the page protection. */
- MmSetPageProtect(AddressSpace->Process, (PVOID)PAddress, Region->Protect);
+ MmSetPageProtect(AddressSpace->Process, PAddress, Region->Protect);
return(STATUS_SUCCESS);
}
/*
* Get or create a pageop
*/
- PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
+ PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
MM_PAGEOP_ACCESSFAULT, FALSE);
if (PageOp == NULL)
{
/*
* Copy the old page
*/
+ MiCopyFromUserPage(NewPage, PAddress);
- NewAddress = ExAllocatePageWithPhysPage(NewPage);
- memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
- ExUnmapPage(NewAddress);
-
+ MmLockAddressSpace(AddressSpace);
/*
* Delete the old entry.
*/
/*
* Set the PTE to point to the new page
*/
- MmLockAddressSpace(AddressSpace);
Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
Region->Protect,
KEBUGCHECK(0);
return(Status);
}
- MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
if (!NT_SUCCESS(Status))
{
DbgPrint("Unable to create virtual mapping\n");
/*
* Unshare the old page.
*/
- MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
+ MmDeleteRmap(OldPage, AddressSpace->Process, PAddress);
+ MmInsertRmap(NewPage, AddressSpace->Process, PAddress);
MmLockSectionSegment(Segment);
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
MmUnlockSectionSegment(Segment);
PFN_TYPE Page;
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
+ if (Process)
+ {
+ MmLockAddressSpace(&Process->AddressSpace);
+ }
+
MmDeleteVirtualMapping(Process,
Address,
FALSE,
}
if (!PageOutContext->Private)
{
+ MmLockSectionSegment(PageOutContext->Segment);
MmUnsharePageEntrySectionSegment(PageOutContext->Section,
PageOutContext->Segment,
PageOutContext->Offset,
PageOutContext->WasDirty,
TRUE);
+ MmUnlockSectionSegment(PageOutContext->Segment);
}
- else
+ if (Process)
+ {
+ MmUnlockAddressSpace(&Process->AddressSpace);
+ }
+
+ if (PageOutContext->Private)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
- DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
+ DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
}
NTSTATUS
+NTAPI
MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
Context.Segment = MemoryArea->Data.SectionData.Segment;
Context.Section = MemoryArea->Data.SectionData.Section;
- Context.Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
+ Context.Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
FileOffset = Context.Offset + Context.Segment->FileOffset;
IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
FileObject = Context.Section->FileObject;
DirectMapped = FALSE;
if (FileObject != NULL &&
- !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
* Prepare the context structure for the rmap delete call.
*/
Context.WasDirty = FALSE;
- if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
+ if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
IS_SWAP_FROM_SSE(Entry) ||
PFN_FROM_SSE(Entry) != Page)
{
if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
{
if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
- !(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
KEBUGCHECK(0);
}
return(STATUS_SUCCESS);
}
}
- else if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
+ else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
{
if (Context.Private)
{
else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
{
MmSetSavedSwapEntryPage(Page, 0);
+ MmLockAddressSpace(AddressSpace);
Status = MmCreatePageFileMapping(AddressSpace->Process,
Address,
SwapEntry);
+ MmUnlockAddressSpace(AddressSpace);
if (!NT_SUCCESS(Status))
{
KEBUGCHECK(0);
if (SwapEntry == 0)
{
MmShowOutOfSpaceMessagePagingFile();
-
+ MmLockAddressSpace(AddressSpace);
/*
* For private pages restore the old mappings.
*/
if (Context.Private)
{
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
MemoryArea->Attributes,
&Page,
1);
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
MmInsertRmap(Page,
- MemoryArea->Process,
+ AddressSpace->Process,
Address);
}
else
* set it back into the section segment entry so we don't loose
* our copy. Otherwise it will be handled by the cache manager.
*/
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
MemoryArea->Attributes,
&Page,
1);
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
MmInsertRmap(Page,
- MemoryArea->Process,
+ AddressSpace->Process,
Address);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
}
+ MmUnlockAddressSpace(AddressSpace);
PageOp->Status = STATUS_UNSUCCESSFUL;
MmspCompleteAndReleasePageOp(PageOp);
return(STATUS_PAGEFILE_QUOTA);
* As above: undo our actions.
* FIXME: Also free the swap page.
*/
+ MmLockAddressSpace(AddressSpace);
if (Context.Private)
{
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
MemoryArea->Attributes,
&Page,
1);
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
MmInsertRmap(Page,
- MemoryArea->Process,
+ AddressSpace->Process,
Address);
}
else
{
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
MemoryArea->Attributes,
&Page,
1);
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
MmInsertRmap(Page,
- MemoryArea->Process,
+ AddressSpace->Process,
Address);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
}
+ MmUnlockAddressSpace(AddressSpace);
PageOp->Status = STATUS_UNSUCCESSFUL;
MmspCompleteAndReleasePageOp(PageOp);
return(STATUS_UNSUCCESSFUL);
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
MmSetSavedSwapEntryPage(Page, 0);
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
- Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)
+ Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
{
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
}
if (Context.Private)
{
- Status = MmCreatePageFileMapping(MemoryArea->Process,
+ MmLockAddressSpace(AddressSpace);
+ Status = MmCreatePageFileMapping(AddressSpace->Process,
Address,
SwapEntry);
+ MmUnlockAddressSpace(AddressSpace);
if (!NT_SUCCESS(Status))
{
KEBUGCHECK(0);
}
NTSTATUS
+NTAPI
MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
Address = (PVOID)PAGE_ROUND_DOWN(Address);
- Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
+ Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
/*
* Get the segment and section.
FileObject = Section->FileObject;
DirectMapped = FALSE;
if (FileObject != NULL &&
- !(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
+ !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
* memory area was mapped at an offset in the file which is page aligned
* then note this is a direct mapped page.
*/
- if ((Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
+ if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
(Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
{
DirectMapped = TRUE;
/*
* Check for a private (COWed) page.
*/
- if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
+ if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
IS_SWAP_FROM_SSE(Entry) ||
PFN_FROM_SSE(Entry) != Page)
{
if (DirectMapped && !Private)
{
ASSERT(SwapEntry == 0);
- CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
+ CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
PageOp->Status = STATUS_SUCCESS;
MmspCompleteAndReleasePageOp(PageOp);
return(STATUS_SUCCESS);
BOOL DoCOW = FALSE;
ULONG i;
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
Segment = MemoryArea->Data.SectionData.Segment;
if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
ULONG Entry;
PFN_TYPE Page;
- Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
+ Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
Page = MmGetPfnForProcess(AddressSpace->Process, Address);
Protect = PAGE_READONLY;
- if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
+ if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
IS_SWAP_FROM_SSE(Entry) ||
PFN_FROM_SSE(Entry) != Page)
{
}
NTSTATUS
+NTAPI
MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID BaseAddress,
{
PMM_REGION Region;
NTSTATUS Status;
+ ULONG_PTR MaxLength;
- Length =
- min(Length, (ULONG) ((char*)MemoryArea->BaseAddress + MemoryArea->Length - (char*)BaseAddress));
- Region = MmFindRegion(MemoryArea->BaseAddress,
+ MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
+ if (Length > MaxLength)
+ Length = MaxLength;
+
+ Region = MmFindRegion(MemoryArea->StartingAddress,
&MemoryArea->Data.SectionData.RegionListHead,
BaseAddress, NULL);
*OldProtect = Region->Protect;
- Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
+ Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
&MemoryArea->Data.SectionData.RegionListHead,
BaseAddress, Length, Region->Type, Protect,
MmAlterViewAttributes);
PMM_REGION Region;
PVOID RegionBaseAddress;
PSECTION_OBJECT Section;
- PLIST_ENTRY CurrentEntry;
- PMEMORY_AREA CurrentMArea;
- KIRQL oldIrql;
+ PMM_SECTION_SEGMENT Segment;
- Region = MmFindRegion(MemoryArea->BaseAddress,
+ Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
&MemoryArea->Data.SectionData.RegionListHead,
Address, &RegionBaseAddress);
if (Region == NULL)
{
return STATUS_UNSUCCESSFUL;
}
+
Section = MemoryArea->Data.SectionData.Section;
if (Section->AllocationAttributes & SEC_IMAGE)
{
- KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
- CurrentEntry = Section->ViewListHead.Flink;
- Info->AllocationBase = NULL;
- while (CurrentEntry != &Section->ViewListHead)
- {
- CurrentMArea = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Data.SectionData.ViewListEntry);
- CurrentEntry = CurrentEntry->Flink;
- if (Info->AllocationBase == NULL)
- {
- Info->AllocationBase = CurrentMArea->BaseAddress;
- }
- else if (CurrentMArea->BaseAddress < Info->AllocationBase)
- {
- Info->AllocationBase = CurrentMArea->BaseAddress;
- }
- }
- KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
- Info->BaseAddress = RegionBaseAddress;
- Info->AllocationProtect = MemoryArea->Attributes;
+ Segment = MemoryArea->Data.SectionData.Segment;
+ Info->AllocationBase = (PBYTE)MemoryArea->StartingAddress - Segment->VirtualAddress;
Info->Type = MEM_IMAGE;
}
else
{
- Info->BaseAddress = RegionBaseAddress;
- Info->AllocationBase = MemoryArea->BaseAddress;
- Info->AllocationProtect = MemoryArea->Attributes;
+ Info->AllocationBase = MemoryArea->StartingAddress;
Info->Type = MEM_MAPPED;
}
- Info->RegionSize = PAGE_ROUND_UP(MemoryArea->Length);
+ Info->BaseAddress = RegionBaseAddress;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->RegionSize = Region->Length;
Info->State = MEM_COMMIT;
Info->Protect = Region->Protect;
}
VOID
+NTAPI
MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
{
ULONG Length;
for (i = 0; i < NrSegments; i++)
{
- if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
+ if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
{
MmLockSectionSegment(&SectionSegments[i]);
}
RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
- if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
+ if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
{
if (RefCount == 0)
{
ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
}
-NTSTATUS STDCALL
-MmpCreateSection(PVOID ObjectBody,
- PVOID Parent,
- PWSTR RemainingPath,
- POBJECT_ATTRIBUTES ObjectAttributes)
-{
- DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
- ObjectBody, Parent, RemainingPath);
-
- if (RemainingPath == NULL)
- {
- return(STATUS_SUCCESS);
- }
-
- if (wcschr(RemainingPath+1, L'\\') != NULL)
- {
- return(STATUS_UNSUCCESSFUL);
- }
- return(STATUS_SUCCESS);
-}
-
-NTSTATUS INIT_FUNCTION
+NTSTATUS
+INIT_FUNCTION
+NTAPI
MmCreatePhysicalMemorySection(VOID)
{
PSECTION_OBJECT PhysSection;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obj;
- UNICODE_STRING Name = ROS_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
+ UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
LARGE_INTEGER SectionSize;
/*
SectionSize.QuadPart = 0xFFFFFFFF;
InitializeObjectAttributes(&Obj,
&Name,
- 0,
+ OBJ_PERMANENT,
NULL,
NULL);
Status = MmCreateSection(&PhysSection,
DbgPrint("Failed to create PhysicalMemory section\n");
KEBUGCHECK(0);
}
+ Status = ObInsertObject(PhysSection,
+ NULL,
+ SECTION_ALL_ACCESS,
+ 0,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(PhysSection);
+ }
PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
+ PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
return(STATUS_SUCCESS);
}
-NTSTATUS INIT_FUNCTION
+NTSTATUS
+INIT_FUNCTION
+NTAPI
MmInitSectionImplementation(VOID)
{
- MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
-
- RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
-
- MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
- MmSectionObjectType->TotalObjects = 0;
- MmSectionObjectType->TotalHandles = 0;
- MmSectionObjectType->MaxObjects = ULONG_MAX;
- MmSectionObjectType->MaxHandles = ULONG_MAX;
- MmSectionObjectType->PagedPoolCharge = 0;
- MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
- MmSectionObjectType->Mapping = &MmpSectionMapping;
- MmSectionObjectType->Dump = NULL;
- MmSectionObjectType->Open = NULL;
- MmSectionObjectType->Close = MmpCloseSection;
- MmSectionObjectType->Delete = MmpDeleteSection;
- MmSectionObjectType->Parse = NULL;
- MmSectionObjectType->Security = NULL;
- MmSectionObjectType->QueryName = NULL;
- MmSectionObjectType->OkayToClose = NULL;
- MmSectionObjectType->Create = MmpCreateSection;
- MmSectionObjectType->DuplicationNotify = NULL;
-
- /*
- * NOTE: Do not register the section object type here because
- * the object manager it not initialized yet!
- * The section object type will be created in ObInit().
- */
- ObpCreateTypeObject(MmSectionObjectType);
+ OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+ UNICODE_STRING Name;
+
+ DPRINT("Creating Section Object Type\n");
+
+ /* Initialize the Section object type */
+ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+ RtlInitUnicodeString(&Name, L"Section");
+ ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+ ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION_OBJECT);
+ ObjectTypeInitializer.PoolType = PagedPool;
+ ObjectTypeInitializer.UseDefaultObject = TRUE;
+ ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
+ ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
+ ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
+ ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &MmSectionObjectType);
return(STATUS_SUCCESS);
}
NTSTATUS
+NTAPI
MmCreatePageFileSection(PSECTION_OBJECT *SectionObject,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
Section->Segment = NULL;
- InitializeListHead(&Section->ViewListHead);
- KeInitializeSpinLock(&Section->ViewListLock);
Section->FileObject = NULL;
Section->MaximumSize = MaximumSize;
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
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;
NTSTATUS
+NTAPI
MmCreateDataFileSection(PSECTION_OBJECT *SectionObject,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
{
return(Status);
}
-
/*
* Initialize it
*/
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
Section->Segment = NULL;
- InitializeListHead(&Section->ViewListHead);
- KeInitializeSpinLock(&Section->ViewListLock);
/*
* Check file access required
* (as in case of the EXT2FS driver by Manoj Paul Joseph where the
* standard file information is filled on first request).
*/
- Status = NtQueryInformationFile(FileHandle,
- &Iosb,
- &FileInfo,
+ Status = IoQueryFileInformation(FileObject,
+ FileStandardInformation,
sizeof(FILE_STANDARD_INFORMATION),
- FileStandardInformation);
+ &FileInfo,
+ &Iosb.Information);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Section);
if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
{
- Status = NtSetInformationFile(FileHandle,
- &Iosb,
- &MaximumSize,
- sizeof(LARGE_INTEGER),
- FileAllocationInformation);
+ Status = IoSetInformation(FileObject,
+ FileAllocationInformation,
+ sizeof(LARGE_INTEGER),
+ &MaximumSize);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Section);
Segment->FileOffset = 0;
Segment->Protection = SectionPageProtection;
- Segment->Attributes = 0;
Segment->Flags = MM_DATAFILE_SEGMENT;
Segment->Characteristics = 0;
Segment->WriteCopy = FALSE;
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
return(STATUS_SUCCESS);
}
-static ULONG SectionCharacteristicsToProtect[16] =
- {
- 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
- };
+/*
+ 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
-MmCreateImageSection(PSECTION_OBJECT *SectionObject,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes,
- PLARGE_INTEGER UMaximumSize,
- ULONG SectionPageProtection,
- ULONG AllocationAttributes,
- HANDLE FileHandle)
+NTAPI
+ExeFmtpReadFile(IN PVOID File,
+ IN PLARGE_INTEGER Offset,
+ IN ULONG Length,
+ OUT PVOID * Data,
+ OUT PVOID * AllocBase,
+ OUT PULONG ReadSize)
{
- 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;
+ LARGE_INTEGER FileOffset;
+ ULONG AdjustOffset;
+ ULONG OffsetAdjustment;
+ ULONG BufferSize;
+ ULONG UsedSize;
+ PVOID Buffer;
- /*
- * Specifying a maximum size is meaningless for an image section
- */
- if (UMaximumSize != NULL)
+ ASSERT_IRQL_LESS(DISPATCH_LEVEL);
+
+ if(Length == 0)
{
- return(STATUS_INVALID_PARAMETER_4);
+ KEBUGCHECK(STATUS_INVALID_PARAMETER_4);
}
- /*
- * Reference the file handle
- */
- Status = ObReferenceObjectByHandle(FileHandle,
- FileAccess,
- IoFileObjectType,
- UserMode,
- (PVOID*)(PVOID)&FileObject,
- NULL);
- if (!NT_SUCCESS(Status))
+ FileOffset = *Offset;
+
+ /* Negative/special offset: it cannot be used in this context */
+ if(FileOffset.u.HighPart < 0)
{
- return Status;
+ KEBUGCHECK(STATUS_INVALID_PARAMETER_5);
}
+ AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
+ OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
+ FileOffset.u.LowPart = AdjustOffset;
+
+ BufferSize = Length + OffsetAdjustment;
+ BufferSize = PAGE_ROUND_UP(BufferSize);
+
/*
- * Initialized caching for this file object if previously caching
- * was initialized for the same on disk file
+ * 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
*/
- Status = CcTryToInitializeFileCache(FileObject);
-
- if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
+ 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
+ */
{
- PIMAGE_SECTION_HEADER ImageSections;
- /*
- * Read the dos header and check the DOS signature
- */
- Offset.QuadPart = 0;
- Status = ZwReadFile(FileHandle,
+ IO_STATUS_BLOCK Iosb;
+
+ Status = ZwReadFile(File,
NULL,
NULL,
NULL,
&Iosb,
- &DosHeader,
- sizeof(DosHeader),
- &Offset,
+ Buffer,
+ BufferSize,
+ &FileOffset,
NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(FileObject);
- return(Status);
- }
- /*
- * Check the DOS signature
- */
- if (Iosb.Information != sizeof(DosHeader) ||
- DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
+ if(NT_SUCCESS(Status))
{
- ObDereferenceObject(FileObject);
- return(STATUS_INVALID_IMAGE_FORMAT);
+ UsedSize = Iosb.Information;
}
+ }
+#endif
- /*
- * 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);
- }
+ if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
+ {
+ Status = STATUS_IN_PAGE_ERROR;
+ ASSERT(!NT_SUCCESS(Status));
+ }
- /*
- * Check the signature
- */
- if (Iosb.Information != sizeof(PEHeader) ||
- PEHeader.Signature != IMAGE_NT_SIGNATURE)
- {
- ObDereferenceObject(FileObject);
- return(STATUS_INVALID_IMAGE_FORMAT);
- }
+ if(NT_SUCCESS(Status))
+ {
+ *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
+ *AllocBase = Buffer;
+ *ReadSize = UsedSize - OffsetAdjustment;
+ }
+ else
+ {
+ ExFreePool(Buffer);
+ }
- /*
- * 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)
- {
- ObDereferenceObject(FileObject);
- return(STATUS_NO_MEMORY);
- }
+ return Status;
+}
- 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);
- }
+#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;
- /*
- * Create the section
- */
- Status = ObCreateObject (ExGetPreviousMode(),
- MmSectionObjectType,
- ObjectAttributes,
- ExGetPreviousMode(),
- NULL,
- sizeof(SECTION_OBJECT),
- 0,
- 0,
- (PVOID*)(PVOID)&Section);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(Status);
- }
+ for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+ ImageSectionObject->Segments[i - 1].VirtualAddress);
+ }
+}
- /*
- * Initialize it
- */
- Section->SectionPageProtection = SectionPageProtection;
- Section->AllocationAttributes = AllocationAttributes;
- Section->ImageSection = NULL;
- InitializeListHead(&Section->ViewListHead);
- KeInitializeSpinLock(&Section->ViewListLock);
+static
+VOID
+NTAPI
+MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
+{
+ ULONG i;
- /*
- * Check file access required
- */
- if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
- {
- FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
- }
- else
- {
- FileAccess = FILE_READ_DATA;
- }
+ MmspAssertSegmentsSorted(ImageSectionObject);
- /*
- * Lock the file
- */
- Status = MmspWaitForFileLock(FileObject);
- if (Status != STATUS_SUCCESS)
- {
- ObDereferenceObject(Section);
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(Status);
- }
+ for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ ASSERT(ImageSectionObject->Segments[i].Length > 0);
- /*
- * 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)
+ if(i > 0)
{
- KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
- ObDereferenceObject(Section);
- ObDereferenceObject(FileObject);
- ExFreePool(ImageSections);
- return(STATUS_NO_MEMORY);
+ ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
+ (ImageSectionObject->Segments[i - 1].VirtualAddress +
+ ImageSectionObject->Segments[i - 1].Length));
}
- 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;
- SectionSegments[0].WriteCopy = TRUE;
- SectionSegments[0].Attributes = 0;
- ExInitializeFastMutex(&SectionSegments[0].Lock);
- RtlZeroMemory(&SectionSegments[0].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
- for (i = 1; i < NrSegments; i++)
- {
- SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
- SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
+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);
+ }
+}
- /*
- * Set up the protection and write copy variables.
- */
- Characteristics = ImageSections[i - 1].Characteristics;
- if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
- {
- SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
- SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
- }
- else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
- {
- SectionSegments[i].Protection = PAGE_EXECUTE_READ;
- SectionSegments[i].WriteCopy = TRUE;
- }
- else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
- {
- SectionSegments[i].Protection = PAGE_READWRITE;
- SectionSegments[i].WriteCopy = TRUE;
- }
- else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
- {
- SectionSegments[i].Protection = PAGE_READWRITE;
- SectionSegments[i].WriteCopy = TRUE;
- }
- else
- {
- SectionSegments[i].Protection = PAGE_NOACCESS;
- SectionSegments[i].WriteCopy = TRUE;
- }
+/*
+ * 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)
+ {
/*
- * Set up the attributes.
+ * 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 (Characteristics & IMAGE_SECTION_CHAR_CODE)
+ if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
+ ImageSectionObject->Segments[i - 1].Length) !=
+ ImageSectionObject->Segments[i].VirtualAddress)
{
- SectionSegments[i].Attributes = 0;
+ return FALSE;
}
- else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
+ }
+ }
+
+ 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;
+ PMM_SECTION_SEGMENT EffectiveSegment;
+
+ if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
+ {
+ MmspAssertSegmentsPageAligned(ImageSectionObject);
+ return TRUE;
+ }
+
+ Initialized = FALSE;
+ LastSegment = 0;
+ EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+ for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
+ {
+ /*
+ * 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)
{
- SectionSegments[i].Attributes = 0;
+ return FALSE;
}
- else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
+
+ /*
+ * 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)
{
- SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
+ LastSegment ++;
+ ASSERT(LastSegment <= i);
+ ASSERT(LastSegment < ImageSectionObject->NrSegments);
+
+ EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
+
+ if (LastSegment != i)
+ {
+ /*
+ * 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);
}
- else
+ /*
+ * The current segment is still part of the current effective segment:
+ * extend the effective segment to reflect this
+ */
+ else if (EndOfEffectiveSegment > Segment->VirtualAddress)
{
- SectionSegments[i].Attributes = 0;
- }
+ 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;
- SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
- if (ImageSections[i-1].Misc.VirtualSize != 0)
- {
- SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
+ /*
+ * 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
{
- SectionSegments[i].Length = ImageSections[i-1].SizeOfRawData;
+ ASSERT(FALSE);
}
- SectionSegments[i].Flags = 0;
- SectionSegments[i].ReferenceCount = 1;
- SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
- ExInitializeFastMutex(&SectionSegments[i].Lock);
- RtlZeroMemory(&SectionSegments[i].PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
}
- if (0 != InterlockedCompareExchangeUL(&FileObject->SectionObjectPointer->ImageSectionObject,
- ImageSectionObject, 0))
- {
- /*
- * An other thread has initialized the some image in the background
- */
- ExFreePool(ImageSectionObject);
- ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
- Section->ImageSection = ImageSectionObject;
- SectionSegments = ImageSectionObject->Segments;
+ }
+ ImageSectionObject->NrSegments = LastSegment + 1;
+
+ 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;
- for (i = 0; i < NrSegments; 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)
{
- InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
+ ExFreePool(ImageSectionObject->Segments);
+ ImageSectionObject->Segments = NULL;
}
}
- ExFreePool(ImageSections);
+
+ 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_NOT_MZ;
+ 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(PagedPool,
+ 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,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ PLARGE_INTEGER UMaximumSize,
+ ULONG SectionPageProtection,
+ ULONG AllocationAttributes,
+ HANDLE FileHandle)
+{
+ PSECTION_OBJECT Section;
+ NTSTATUS Status;
+ PFILE_OBJECT FileObject;
+ PMM_SECTION_SEGMENT SectionSegments;
+ PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+ ULONG i;
+ ULONG FileAccess = 0;
+
+ /*
+ * Specifying a maximum size is meaningless for an image section
+ */
+ if (UMaximumSize != NULL)
+ {
+ return(STATUS_INVALID_PARAMETER_4);
+ }
+
+ /*
+ * Check file access required
+ */
+ if (SectionPageProtection & PAGE_READWRITE ||
+ SectionPageProtection & PAGE_EXECUTE_READWRITE)
+ {
+ FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
}
else
{
- /*
- * Create the section
- */
- Status = ObCreateObject (ExGetPreviousMode(),
- MmSectionObjectType,
- ObjectAttributes,
- ExGetPreviousMode(),
- NULL,
- sizeof(SECTION_OBJECT),
- 0,
- 0,
- (PVOID*)(PVOID)&Section);
- if (!NT_SUCCESS(Status))
+ FileAccess = FILE_READ_DATA;
+ }
+
+ /*
+ * Reference the file handle
+ */
+ Status = ObReferenceObjectByHandle(FileHandle,
+ FileAccess,
+ IoFileObjectType,
+ UserMode,
+ (PVOID*)(PVOID)&FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /*
+ * 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;
+
+ /*
+ * Initialized caching for this file object if previously caching
+ * was initialized for the same on disk file
+ */
+ Status = CcTryToInitializeFileCache(FileObject);
+
+ if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
+ {
+ NTSTATUS StatusExeFmt;
+
+ ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
+ if (ImageSectionObject == NULL)
{
ObDereferenceObject(FileObject);
- return(Status);
+ ObDereferenceObject(Section);
+ return(STATUS_NO_MEMORY);
}
+
+ RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
- /*
- * Initialize it
- */
- Section->SectionPageProtection = SectionPageProtection;
- Section->AllocationAttributes = AllocationAttributes;
- InitializeListHead(&Section->ViewListHead);
- KeInitializeSpinLock(&Section->ViewListLock);
+ StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
+
+ if (!NT_SUCCESS(StatusExeFmt))
+ {
+ if(ImageSectionObject->Segments != NULL)
+ ExFreePool(ImageSectionObject->Segments);
+
+ ExFreePool(ImageSectionObject);
+ ObDereferenceObject(Section);
+ ObDereferenceObject(FileObject);
+ return(StatusExeFmt);
+ }
+
+ Section->ImageSection = ImageSectionObject;
+ ASSERT(ImageSectionObject->Segments);
/*
- * Check file access required
+ * Lock the file
*/
- if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
+ Status = MmspWaitForFileLock(FileObject);
+ if (!NT_SUCCESS(Status))
{
- FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
+ ExFreePool(ImageSectionObject->Segments);
+ ExFreePool(ImageSectionObject);
+ ObDereferenceObject(Section);
+ ObDereferenceObject(FileObject);
+ return(Status);
}
- else
+
+ if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
+ ImageSectionObject, NULL))
{
- FileAccess = FILE_READ_DATA;
+ /*
+ * An other thread has initialized the some image in the background
+ */
+ ExFreePool(ImageSectionObject->Segments);
+ ExFreePool(ImageSectionObject);
+ ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
+ Section->ImageSection = ImageSectionObject;
+ SectionSegments = ImageSectionObject->Segments;
+
+ for (i = 0; i < ImageSectionObject->NrSegments; i++)
+ {
+ InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
+ }
}
+ Status = StatusExeFmt;
+ }
+ else
+ {
/*
* Lock the file
*/
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
Section->ImageSection = ImageSectionObject;
SectionSegments = ImageSectionObject->Segments;
- NrSegments = ImageSectionObject->NrSegments;
/*
* Otherwise just reference all the section segments
*/
- for (i = 0; i < NrSegments; i++)
+ for (i = 0; i < ImageSectionObject->NrSegments; i++)
{
InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
}
+ Status = STATUS_SUCCESS;
}
Section->FileObject = FileObject;
CcRosReferenceCache(FileObject);
KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
*SectionObject = Section;
- return(STATUS_SUCCESS);
+ return(Status);
}
/*
IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL)
{
+ LARGE_INTEGER SafeMaximumSize;
PSECTION_OBJECT SectionObject;
- NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PreviousMode = ExGetPreviousMode();
+
+ if(MaximumSize != NULL && PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ /* make a copy on the stack */
+ SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+ MaximumSize = &SafeMaximumSize;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if(!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
/*
* Check the protection
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes)
{
- NTSTATUS Status;
+ HANDLE hSection;
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS Status = STATUS_SUCCESS;
- *SectionHandle = 0;
+ PreviousMode = ExGetPreviousMode();
+
+ if(PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ ProbeForWriteHandle(SectionHandle);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if(!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
Status = ObOpenObjectByName(ObjectAttributes,
MmSectionObjectType,
NULL,
- UserMode,
+ PreviousMode,
DesiredAccess,
NULL,
- SectionHandle);
+ &hSection);
+
+ if(NT_SUCCESS(Status))
+ {
+ _SEH_TRY
+ {
+ *SectionHandle = hSection;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
return(Status);
}
{
PMEMORY_AREA MArea;
NTSTATUS Status;
- KIRQL oldIrql;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
BoundaryAddressMultiple.QuadPart = 0;
return(Status);
}
- KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
- InsertTailList(&Section->ViewListHead,
- &MArea->Data.SectionData.ViewListEntry);
- KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
ObReferenceObjectByPointer((PVOID)Section,
SECTION_MAP_READ,
* @implemented
*/
NTSTATUS STDCALL
-NtMapViewOfSection(HANDLE SectionHandle,
- HANDLE ProcessHandle,
- PVOID* BaseAddress,
- ULONG ZeroBits,
- ULONG CommitSize,
- PLARGE_INTEGER SectionOffset,
- PULONG ViewSize,
- SECTION_INHERIT InheritDisposition,
- ULONG AllocationType,
- ULONG Protect)
+NtMapViewOfSection(IN HANDLE SectionHandle,
+ IN HANDLE ProcessHandle,
+ IN OUT PVOID* BaseAddress OPTIONAL,
+ IN ULONG ZeroBits OPTIONAL,
+ IN ULONG CommitSize,
+ IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+ IN OUT PULONG ViewSize,
+ IN SECTION_INHERIT InheritDisposition,
+ IN ULONG AllocationType OPTIONAL,
+ IN ULONG Protect)
{
+ PVOID SafeBaseAddress;
+ LARGE_INTEGER SafeSectionOffset;
+ ULONG SafeViewSize;
PSECTION_OBJECT Section;
PEPROCESS Process;
- NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
PMADDRESS_SPACE AddressSpace;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PreviousMode = ExGetPreviousMode();
+
+ if(PreviousMode != KernelMode)
+ {
+ SafeBaseAddress = NULL;
+ SafeSectionOffset.QuadPart = 0;
+ SafeViewSize = 0;
+
+ _SEH_TRY
+ {
+ if(BaseAddress != NULL)
+ {
+ ProbeForWritePointer(BaseAddress);
+ SafeBaseAddress = *BaseAddress;
+ }
+ if(SectionOffset != NULL)
+ {
+ ProbeForWriteLargeInteger(SectionOffset);
+ SafeSectionOffset = *SectionOffset;
+ }
+ ProbeForWriteUlong(ViewSize);
+ SafeViewSize = *ViewSize;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if(!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+ else
+ {
+ SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
+ SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
+ SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
+ }
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
- UserMode,
+ PreviousMode,
(PVOID*)(PVOID)&Process,
NULL);
if (!NT_SUCCESS(Status))
Status = ObReferenceObjectByHandle(SectionHandle,
SECTION_MAP_READ,
MmSectionObjectType,
- UserMode,
+ PreviousMode,
(PVOID*)(PVOID)&Section,
NULL);
if (!(NT_SUCCESS(Status)))
Status = MmMapViewOfSection(Section,
Process,
- BaseAddress,
+ (BaseAddress != NULL ? &SafeBaseAddress : NULL),
ZeroBits,
CommitSize,
- SectionOffset,
- ViewSize,
+ (SectionOffset != NULL ? &SafeSectionOffset : NULL),
+ (ViewSize != NULL ? &SafeViewSize : NULL),
InheritDisposition,
AllocationType,
Protect);
ObDereferenceObject(Section);
ObDereferenceObject(Process);
+ if(NT_SUCCESS(Status))
+ {
+ /* copy parameters back to the caller */
+ _SEH_TRY
+ {
+ if(BaseAddress != NULL)
+ {
+ *BaseAddress = SafeBaseAddress;
+ }
+ if(SectionOffset != NULL)
+ {
+ *SectionOffset = SafeSectionOffset;
+ }
+ if(ViewSize != NULL)
+ {
+ *ViewSize = SafeViewSize;
+ }
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+
return(Status);
}
MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
{
- PMEMORY_AREA MArea;
ULONG Entry;
PFILE_OBJECT FileObject;
PBCB Bcb;
NTSTATUS Status;
PSECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
+ PMADDRESS_SPACE AddressSpace;
- MArea = (PMEMORY_AREA)Context;
+ AddressSpace = (PMADDRESS_SPACE)Context;
Address = (PVOID)PAGE_ROUND_DOWN(Address);
- Offset = ((ULONG_PTR)Address - (ULONG_PTR)MArea->BaseAddress) +
+ Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
MemoryArea->Data.SectionData.ViewOffset;
- Section = MArea->Data.SectionData.Section;
- Segment = MArea->Data.SectionData.Segment;
+ Section = MemoryArea->Data.SectionData.Section;
+ Segment = MemoryArea->Data.SectionData.Segment;
- PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
+ PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
while (PageOp)
{
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(&MArea->Process->AddressSpace);
+ MmUnlockAddressSpace(AddressSpace);
Status = MmspWaitForPageOpCompletionEvent(PageOp);
if (Status != STATUS_SUCCESS)
KEBUGCHECK(0);
}
- MmLockAddressSpace(&MArea->Process->AddressSpace);
+ MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
MmspCompleteAndReleasePageOp(PageOp);
- PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
+ PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
}
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
{
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
- CcRosMarkDirtyCacheSegment(Bcb, Offset);
+ CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
ASSERT(SwapEntry == 0);
}
}
MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
- MmDeleteRmap(Page, MArea->Process, Address);
+ MmDeleteRmap(Page, AddressSpace->Process, Address);
MmReleasePageMemoryConsumer(MC_USER, Page);
}
else
{
- MmDeleteRmap(Page, MArea->Process, Address);
+ MmDeleteRmap(Page, AddressSpace->Process, Address);
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
}
}
}
-NTSTATUS
+STATIC NTSTATUS
MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
PVOID BaseAddress)
{
PMEMORY_AREA MemoryArea;
PSECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
- KIRQL oldIrql;
PLIST_ENTRY CurrentEntry;
PMM_REGION CurrentRegion;
PLIST_ENTRY RegionListHead;
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
- BaseAddress);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+ BaseAddress);
if (MemoryArea == NULL)
{
return(STATUS_UNSUCCESSFUL);
Segment = MemoryArea->Data.SectionData.Segment;
MmLockSectionSegment(Segment);
- KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
- RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
- KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
while (!IsListEmpty(RegionListHead))
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
{
Status = MmFreeMemoryArea(AddressSpace,
- BaseAddress,
- 0,
+ MemoryArea,
NULL,
NULL);
}
else
{
Status = MmFreeMemoryArea(AddressSpace,
- BaseAddress,
- 0,
+ MemoryArea,
MmFreeSectionPage,
- MemoryArea);
+ AddressSpace);
}
MmUnlockSectionSegment(Segment);
ObDereferenceObject(Section);
PMEMORY_AREA MemoryArea;
PMADDRESS_SPACE AddressSpace;
PSECTION_OBJECT Section;
+ PMM_PAGEOP PageOp;
+ ULONG_PTR Offset;
DPRINT("Opening memory area Process %x BaseAddress %x\n",
Process, BaseAddress);
ASSERT(Process);
AddressSpace = &Process->AddressSpace;
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
- BaseAddress);
+
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+ BaseAddress);
if (MemoryArea == NULL ||
MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
MemoryArea->DeleteInProgress)
{
+ MmUnlockAddressSpace(AddressSpace);
return STATUS_NOT_MAPPED_VIEW;
}
+ MemoryArea->DeleteInProgress = TRUE;
+
+ while (MemoryArea->PageOpCount)
+ {
+ Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
+
+ while (Offset)
+ {
+ Offset -= PAGE_SIZE;
+ PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
+ MemoryArea->Data.SectionData.Segment,
+ Offset + MemoryArea->Data.SectionData.ViewOffset);
+ if (PageOp)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ Status = MmspWaitForPageOpCompletionEvent(PageOp);
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("Failed to wait for page op, status = %x\n", Status);
+ KEBUGCHECK(0);
+ }
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+ BaseAddress);
+ if (MemoryArea == NULL ||
+ MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_NOT_MAPPED_VIEW;
+ }
+ break;
+ }
+ }
+ }
+
Section = MemoryArea->Data.SectionData.Section;
if (Section->AllocationAttributes & SEC_IMAGE)
* and calculate the image base address */
for (i = 0; i < NrSegments; i++)
{
- if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
+ if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
{
if (Segment == &SectionSegments[i])
{
for (i = 0; i < NrSegments; i++)
{
- if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
+ if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
{
PVOID SBaseAddress = (PVOID)
((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
{
Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
}
+ MmUnlockAddressSpace(AddressSpace);
return(STATUS_SUCCESS);
}
PVOID BaseAddress)
{
PEPROCESS Process;
+ KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
ProcessHandle, BaseAddress);
+ PreviousMode = ExGetPreviousMode();
+
DPRINT("Referencing process\n");
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
- UserMode,
+ PreviousMode,
(PVOID*)(PVOID)&Process,
NULL);
if (!NT_SUCCESS(Status))
return(Status);
}
- MmLockAddressSpace(&Process->AddressSpace);
Status = MmUnmapViewOfSection(Process, BaseAddress);
- MmUnlockAddressSpace(&Process->AddressSpace);
ObDereferenceObject(Process);
/**
* Queries the information of a section object.
- *
+ *
* @param SectionHandle
* Handle to the section object. It must be opened with SECTION_QUERY
* access.
*
* @return Status.
*
- * @todo Guard by SEH.
* @implemented
*/
NTSTATUS STDCALL
NtQuerySection(IN HANDLE SectionHandle,
- IN CINT SectionInformationClass,
+ IN SECTION_INFORMATION_CLASS SectionInformationClass,
OUT PVOID SectionInformation,
- IN ULONG Length,
- OUT PULONG ResultLength)
+ IN ULONG SectionInformationLength,
+ OUT PULONG ResultLength OPTIONAL)
{
PSECTION_OBJECT Section;
- NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PreviousMode = ExGetPreviousMode();
+
+ Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
+ ExSectionInfoClass,
+ sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
+ SectionInformation,
+ SectionInformationLength,
+ ResultLength,
+ PreviousMode);
+
+ if(!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
+ return Status;
+ }
Status = ObReferenceObjectByHandle(SectionHandle,
SECTION_QUERY,
MmSectionObjectType,
- UserMode,
+ PreviousMode,
(PVOID*)(PVOID)&Section,
NULL);
- if (!(NT_SUCCESS(Status)))
- {
- return(Status);
- }
-
- switch (SectionInformationClass)
+ if (NT_SUCCESS(Status))
{
- case SectionBasicInformation:
+ switch (SectionInformationClass)
+ {
+ case SectionBasicInformation:
{
- PSECTION_BASIC_INFORMATION Sbi;
+ PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
- if (Length != sizeof(SECTION_BASIC_INFORMATION))
+ _SEH_TRY
{
- ObDereferenceObject(Section);
- return(STATUS_INFO_LENGTH_MISMATCH);
- }
-
- Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
+ Sbi->Attributes = Section->AllocationAttributes;
+ if (Section->AllocationAttributes & SEC_IMAGE)
+ {
+ Sbi->BaseAddress = 0;
+ Sbi->Size.QuadPart = 0;
+ }
+ else
+ {
+ Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
+ Sbi->Size.QuadPart = Section->Segment->Length;
+ }
- Sbi->Attributes = Section->AllocationAttributes;
- if (Section->AllocationAttributes & SEC_IMAGE)
- {
- Sbi->BaseAddress = 0;
- Sbi->Size.QuadPart = 0;
+ if (ResultLength != NULL)
+ {
+ *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
+ }
+ Status = STATUS_SUCCESS;
}
- else
+ _SEH_HANDLE
{
- Sbi->BaseAddress = Section->Segment->VirtualAddress;
- Sbi->Size.QuadPart = Section->Segment->Length;
+ Status = _SEH_GetExceptionCode();
}
+ _SEH_END;
- *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
- Status = STATUS_SUCCESS;
break;
}
- case SectionImageInformation:
+ case SectionImageInformation:
{
- PSECTION_IMAGE_INFORMATION Sii;
+ PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
- if (Length != sizeof(SECTION_IMAGE_INFORMATION))
+ _SEH_TRY
{
- ObDereferenceObject(Section);
- return(STATUS_INFO_LENGTH_MISMATCH);
- }
+ memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
+ if (Section->AllocationAttributes & SEC_IMAGE)
+ {
+ PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
+ ImageSectionObject = Section->ImageSection;
+
+ Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
+ Sii->MaximumStackSize = ImageSectionObject->StackReserve;
+ Sii->CommittedStackSize = ImageSectionObject->StackCommit;
+ Sii->SubsystemType = ImageSectionObject->Subsystem;
+ Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
+ Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
+ Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
+ Sii->Machine = ImageSectionObject->Machine;
+ Sii->ImageContainsCode = ImageSectionObject->Executable;
+ }
- Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
- memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
- if (Section->AllocationAttributes & SEC_IMAGE)
+ if (ResultLength != NULL)
+ {
+ *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
+ }
+ Status = STATUS_SUCCESS;
+ }
+ _SEH_HANDLE
{
- PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
- ImageSectionObject = Section->ImageSection;
-
- Sii->EntryPoint = ImageSectionObject->EntryPoint;
- Sii->StackReserve = ImageSectionObject->StackReserve;
- Sii->StackCommit = ImageSectionObject->StackCommit;
- Sii->Subsystem = ImageSectionObject->Subsystem;
- Sii->MinorSubsystemVersion = (USHORT)ImageSectionObject->MinorSubsystemVersion;
- Sii->MajorSubsystemVersion = (USHORT)ImageSectionObject->MajorSubsystemVersion;
- Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
- Sii->ImageNumber = ImageSectionObject->Machine;
- Sii->Executable = ImageSectionObject->Executable;
+ Status = _SEH_GetExceptionCode();
}
- *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
- Status = STATUS_SUCCESS;
+ _SEH_END;
+
break;
}
+ }
- default:
- *ResultLength = 0;
- Status = STATUS_INVALID_INFO_CLASS;
+ ObDereferenceObject(Section);
}
- ObDereferenceObject(Section);
+
return(Status);
}
/**
* Extends size of file backed section.
- *
+ *
* @param SectionHandle
* Handle to the section object. It must be opened with
* SECTION_EXTEND_SIZE access.
*
* @return Status.
*
- * @todo Guard by SEH.
* @todo Move the actual code to internal function MmExtendSection.
* @unimplemented
*/
NtExtendSection(IN HANDLE SectionHandle,
IN PLARGE_INTEGER NewMaximumSize)
{
+ LARGE_INTEGER SafeNewMaximumSize;
PSECTION_OBJECT Section;
- NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PreviousMode = ExGetPreviousMode();
+
+ if(PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ /* make a copy on the stack */
+ SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
+ NewMaximumSize = &SafeNewMaximumSize;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if(!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
Status = ObReferenceObjectByHandle(SectionHandle,
SECTION_EXTEND_SIZE,
MmSectionObjectType,
- UserMode,
+ PreviousMode,
(PVOID*)&Section,
NULL);
if (!NT_SUCCESS(Status))
ObfDereferenceObject(Section);
return STATUS_INVALID_PARAMETER;
}
-
+
/*
* - Acquire file extneding resource.
* - Check if we're not resizing the section below it's actual size!
KEBUGCHECK(0);
}
Status = MmCreateVirtualMapping (NULL,
- ((char*)Result + (i * PAGE_SIZE)),
+ (PVOID)((ULONG_PTR)Result + (i * PAGE_SIZE)),
PAGE_READWRITE,
&Page,
1);
{
ULONG i;
ULONG NrSegments;
- PVOID ImageBase;
+ ULONG_PTR ImageBase;
ULONG ImageSize;
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
PMM_SECTION_SEGMENT SectionSegments;
NrSegments = ImageSectionObject->NrSegments;
- ImageBase = *BaseAddress;
- if (ImageBase == NULL)
+ ImageBase = (ULONG_PTR)*BaseAddress;
+ if (ImageBase == 0)
{
ImageBase = ImageSectionObject->ImageBase;
}
ImageSize = 0;
for (i = 0; i < NrSegments; i++)
{
- if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
+ if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
{
- ULONG MaxExtent;
- MaxExtent = (ULONG)((char*)SectionSegments[i].VirtualAddress +
- SectionSegments[i].Length);
+ ULONG_PTR MaxExtent;
+ MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
+ SectionSegments[i].Length;
ImageSize = max(ImageSize, MaxExtent);
}
}
/* Check there is enough space to map the section at that point. */
- if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
- PAGE_ROUND_UP(ImageSize)) != NULL)
+ if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
+ PAGE_ROUND_UP(ImageSize)) != NULL)
{
/* Fail if the user requested a fixed base address. */
if ((*BaseAddress) != NULL)
return(STATUS_UNSUCCESSFUL);
}
/* Otherwise find a gap to map the image. */
- ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
- if (ImageBase == NULL)
+ ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
+ if (ImageBase == 0)
{
MmUnlockAddressSpace(AddressSpace);
return(STATUS_UNSUCCESSFUL);
for (i = 0; i < NrSegments; i++)
{
- if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
+ if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
{
PVOID SBaseAddress = (PVOID)
((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
}
}
- *BaseAddress = ImageBase;
+ *BaseAddress = (PVOID)ImageBase;
}
else
{
*ViewSize,
Protect,
ViewOffset,
- (AllocationType & MEM_TOP_DOWN));
+ (AllocationType & MEM_TOP_DOWN) == MEM_TOP_DOWN);
MmUnlockSectionSegment(Section->Segment);
if (!NT_SUCCESS(Status))
{
* @unimplemented
*/
BOOLEAN STDCALL
-MmForceSectionClosed (DWORD Unknown0,
- DWORD Unknown1)
+MmForceSectionClosed (
+ IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+ IN BOOLEAN DelayClose)
{
UNIMPLEMENTED;
return (FALSE);