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
);
//
// 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
//

View file

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

View file

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

View file

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

View file

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