Author: jgardou
Date: Tue Sep 23 18:06:47 2014
New Revision: 64242
URL:
http://svn.reactos.org/svn/reactos?rev=64242&view=rev
Log:
[NTOS/MM]
- Simplify and fix MmCopyVirtualMemory, where the processes where not correctly detached
on failure.
Fixes a few "Process xyz.exe" is a zombie.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Tue Sep 23 18:06:47 2014
@@ -774,10 +774,10 @@
PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
PMDL Mdl = (PMDL)MdlBuffer;
SIZE_T TotalSize, CurrentSize, RemainingSize;
- volatile BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
- volatile BOOLEAN PagesLocked;
+ volatile BOOLEAN FailedInProbe = FALSE;
+ volatile BOOLEAN PagesLocked = FALSE;
PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
- volatile PVOID MdlAddress;
+ volatile PVOID MdlAddress = NULL;
KAPC_STATE ApcState;
BOOLEAN HaveBadAddress;
ULONG_PTR BadAddress;
@@ -808,11 +808,10 @@
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
//
- // Reset state for this pass
- //
- MdlAddress = NULL;
- PagesLocked = FALSE;
- FailedInMoving = FALSE;
+ // Check state for this pass
+ //
+ ASSERT(MdlAddress == NULL);
+ ASSERT(PagesLocked == FALSE);
ASSERT(FailedInProbe == FALSE);
//
@@ -847,35 +846,47 @@
MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
PagesLocked = TRUE;
-
- //
- // Now map the pages
- //
- MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
- KernelMode,
- MmCached,
- NULL,
- FALSE,
- HighPagePriority);
- if (!MdlAddress)
- {
- //
- // Use our SEH handler to pick this up
- //
- FailedInMapping = TRUE;
- ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- //
- // Now let go of the source and grab to the target process
- //
- KeUnstackDetachProcess(&ApcState);
- KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
-
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ /* Detach from source process */
+ KeUnstackDetachProcess(&ApcState);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ goto Exit;
+ }
+
+ //
+ // Now map the pages
+ //
+ MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
+ KernelMode,
+ MmCached,
+ NULL,
+ FALSE,
+ HighPagePriority);
+ if (!MdlAddress)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Grab to the target process
+ //
+ KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
+
+ _SEH2_TRY
+ {
//
// Check if this is our first time through
//
- if ((CurrentAddress == SourceAddress) && (PreviousMode !=
KernelMode))
+ if ((CurrentTargetAddress == TargetAddress) && (PreviousMode !=
KernelMode))
{
//
// Catch a failure here
@@ -896,58 +907,27 @@
//
// Now do the actual move
//
- FailedInMoving = TRUE;
RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
}
_SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
&HaveBadAddress,
&BadAddress))
{
- //
- // Detach from whoever we may be attached to
- //
- KeUnstackDetachProcess(&ApcState);
-
- //
- // Check if we had mapped the pages
- //
- if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl);
-
- //
- // Check if we had locked the pages
- //
- if (PagesLocked) MmUnlockPages(Mdl);
-
- //
- // Check if we hit working set quota
- //
- if (_SEH2_GetExceptionCode() == STATUS_WORKING_SET_QUOTA)
- {
- //
- // Return the error
- //
- _SEH2_YIELD(return STATUS_WORKING_SET_QUOTA);
- }
-
- //
- // Check if we failed during the probe or mapping
- //
- if ((FailedInProbe) || (FailedInMapping))
+ *ReturnSize = BufferSize - RemainingSize;
+ //
+ // Check if we failed during the probe
+ //
+ if (FailedInProbe)
{
//
// Exit
//
Status = _SEH2_GetExceptionCode();
- _SEH2_YIELD(return Status);
- }
-
- //
- // Otherwise, we failed probably during the move
- //
- *ReturnSize = BufferSize - RemainingSize;
- if (FailedInMoving)
- {
- //
+ }
+ else
+ {
+ //
+ // Othewise we failed during the move.
// Check if we know exactly where we stopped copying
//
if (HaveBadAddress)
@@ -957,30 +937,32 @@
//
*ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
}
- }
-
- //
- // Return partial copy
- //
- Status = STATUS_PARTIAL_COPY;
+ //
+ // Return partial copy
+ //
+ Status = STATUS_PARTIAL_COPY;
+ }
}
_SEH2_END;
+ /* Detach from target process */
+ KeUnstackDetachProcess(&ApcState);
+
//
// Check for SEH status
//
- if (Status != STATUS_SUCCESS) return Status;
-
- //
- // Detach from target
- //
- KeUnstackDetachProcess(&ApcState);
+ if (Status != STATUS_SUCCESS)
+ {
+ goto Exit;
+ }
//
// Unmap and unlock
//
MmUnmapLockedPages(MdlAddress, Mdl);
+ MdlAddress = NULL;
MmUnlockPages(Mdl);
+ PagesLocked = FALSE;
//
// Update location and size
@@ -990,11 +972,18 @@
CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
}
+Exit:
+ if (MdlAddress != NULL)
+ MmUnmapLockedPages(MdlAddress, Mdl);
+ if (PagesLocked)
+ MmUnlockPages(Mdl);
+
//
// All bytes read
//
- *ReturnSize = BufferSize;
- return STATUS_SUCCESS;
+ if (Status == STATUS_SUCCESS)
+ *ReturnSize = BufferSize;
+ return Status;
}
NTSTATUS
@@ -1009,7 +998,7 @@
{
UCHAR StackBuffer[MI_POOL_COPY_BYTES];
SIZE_T TotalSize, CurrentSize, RemainingSize;
- volatile BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE;
+ volatile BOOLEAN FailedInProbe = FALSE, HavePoolAddress = FALSE;
PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
PVOID PoolAddress;
KAPC_STATE ApcState;
@@ -1018,6 +1007,9 @@
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
+ DPRINT("Copying %Iu bytes from process %p (address %p) to process %p (Address
%p)\n",
+ BufferSize, SourceProcess, SourceAddress, TargetProcess, TargetAddress);
+
//
// Calculate the maximum amount of data to move
//
@@ -1061,11 +1053,9 @@
//
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
- //
- // Reset state for this pass
- //
- FailedInMoving = FALSE;
+ /* Check that state is sane */
ASSERT(FailedInProbe == FALSE);
+ ASSERT(Status == STATUS_SUCCESS);
//
// Protect user-mode copy
@@ -1097,53 +1087,12 @@
// Do the copy
//
RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
-
- //
- // Now let go of the source and grab to the target process
- //
- KeUnstackDetachProcess(&ApcState);
- KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
-
- //
- // Check if this is our first time through
- //
- if ((CurrentAddress == SourceAddress) && (PreviousMode !=
KernelMode))
- {
- //
- // Catch a failure here
- //
- FailedInProbe = TRUE;
-
- //
- // Do the probe
- //
- ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
-
- //
- // Passed
- //
- FailedInProbe = FALSE;
- }
-
- //
- // Now do the actual move
- //
- FailedInMoving = TRUE;
- RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
}
_SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
&HaveBadAddress,
&BadAddress))
{
- //
- // Detach from whoever we may be attached to
- //
- KeUnstackDetachProcess(&ApcState);
-
- //
- // Check if we had allocated pool
- //
- if (HavePoolAddress) ExFreePoolWithTag(PoolAddress, 'VmRw');
+ *ReturnSize = BufferSize - RemainingSize;
//
// Check if we failed during the probe
@@ -1154,16 +1103,11 @@
// Exit
//
Status = _SEH2_GetExceptionCode();
- _SEH2_YIELD(return Status);
- }
-
- //
- // Otherwise, we failed, probably during the move
- //
- *ReturnSize = BufferSize - RemainingSize;
- if (FailedInMoving)
- {
- //
+ }
+ else
+ {
+ //
+ // We failed during the move.
// Check if we know exactly where we stopped copying
//
if (HaveBadAddress)
@@ -1173,24 +1117,101 @@
//
*ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
}
- }
-
- //
- // Return partial copy
- //
- Status = STATUS_PARTIAL_COPY;
+ //
+ // Return partial copy
+ //
+ Status = STATUS_PARTIAL_COPY;
+ }
+ }
+ _SEH2_END
+
+ /* Let go of the source */
+ KeUnstackDetachProcess(&ApcState);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ goto Exit;
+ }
+
+ /* Grab the target process */
+ KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
+
+ _SEH2_TRY
+ {
+ //
+ // Check if this is our first time through
+ //
+ if ((CurrentTargetAddress == TargetAddress) && (PreviousMode !=
KernelMode))
+ {
+ //
+ // Catch a failure here
+ //
+ FailedInProbe = TRUE;
+
+ //
+ // Do the probe
+ //
+ ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
+
+ //
+ // Passed
+ //
+ FailedInProbe = FALSE;
+ }
+
+ //
+ // Now do the actual move
+ //
+ RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
+ }
+ _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
+ &HaveBadAddress,
+ &BadAddress))
+ {
+ *ReturnSize = BufferSize - RemainingSize;
+ //
+ // Check if we failed during the probe
+ //
+ if (FailedInProbe)
+ {
+ //
+ // Exit
+ //
+ Status = _SEH2_GetExceptionCode();
+ }
+ else
+ {
+ //
+ // Otherwise we failed during the move.
+ // Check if we know exactly where we stopped copying
+ //
+ if (HaveBadAddress)
+ {
+ //
+ // Return the exact number of bytes copied
+ //
+ *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
+ }
+ //
+ // Return partial copy
+ //
+ Status = STATUS_PARTIAL_COPY;
+ }
}
_SEH2_END;
//
+ // Detach from target
+ //
+ KeUnstackDetachProcess(&ApcState);
+
+ //
// Check for SEH status
//
- if (Status != STATUS_SUCCESS) return Status;
-
- //
- // Detach from target
- //
- KeUnstackDetachProcess(&ApcState);
+ if (Status != STATUS_SUCCESS)
+ {
+ goto Exit;
+ }
//
// Update location and size
@@ -1201,16 +1222,19 @@
CurrentSize);
}
+Exit:
//
// Check if we had allocated pool
//
- if (HavePoolAddress) ExFreePoolWithTag(PoolAddress, 'VmRw');
+ if (HavePoolAddress)
+ ExFreePoolWithTag(PoolAddress, 'VmRw');
//
// All bytes read
//
- *ReturnSize = BufferSize;
- return STATUS_SUCCESS;
+ if (Status == STATUS_SUCCESS)
+ *ReturnSize = BufferSize;
+ return Status;
}
NTSTATUS