Isolate KD a bit by replacing Rtl* memory routines with internal versions. Lets one put breakpoints inside kernel memcpy/memset without making KD very, very sad. Fix MmDbgCopyMemory to also not use RtlCopyMemory -- there is no need for it since it only performs 1-to-8 byte copies anyway. Minor fixes in the print/prompt routines.

svn path=/trunk/; revision=69539
This commit is contained in:
Stefan Ginsberg 2015-10-15 12:56:19 +00:00
parent 017269e128
commit 8ea1ea856d
5 changed files with 147 additions and 53 deletions

View file

@ -351,6 +351,24 @@ KdpCopyMemoryChunks(
OUT PULONG ActualSize OPTIONAL OUT PULONG ActualSize OPTIONAL
); );
//
// Internal memory handling routines for KD isolation
//
VOID
NTAPI
KdpMoveMemory(
IN PVOID Destination,
IN PVOID Source,
IN SIZE_T Length
);
VOID
NTAPI
KdpZeroMemory(
IN PVOID Destination,
IN SIZE_T Length
);
// //
// Low Level Support Routines for the KD API // Low Level Support Routines for the KD API
// //

View file

@ -15,6 +15,32 @@
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
KdpMoveMemory(IN PVOID Destination,
IN PVOID Source,
IN SIZE_T Length)
{
PCHAR DestinationBytes, SourceBytes;
/* Copy the buffers 1 byte at a time */
DestinationBytes = Destination;
SourceBytes = Source;
while (Length--) *DestinationBytes++ = *SourceBytes++;
}
VOID
NTAPI
KdpZeroMemory(IN PVOID Destination,
IN SIZE_T Length)
{
PCHAR DestinationBytes;
/* Zero the buffer 1 byte at a time */
DestinationBytes = Destination;
while (Length--) *DestinationBytes++ = 0;
}
NTSTATUS NTSTATUS
NTAPI NTAPI
KdpCopyMemoryChunks(IN ULONG64 Address, KdpCopyMemoryChunks(IN ULONG64 Address,
@ -368,7 +394,7 @@ KdpSetCommonState(IN ULONG NewState,
WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context); WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context);
/* Zero out the entire Control Report */ /* Zero out the entire Control Report */
RtlZeroMemory(&WaitStateChange->AnyControlReport, KdpZeroMemory(&WaitStateChange->AnyControlReport,
sizeof(DBGKD_ANY_CONTROL_REPORT)); sizeof(DBGKD_ANY_CONTROL_REPORT));
/* Now copy the instruction stream and set the count */ /* Now copy the instruction stream and set the count */
@ -402,7 +428,9 @@ NTAPI
KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version) KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
{ {
/* Copy the version block */ /* Copy the version block */
RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64)); KdpMoveMemory(Version,
&KdVersionBlock,
sizeof(DBGKD_GET_VERSION64));
} }
VOID VOID
@ -711,7 +739,9 @@ KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
} }
/* Copy it over to the debugger */ /* Copy it over to the debugger */
RtlCopyMemory(Data->Buffer, TargetContext, sizeof(CONTEXT)); KdpMoveMemory(Data->Buffer,
TargetContext,
sizeof(CONTEXT));
Data->Length = sizeof(CONTEXT); Data->Length = sizeof(CONTEXT);
/* Let the debugger set the context now */ /* Let the debugger set the context now */
@ -765,7 +795,9 @@ KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
} }
/* Copy the new context to it */ /* Copy the new context to it */
RtlCopyMemory(TargetContext, Data->Buffer, sizeof(CONTEXT)); KdpMoveMemory(TargetContext,
Data->Buffer,
sizeof(CONTEXT));
/* Finish up */ /* Finish up */
State->ReturnStatus = STATUS_SUCCESS; State->ReturnStatus = STATUS_SUCCESS;
@ -819,7 +851,7 @@ KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
} }
/* Copy what is requested */ /* Copy what is requested */
RtlCopyMemory(Data->Buffer, KdpMoveMemory(Data->Buffer,
(PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset), (PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
ContextEx->ByteCount); ContextEx->ByteCount);
@ -883,7 +915,7 @@ KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
} }
/* Copy what is requested */ /* Copy what is requested */
RtlCopyMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset), KdpMoveMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
Data->Buffer, Data->Buffer,
ContextEx->ByteCount); ContextEx->ByteCount);
@ -1639,7 +1671,7 @@ KdpReportCommandStringStateChange(IN PSTRING NameString,
KdpSetContextState(&WaitStateChange, Context); KdpSetContextState(&WaitStateChange, Context);
/* Clear the command string structure */ /* Clear the command string structure */
RtlZeroMemory(&WaitStateChange.u.CommandString, KdpZeroMemory(&WaitStateChange.u.CommandString,
sizeof(DBGKD_COMMAND_STRING)); sizeof(DBGKD_COMMAND_STRING));
/* Normalize name string to max */ /* Normalize name string to max */
@ -1709,15 +1741,22 @@ KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
/* Build the architecture common parts of the message */ /* Build the architecture common parts of the message */
KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange); KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
/* Copy the Exception Record and set First Chance flag */
#if !defined(_WIN64) #if !defined(_WIN64)
/* Convert it and copy it over */
ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord, ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
&WaitStateChange.u.Exception.ExceptionRecord); &WaitStateChange.u.Exception.ExceptionRecord);
#else #else
RtlCopyMemory(&WaitStateChange.u.Exception.ExceptionRecord,
/* Just copy it directly, no need to convert */
KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord,
ExceptionRecord, ExceptionRecord,
sizeof(EXCEPTION_RECORD)); sizeof(EXCEPTION_RECORD));
#endif #endif
/* Set the First Chance flag */
WaitStateChange.u.Exception.FirstChance = !SecondChanceException; WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
/* Now finish creating the structure */ /* Now finish creating the structure */

