[NTOS:MM] Keep image maps & file maps coherent at the time of creating the image map

This commit is contained in:
Jérôme Gardou 2020-12-21 13:54:29 +01:00
parent 543112008a
commit addf824d87

View file

@ -2448,6 +2448,19 @@ ExeFmtpAllocateSegments(IN ULONG NrSegments)
return Segments;
}
static NTSTATUS
MmMapViewOfSegment(PMMSUPPORT AddressSpace,
BOOLEAN AsImage,
PMM_SECTION_SEGMENT Segment,
PVOID* BaseAddress,
SIZE_T ViewSize,
ULONG Protect,
LONGLONG ViewOffset,
ULONG AllocationType);
static NTSTATUS
MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
PVOID BaseAddress);
static
NTSTATUS
NTAPI
@ -2490,36 +2503,57 @@ ExeFmtpReadFile(IN PVOID File,
BufferSize = Length + OffsetAdjustment;
BufferSize = PAGE_ROUND_UP(BufferSize);
/* Flush data since we're about to perform a non-cached read */
CcFlushCache(FileObject->SectionObjectPointer,
&FileOffset,
BufferSize,
&Iosb);
/*
* 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,
'rXmM');
Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, 'rXmM');
if (!Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
UsedSize = 0;
Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
UsedSize = (ULONG)Iosb.Information;
if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
if (FileObject->SectionObjectPointer->DataSectionObject)
{
Status = STATUS_IN_PAGE_ERROR;
ASSERT(!NT_SUCCESS(Status));
PVOID SegmentMap = NULL;
/* Get the data from the file mapping instead */
MmLockAddressSpace(MmGetKernelAddressSpace());
Status = MmMapViewOfSegment(MmGetKernelAddressSpace(),
FALSE,
FileObject->SectionObjectPointer->DataSectionObject,
&SegmentMap,
BufferSize,
PAGE_READONLY,
FileOffset.QuadPart,
0);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
if (!NT_SUCCESS(Status))
return Status;
RtlCopyMemory(Buffer, SegmentMap, BufferSize);
UsedSize = BufferSize;
MmLockAddressSpace(MmGetKernelAddressSpace());
MmUnmapViewOfSegment(MmGetKernelAddressSpace(), SegmentMap);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
}
else
{
Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
UsedSize = (ULONG)Iosb.Information;
if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
{
Status = STATUS_IN_PAGE_ERROR;
ASSERT(!NT_SUCCESS(Status));
}
}
if(NT_SUCCESS(Status))
@ -3102,7 +3136,6 @@ MmCreateImageSection(PSECTION *SectionObject,
if (ImageSectionObject == NULL)
{
NTSTATUS StatusExeFmt;
PMM_SECTION_SEGMENT DataSectionObject;
ImageSectionObject = ExAllocatePoolZero(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
if (ImageSectionObject == NULL)
@ -3116,44 +3149,12 @@ MmCreateImageSection(PSECTION *SectionObject,
ImageSectionObject->RefCount = 1;
FileObject->SectionObjectPointer->ImageSectionObject = ImageSectionObject;
/* Get a ref on the data section object */
DataSectionObject = FileObject->SectionObjectPointer->DataSectionObject;
while (DataSectionObject && (DataSectionObject->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE)))
{
LARGE_INTEGER ShortTime;
MiReleasePfnLock(OldIrql);
ShortTime.QuadPart = - 10 * 100 * 1000;
KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
OldIrql = MiAcquirePfnLock();
DataSectionObject = FileObject->SectionObjectPointer->DataSectionObject;
ASSERT(DataSectionObject->SegFlags & MM_DATAFILE_SEGMENT);
}
/* Get a ref on it. */
if (DataSectionObject)
InterlockedIncrementUL(&DataSectionObject->RefCount);
MiReleasePfnLock(OldIrql);
if (DataSectionObject)
/* Purge the cache */
if (CcIsFileCached(FileObject))
{
if ((DataSectionObject->SectionCount - (FileObject->SectionObjectPointer->SharedCacheMap != NULL)) > 0)
{
/* Someone's got a section opened. Deny creation */
DPRINT1("Denying image creation for %wZ: Sections opened: %lu.\n",
&FileObject->FileName, DataSectionObject->SectionCount);
InterlockedExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject, NULL);
ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
MmDereferenceSegment(DataSectionObject);
ObDereferenceObject(Section);
return STATUS_ACCESS_DENIED;
}
/* Purge the cache. */
CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, FALSE);
CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
}
StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
@ -3234,14 +3235,15 @@ MmCreateImageSection(PSECTION *SectionObject,
static NTSTATUS
MmMapViewOfSegment(PMMSUPPORT AddressSpace,
PSECTION Section,
PMM_SECTION_SEGMENT Segment,
PVOID* BaseAddress,
SIZE_T ViewSize,
ULONG Protect,
LONGLONG ViewOffset,
ULONG AllocationType)
MmMapViewOfSegment(
PMMSUPPORT AddressSpace,
BOOLEAN AsImage,
PMM_SECTION_SEGMENT Segment,
PVOID* BaseAddress,
SIZE_T ViewSize,
ULONG Protect,
LONGLONG ViewOffset,
ULONG AllocationType)
{
PMEMORY_AREA MArea;
NTSTATUS Status;
@ -3297,7 +3299,7 @@ MmMapViewOfSegment(PMMSUPPORT AddressSpace,
MArea->SectionData.Segment = Segment;
MArea->SectionData.ViewOffset.QuadPart = ViewOffset;
if (Section->u.Flags.Image)
if (AsImage)
{
MArea->VadNode.u.VadFlags.VadType = VadImageMap;
}
@ -3932,7 +3934,7 @@ MmMapViewOfSection(IN PVOID SectionObject,
((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
MmLockSectionSegment(&SectionSegments[i]);
Status = MmMapViewOfSegment(AddressSpace,
Section,
TRUE,
&SectionSegments[i],
&SBaseAddress,
SectionSegments[i].Length.QuadPart,
@ -4017,7 +4019,7 @@ MmMapViewOfSection(IN PVOID SectionObject,
MmLockSectionSegment(Segment);
Status = MmMapViewOfSegment(AddressSpace,
Section,
FALSE,
Segment,
BaseAddress,
*ViewSize,
@ -4191,7 +4193,7 @@ MmMapViewInSystemSpaceEx (
MmLockSectionSegment(Segment);
Status = MmMapViewOfSegment(AddressSpace,
Section,
Section->u.Flags.Image,
Segment,
MappedBase,
*ViewSize,