From: Alex Ionescu Date: Mon, 3 Oct 2016 03:30:11 +0000 (+0000) Subject: [NTOS]: Handle two complex failure paths, one of which is apparently easily reproduci... X-Git-Tag: ReactOS-0.4.3~159 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=eb94308bbb8f3eeb553e26323459da938770093c [NTOS]: Handle two complex failure paths, one of which is apparently easily reproducible by ntdll:om test (I'm guessing some invalid object attribute). Thanks to Amine and lentin. Haven't tested this, but hopefully fixes things (and doesn't leak). svn path=/trunk/; revision=72896 --- diff --git a/reactos/ntoskrnl/mm/ARM3/section.c b/reactos/ntoskrnl/mm/ARM3/section.c index 7a2f3b5e266..0b008c50574 100644 --- a/reactos/ntoskrnl/mm/ARM3/section.c +++ b/reactos/ntoskrnl/mm/ARM3/section.c @@ -2419,6 +2419,7 @@ MmCreateArm3Section(OUT PVOID *SectionObject, BOOLEAN FileLock = FALSE, KernelCall = FALSE; KIRQL OldIrql; PFILE_OBJECT File; + BOOLEAN UserRefIncremented = FALSE; PVOID PreviousSectionPointer; /* Make the same sanity checks that the Nt interface should've validated */ @@ -2516,6 +2517,7 @@ MmCreateArm3Section(OUT PVOID *SectionObject, /* Write down that this CA is being created, and set it */ ControlArea->u.Flags.BeingCreated = TRUE; + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); PreviousSectionPointer = File->SectionObjectPointer; File->SectionObjectPointer->DataSectionObject = ControlArea; @@ -2535,8 +2537,47 @@ MmCreateArm3Section(OUT PVOID *SectionObject, SectionPageProtection, AllocationAttributes, KernelCall); + if (!NT_SUCCESS(Status)) + { + /* Lock the PFN database while we play with the section pointers */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Reset the waiting-for-deletion event */ + ASSERT(ControlArea->WaitingForDeletion == NULL); + ControlArea->WaitingForDeletion = NULL; + + /* Set the file pointer NULL flag */ + ASSERT(ControlArea->u.Flags.FilePointerNull == 0); + ControlArea->u.Flags.FilePointerNull = TRUE; + + /* Delete the data section object */ + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); + File->SectionObjectPointer->DataSectionObject = NULL; + + /* No longer being created */ + ControlArea->u.Flags.BeingCreated = FALSE; + + /* We can release the PFN lock now */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + /* Check if we locked and set the IRP */ + if (FileLock) + { + /* Undo */ + IoSetTopLevelIrp(NULL); + //FsRtlReleaseFile(File); + } + + /* Free the control area and de-ref the file object */ + ExFreePool(ControlArea); + ObDereferenceObject(File); + + /* All done */ + return Status; + } + + /* On success, we expect this */ ASSERT(PreviousSectionPointer == File->SectionObjectPointer); - ASSERT(NT_SUCCESS(Status)); /* Check if a maximum size was specified */ if (!InputMaximumSize->QuadPart) @@ -2568,7 +2609,9 @@ MmCreateArm3Section(OUT PVOID *SectionObject, /* Set the size here, and read the control area */ Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; ControlArea = NewSegment->ControlArea; - ASSERT(ControlArea->u.Flags.BeingCreated == 1); + + /* MiCreatePagingFileMap increments user references */ + UserRefIncremented = TRUE; } /* Did we already have a segment? */ @@ -2613,16 +2656,16 @@ MmCreateArm3Section(OUT PVOID *SectionObject, /* Check if this is a user-mode read-write non-image file mapping */ if (!(FileObject) && (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && - (ControlArea->u.Flags.Image == 0) && - (ControlArea->FilePointer != NULL)) + !(ControlArea->u.Flags.Image) && + (ControlArea->FilePointer)) { /* Add a reference and set the flag */ - Section.u.Flags.UserWritable = 1; - InterlockedIncrement((PLONG)&ControlArea->WritableUserReferences); + Section.u.Flags.UserWritable = TRUE; + InterlockedIncrement((volatile LONG*)&ControlArea->WritableUserReferences); } /* Check for image mappings or page file mappings */ - if ((ControlArea->u.Flags.Image == 1) || !(ControlArea->FilePointer)) + if ((ControlArea->u.Flags.Image) || !(ControlArea->FilePointer)) { /* Charge the segment size, and allocate a subsection */ PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE); @@ -2657,7 +2700,39 @@ MmCreateArm3Section(OUT PVOID *SectionObject, PagedCharge, NonPagedCharge, (PVOID*)&NewSection); - ASSERT(NT_SUCCESS(Status)); + if (!NT_SUCCESS(Status)) + { + /* Check if this is a user-mode read-write non-image file mapping */ + if (!(FileObject) && + (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && + !(ControlArea->u.Flags.Image) && + (ControlArea->FilePointer)) + { + /* Remove a reference and check the flag */ + ASSERT(Section.u.Flags.UserWritable == 1); + InterlockedDecrement((volatile LONG*)&ControlArea->WritableUserReferences); + } + + /* Check if a user reference was added */ + if (UserRefIncremented) + { + /* Acquire the PFN lock while we change counters */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Decrement the accounting counters */ + ControlArea->NumberOfSectionReferences--; + ASSERT((LONG)ControlArea->NumberOfUserReferences > 0); + ControlArea->NumberOfUserReferences--; + + /* Check if we should destroy the CA and release the lock */ + MiCheckControlArea(ControlArea, OldIrql); + } + + /* Return the failure code */ + return Status; + } + + /* NOTE: Past this point, all failures will be handled by Ob upon ref->0 */ /* Now copy the local section object from the stack into this new object */ RtlCopyMemory(NewSection, &Section, sizeof(SECTION));