View file

@ -21,12 +21,15 @@ KdpPrintString(IN PSTRING Output)
{ {
STRING Data, Header; STRING Data, Header;
DBGKD_DEBUG_IO DebugIo; DBGKD_DEBUG_IO DebugIo;
USHORT Length = Output->Length; USHORT Length;
/* Copy the string */ /* Copy the string */
RtlMoveMemory(KdpMessageBuffer, Output->Buffer, Length); KdpMoveMemory(KdpMessageBuffer,
Output->Buffer,
Output->Length);
/* Make sure we don't exceed the KD Packet size */ /* Make sure we don't exceed the KD Packet size */
Length = Output->Length;
if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE) if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
{ {
/* Normalize length */ /* Normalize length */
@ -59,15 +62,16 @@ KdpPromptString(IN PSTRING PromptString,
{ {
STRING Data, Header; STRING Data, Header;
DBGKD_DEBUG_IO DebugIo; DBGKD_DEBUG_IO DebugIo;
ULONG Length = PromptString->Length; ULONG Length;
KDSTATUS Status; KDSTATUS Status;
/* Copy the string to the message buffer */ /* Copy the string to the message buffer */
RtlCopyMemory(KdpMessageBuffer, KdpMoveMemory(KdpMessageBuffer,
PromptString->Buffer, PromptString->Buffer,
PromptString->Length); PromptString->Length);
/* Make sure we don't exceed the KD Packet size */ /* Make sure we don't exceed the KD Packet size */
Length = PromptString->Length;
if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE) if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
{ {
/* Normalize length */ /* Normalize length */
@ -84,7 +88,7 @@ KdpPromptString(IN PSTRING PromptString,
Header.Buffer = (PCHAR)&DebugIo; Header.Buffer = (PCHAR)&DebugIo;
/* Build the data */ /* Build the data */
Data.Length = PromptString->Length; Data.Length = Length;
Data.Buffer = KdpMessageBuffer; Data.Buffer = KdpMessageBuffer;
/* Send the packet */ /* Send the packet */
@ -111,10 +115,13 @@ KdpPromptString(IN PSTRING PromptString,
} while (Status != KdPacketReceived); } while (Status != KdPacketReceived);
/* Don't copy back a larger response than there is room for */ /* Don't copy back a larger response than there is room for */
Length = min(Length, ResponseString->MaximumLength); Length = min(Length,
ResponseString->MaximumLength);
/* Copy back the string and return the length */ /* Copy back the string and return the length */
RtlCopyMemory(ResponseString->Buffer, KdpMessageBuffer, Length); KdpMoveMemory(ResponseString->Buffer,
KdpMessageBuffer,
Length);
ResponseString->Length = (USHORT)Length; ResponseString->Length = (USHORT)Length;
/* Success; we don't need to resend */ /* Success; we don't need to resend */
@ -141,7 +148,7 @@ KdpCommandString(IN PSTRING NameString,
/* Save the CPU Control State and save the context */ /* Save the CPU Control State and save the context */
KiSaveProcessorControlState(&Prcb->ProcessorState); KiSaveProcessorControlState(&Prcb->ProcessorState);
RtlCopyMemory(&Prcb->ProcessorState.ContextFrame, KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
ContextRecord, ContextRecord,
sizeof(CONTEXT)); sizeof(CONTEXT));
@ -151,7 +158,7 @@ KdpCommandString(IN PSTRING NameString,
&Prcb->ProcessorState.ContextFrame); &Prcb->ProcessorState.ContextFrame);
/* Restore the processor state */ /* Restore the processor state */
RtlCopyMemory(ContextRecord, KdpMoveMemory(ContextRecord,
&Prcb->ProcessorState.ContextFrame, &Prcb->ProcessorState.ContextFrame,
sizeof(CONTEXT)); sizeof(CONTEXT));
KiRestoreProcessorControlState(&Prcb->ProcessorState); KiRestoreProcessorControlState(&Prcb->ProcessorState);
@ -181,7 +188,7 @@ KdpSymbol(IN PSTRING DllPath,
/* Save the CPU Control State and save the context */ /* Save the CPU Control State and save the context */
KiSaveProcessorControlState(&Prcb->ProcessorState); KiSaveProcessorControlState(&Prcb->ProcessorState);
RtlCopyMemory(&Prcb->ProcessorState.ContextFrame, KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
ContextRecord, ContextRecord,
sizeof(CONTEXT)); sizeof(CONTEXT));
@ -192,7 +199,7 @@ KdpSymbol(IN PSTRING DllPath,
&Prcb->ProcessorState.ContextFrame); &Prcb->ProcessorState.ContextFrame);
/* Restore the processor state */ /* Restore the processor state */
RtlCopyMemory(ContextRecord, KdpMoveMemory(ContextRecord,
&Prcb->ProcessorState.ContextFrame, &Prcb->ProcessorState.ContextFrame,
sizeof(CONTEXT)); sizeof(CONTEXT));
KiRestoreProcessorControlState(&Prcb->ProcessorState); KiRestoreProcessorControlState(&Prcb->ProcessorState);
@ -216,38 +223,48 @@ KdpPrompt(IN LPSTR PromptString,
PVOID CapturedPrompt, CapturedResponse; PVOID CapturedPrompt, CapturedResponse;
/* Normalize the lengths */ /* Normalize the lengths */
PromptLength = min(PromptLength, 512); PromptLength = min(PromptLength,
MaximumResponseLength = min(MaximumResponseLength, 512); 512);
MaximumResponseLength = min(MaximumResponseLength,
512);
/* Check if we need to verify the string */ /* Check if we need to verify the string */
if (PreviousMode != KernelMode) if (PreviousMode != KernelMode)
{ {
/* Capture user-mode buffers */ /* Handle user-mode buffers safely */
_SEH2_TRY _SEH2_TRY
{ {
ProbeForRead(PromptString, PromptLength, 1); /* Probe the prompt */
CapturedPrompt = alloca(512); ProbeForRead(PromptString,
RtlMoveMemory(CapturedPrompt, PromptString, PromptLength); PromptLength,
1);
/* Capture prompt */
CapturedPrompt = _alloca(PromptLength);
KdpMoveMemory(CapturedPrompt,
PromptString,
PromptLength);
PromptString = CapturedPrompt; PromptString = CapturedPrompt;
ProbeForWrite(ResponseString, MaximumResponseLength, 1); /* Probe and make room for response */
CapturedResponse = alloca(512); ProbeForWrite(ResponseString,
MaximumResponseLength,
1);
CapturedResponse = _alloca(MaximumResponseLength);
ResponseString = CapturedResponse;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
/* Bad string pointer, bail out */
_SEH2_YIELD(return 0); _SEH2_YIELD(return 0);
} }
_SEH2_END; _SEH2_END;
} }
else
{
CapturedResponse = ResponseString;
}
/* Setup the prompt and response buffers */ /* Setup the prompt and response buffers */
PromptBuffer.Buffer = PromptString; PromptBuffer.Buffer = PromptString;
PromptBuffer.Length = PromptLength; PromptBuffer.Length = PromptLength;
ResponseBuffer.Buffer = CapturedResponse; ResponseBuffer.Buffer = ResponseString;
ResponseBuffer.Length = 0; ResponseBuffer.Length = 0;
ResponseBuffer.MaximumLength = MaximumResponseLength; ResponseBuffer.MaximumLength = MaximumResponseLength;
@ -274,10 +291,14 @@ KdpPrompt(IN LPSTR PromptString,
{ {
_SEH2_TRY _SEH2_TRY
{ {
RtlMoveMemory(ResponseString, ResponseBuffer.Buffer, ResponseBuffer.Length); /* Safely copy back response to user mode */
KdpMoveMemory(ResponseString,
ResponseBuffer.Buffer,
ResponseBuffer.Length);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
/* String became invalid after we exited, fail */
_SEH2_YIELD(return 0); _SEH2_YIELD(return 0);
} }
_SEH2_END; _SEH2_END;
@ -326,13 +347,21 @@ KdpPrint(IN ULONG ComponentId,
/* Capture user-mode buffers */ /* Capture user-mode buffers */
_SEH2_TRY _SEH2_TRY
{ {
ProbeForRead(String, Length, 1); /* Probe the string */
CapturedString = alloca(512); ProbeForRead(String,
RtlMoveMemory(CapturedString, String, Length); Length,
1);
/* Capture it */
CapturedString = alloca(Length);
KdpMoveMemory(CapturedString,
String,
Length);
String = CapturedString; String = CapturedString;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
/* Bad pointer, fail the print */
_SEH2_YIELD(return STATUS_ACCESS_VIOLATION); _SEH2_YIELD(return STATUS_ACCESS_VIOLATION);
} }
_SEH2_END; _SEH2_END;

View file

@ -58,13 +58,14 @@ KdpReport(IN PKTRAP_FRAME TrapFrame,
{ {
BOOLEAN Enable, Handled; BOOLEAN Enable, Handled;
PKPRCB Prcb; PKPRCB Prcb;
NTSTATUS ExceptionCode = ExceptionRecord->ExceptionCode; NTSTATUS ExceptionCode;
/* /*
* Determine whether to pass the exception to the debugger. * Determine whether to pass the exception to the debugger.
* First, check if this is a "debug exception", meaning breakpoint * First, check if this is a "debug exception", meaning breakpoint
* (including debug service), single step and assertion failure exceptions. * (including debug service), single step and assertion failure exceptions.
*/ */
ExceptionCode = ExceptionRecord->ExceptionCode;
if ((ExceptionCode == STATUS_BREAKPOINT) || if ((ExceptionCode == STATUS_BREAKPOINT) ||
(ExceptionCode == STATUS_SINGLE_STEP) || (ExceptionCode == STATUS_SINGLE_STEP) ||
(ExceptionCode == STATUS_ASSERTION_FAILURE)) (ExceptionCode == STATUS_ASSERTION_FAILURE))
@ -92,8 +93,8 @@ KdpReport(IN PKTRAP_FRAME TrapFrame,
else if (SecondChanceException == FALSE) else if (SecondChanceException == FALSE)
{ {
/* /*
* This isn't a debug exception and the stop-on-exception flag isn't * This isn't a debug exception and the stop-on-exception flag isn't set,
* set, so don't bother * so don't bother handling it
*/ */
return FALSE; return FALSE;
} }
@ -107,7 +108,7 @@ KdpReport(IN PKTRAP_FRAME TrapFrame,
*/ */
Prcb = KeGetCurrentPrcb(); Prcb = KeGetCurrentPrcb();
KiSaveProcessorControlState(&Prcb->ProcessorState); KiSaveProcessorControlState(&Prcb->ProcessorState);
RtlCopyMemory(&Prcb->ProcessorState.ContextFrame, KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
ContextRecord, ContextRecord,
sizeof(CONTEXT)); sizeof(CONTEXT));
@ -118,7 +119,7 @@ KdpReport(IN PKTRAP_FRAME TrapFrame,
SecondChanceException); SecondChanceException);
/* Now restore the processor state, manually again. */ /* Now restore the processor state, manually again. */
RtlCopyMemory(ContextRecord, KdpMoveMemory(ContextRecord,
&Prcb->ProcessorState.ContextFrame, &Prcb->ProcessorState.ContextFrame,
sizeof(CONTEXT)); sizeof(CONTEXT));
KiRestoreProcessorControlState(&Prcb->ProcessorState); KiRestoreProcessorControlState(&Prcb->ProcessorState);
@ -138,7 +139,7 @@ KdpTrap(IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode, IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN SecondChanceException) IN BOOLEAN SecondChanceException)
{ {
BOOLEAN Unload = FALSE; BOOLEAN Unload;
ULONG_PTR ProgramCounter; ULONG_PTR ProgramCounter;
BOOLEAN Handled; BOOLEAN Handled;
NTSTATUS ReturnStatus; NTSTATUS ReturnStatus;
@ -156,6 +157,7 @@ KdpTrap(IN PKTRAP_FRAME TrapFrame,
ProgramCounter = KeGetContextPc(ContextRecord); ProgramCounter = KeGetContextPc(ContextRecord);
/* Check what kind of operation was requested from us */ /* Check what kind of operation was requested from us */
Unload = FALSE;
switch (ExceptionRecord->ExceptionInformation[0]) switch (ExceptionRecord->ExceptionInformation[0])
{ {
/* DbgPrint */ /* DbgPrint */
@ -164,27 +166,24 @@ KdpTrap(IN PKTRAP_FRAME TrapFrame,
/* Call the worker routine */ /* Call the worker routine */
ReturnStatus = KdpPrint((ULONG)KdpGetParameterThree(ContextRecord), ReturnStatus = KdpPrint((ULONG)KdpGetParameterThree(ContextRecord),
(ULONG)KdpGetParameterFour(ContextRecord), (ULONG)KdpGetParameterFour(ContextRecord),
(LPSTR)ExceptionRecord-> (LPSTR)ExceptionRecord->ExceptionInformation[1],
ExceptionInformation[1], (USHORT)ExceptionRecord->ExceptionInformation[2],
(USHORT)ExceptionRecord->
ExceptionInformation[2],
PreviousMode, PreviousMode,
TrapFrame, TrapFrame,
ExceptionFrame, ExceptionFrame,
&Handled); &Handled);
/* Update the return value for the caller */ /* Update the return value for the caller */
KeSetContextReturnRegister(ContextRecord, ReturnStatus); KeSetContextReturnRegister(ContextRecord,
ReturnStatus);
break; break;
/* DbgPrompt */ /* DbgPrompt */
case BREAKPOINT_PROMPT: case BREAKPOINT_PROMPT:
/* Call the worker routine */ /* Call the worker routine */
ReturnLength = KdpPrompt((LPSTR)ExceptionRecord-> ReturnLength = KdpPrompt((LPSTR)ExceptionRecord->ExceptionInformation[1],
ExceptionInformation[1], (USHORT)ExceptionRecord->ExceptionInformation[2],
(USHORT)ExceptionRecord->
ExceptionInformation[2],
(LPSTR)KdpGetParameterThree(ContextRecord), (LPSTR)KdpGetParameterThree(ContextRecord),
(USHORT)KdpGetParameterFour(ContextRecord), (USHORT)KdpGetParameterFour(ContextRecord),
PreviousMode, PreviousMode,
@ -276,9 +275,10 @@ KdpStub(IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode, IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN SecondChanceException) IN BOOLEAN SecondChanceException)
{ {
ULONG_PTR ExceptionCommand = ExceptionRecord->ExceptionInformation[0]; ULONG_PTR ExceptionCommand;
/* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */ /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
(ExceptionRecord->NumberParameters > 0) && (ExceptionRecord->NumberParameters > 0) &&
((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) || ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||

View file

@ -44,6 +44,14 @@ MiInitializeSessionWsSupport(VOID)
InitializeListHead(&MmWorkingSetExpansionHead); InitializeListHead(&MmWorkingSetExpansionHead);
} }
BOOLEAN
NTAPI
MmIsSessionAddress(IN PVOID Address)
{
/* Check if it is in range */
return MI_IS_SESSION_ADDRESS(Address) ? TRUE : FALSE;
}
LCID LCID
NTAPI NTAPI
MmGetSessionLocaleId(VOID) MmGetSessionLocaleId(VOID)