diff --git a/ntoskrnl/ex/dbgctrl.c b/ntoskrnl/ex/dbgctrl.c index 74baed017f2bb..e3d86224e8922 100644 --- a/ntoskrnl/ex/dbgctrl.c +++ b/ntoskrnl/ex/dbgctrl.c @@ -208,6 +208,52 @@ NtSystemDebugControl( _In_ ULONG OutputBufferLength, _Out_opt_ PULONG ReturnLength) { + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + + /* Debugger controlling requires the debug privilege */ + if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) + { + return STATUS_ACCESS_DENIED; + } + + /* Live dumping is allowed even if kernel debugging is disabled or absent. + * Otherwise, check whether the kernel debugger is present and fail if not. */ + if ((Command != SysDbgGetTriageDump) +#if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81 + && (Command != SysDbgGetLiveKernelDump) +#endif + ) + { + if (KdDebuggerNotPresent || KdPitchDebugger) + return STATUS_DEBUGGER_INACTIVE; + } + + /* Probe the parameters if we are called from user-mode */ + if (PreviousMode != KernelMode) + { + _SEH2_TRY + { + if (InputBufferLength != 0) + ProbeForRead(InputBuffer, InputBufferLength, sizeof(ULONG)); + if (OutputBufferLength != 0) + ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG)); + if (ReturnLength) + ProbeForWriteUlong(ReturnLength, sizeof(*ReturnLength), sizeof(ULONG)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + } + + /* Default to returning success */ + Status = STATUS_SUCCESS; + + /* Protect all cases with SEH */ + _SEH2_TRY + { switch (Command) { /* Commands 0-5 */ @@ -217,9 +263,12 @@ NtSystemDebugControl( case SysDbgSetSpecialCall: case SysDbgClearSpecialCalls: case SysDbgQuerySpecialCalls: + _SEH2_YIELD(return STATUS_NOT_IMPLEMENTED); /* Command 6 */ case SysDbgBreakPoint: + DbgBreakPointWithStatus(DBG_STATUS_DEBUG_CONTROL); + break; /* Commands 7-20 - Implemented by KdSystemDebugControl() instead */ case SysDbgQueryVersion: @@ -236,30 +285,114 @@ NtSystemDebugControl( case SysDbgReadBusData: case SysDbgWriteBusData: case SysDbgCheckLowMemory: - - /* Command 29 */ - case SysDbgGetTriageDump: - return STATUS_NOT_IMPLEMENTED; + _SEH2_YIELD(return STATUS_NOT_IMPLEMENTED); /* Commands 21-28 */ case SysDbgEnableKernelDebugger: + { + Status = KdEnableDebugger(); + break; + } case SysDbgDisableKernelDebugger: + { + Status = KdDisableDebugger(); + break; + } + case SysDbgGetAutoKdEnable: + { + if (OutputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + *(PBOOLEAN)OutputBuffer = KdAutoEnableOnEvent; + break; + } case SysDbgSetAutoKdEnable: + { + if (InputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + KdAutoEnableOnEvent = !!*(PBOOLEAN)InputBuffer; + break; + } + case SysDbgGetPrintBufferSize: + { + if (OutputBufferLength != sizeof(ULONG)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + *(PULONG)OutputBuffer = KdPrintBufferSize; + break; + } case SysDbgSetPrintBufferSize: + _SEH2_YIELD(return STATUS_NOT_IMPLEMENTED); + case SysDbgGetKdUmExceptionEnable: + { + if (OutputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + *(PBOOLEAN)OutputBuffer = KdIgnoreUmExceptions; + break; + } case SysDbgSetKdUmExceptionEnable: + { + if (InputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + KdIgnoreUmExceptions = !!*(PBOOLEAN)InputBuffer; + break; + } + + /* Command 29 */ + case SysDbgGetTriageDump: + // This is implemented in Vista+. + DbgPrint("%s: Command %d is unimplemented!\n", __FUNCTION__, Command); + _SEH2_YIELD(return STATUS_NOT_IMPLEMENTED); /* Commands 30-31 */ case SysDbgGetKdBlockEnable: + { + if (OutputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + *(PBOOLEAN)OutputBuffer = KdBlockEnable; + break; + } case SysDbgSetKdBlockEnable: - return KdSystemDebugControl( - Command, - InputBuffer, InputBufferLength, - OutputBuffer, OutputBufferLength, - ReturnLength, KeGetPreviousMode()); + { + if (InputBufferLength != sizeof(BOOLEAN)) + _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); + KdBlockEnable = !!*(PBOOLEAN)InputBuffer; + break; + } + + /* Commands 32-3x */ +#if (NTDDI_VERSION >= NTDDI_VISTA) + case SysDbgRegisterForUmBreakInfo: + case SysDbgGetUmBreakPid: + case SysDbgClearUmBreakPid: + case SysDbgGetUmAttachPid: + case SysDbgClearUmAttachPid: +#if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81 + case SysDbgGetLiveKernelDump: +#endif +#if (NTDDI_VERSION >= NTDDI_WIN10_VB) + case SysDbgKdPullRemoteFile: +#endif + DbgPrint("%s: Command %d is unimplemented!\n", __FUNCTION__, Command); + _SEH2_YIELD(return STATUS_NOT_IMPLEMENTED); +#endif // (NTDDI_VERSION >= NTDDI_VISTA) + default: - return STATUS_INVALID_INFO_CLASS; + Status = STATUS_INVALID_INFO_CLASS; + break; + } + + /* Return the actual data length written in the output buffer, if requested */ + // FIXME: A non-zero length is returned only for the dump commands. + if (ReturnLength) + *ReturnLength = 0; } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + + return Status; } diff --git a/ntoskrnl/kd64/kdapi.c b/ntoskrnl/kd64/kdapi.c index 21ac8d8017f44..0d12d5b79a8f2 100644 --- a/ntoskrnl/kd64/kdapi.c +++ b/ntoskrnl/kd64/kdapi.c @@ -2222,6 +2222,10 @@ KdSystemDebugControl( _Out_opt_ PULONG ReturnLength, _In_ KPROCESSOR_MODE PreviousMode) { + /* Check whether the kernel debugger is present and fail if not */ + if (KdDebuggerNotPresent || KdPitchDebugger) + return STATUS_DEBUGGER_INACTIVE; + /* Handle some internal commands */ switch ((ULONG)Command) { @@ -2281,10 +2285,232 @@ KdSystemDebugControl( } #endif // KDBG #endif + default: break; } +// Cases 7 to 20 done here... + switch (Command) + { + case SysDbgQueryVersion: + { + if (OutputBufferLength != sizeof(DBGKD_GET_VERSION64)) + return STATUS_INFO_LENGTH_MISMATCH; + KdpSysGetVersion((PDBGKD_GET_VERSION64)OutputBuffer); + return STATUS_SUCCESS; + } + + case SysDbgReadVirtual: + { + /* + OutputBuffer; + OutputBufferLength; + KdpCopyMemoryChunks(); + */ + break; + } + + case SysDbgWriteVirtual: + { + /* + InputBuffer; + InputBufferLength; + KdpCopyMemoryChunks(); + */ + break; + } + + case SysDbgReadPhysical: + { + /* + OutputBuffer; + OutputBufferLength; + KdpCopyMemoryChunks(); + */ + break; + } + + case SysDbgWritePhysical: + { + /* + InputBuffer; + InputBufferLength; + KdpCopyMemoryChunks(); + */ + break; + } + + case SysDbgReadControlSpace: + { + PSYSDBG_CONTROL_SPACE ReadMemory; + ULONG Length; + NTSTATUS ReturnStatus; + + if (OutputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) + return STATUS_INFO_LENGTH_MISMATCH; + + ReadMemory = (PSYSDBG_CONTROL_SPACE)OutputBuffer; + ReturnStatus = KdpSysReadControlSpace(ReadMemory->Processor, + ReadMemory->Address, + ReadMemory->Buffer, + ReadMemory->Request, + &Length); + + /* Return the actual length read */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgWriteControlSpace: + { + PSYSDBG_CONTROL_SPACE WriteMemory; + ULONG Length; + NTSTATUS ReturnStatus; + + if (OutputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) + return STATUS_INFO_LENGTH_MISMATCH; + + WriteMemory = (PSYSDBG_CONTROL_SPACE)OutputBuffer; + ReturnStatus = KdpSysWriteControlSpace(WriteMemory->Processor, + WriteMemory->Address, + WriteMemory->Buffer, + WriteMemory->Request, + &Length); + + /* Return the actual length written */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgReadIoSpace: + { + PSYSDBG_IO_SPACE IoSpace; + ULONG Length; + NTSTATUS ReturnStatus; + + if (OutputBufferLength != sizeof(SYSDBG_IO_SPACE)) + return STATUS_INFO_LENGTH_MISMATCH; + + IoSpace = (PSYSDBG_IO_SPACE)OutputBuffer; + ReturnStatus = KdpSysReadIoSpace(IoSpace->InterfaceType, + IoSpace->BusNumber, + IoSpace->AddressSpace, + IoSpace->IoAddress, + IoSpace->Buffer, + IoSpace->Request, + &Length); + + /* Return the actual length read */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgWriteIoSpace: + { + PSYSDBG_IO_SPACE IoSpace; + ULONG Length; + NTSTATUS ReturnStatus; + + if (InputBufferLength != sizeof(SYSDBG_IO_SPACE)) + return STATUS_INFO_LENGTH_MISMATCH; + + IoSpace = (PSYSDBG_IO_SPACE)InputBuffer; + ReturnStatus = KdpSysWriteIoSpace(IoSpace->InterfaceType, + IoSpace->BusNumber, + IoSpace->AddressSpace, + IoSpace->IoAddress, + IoSpace->Buffer, + IoSpace->Request, + &Length); + + /* Return the actual length written */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgReadMsr: + { + PSYSDBG_MSR ReadMsr; + + if (OutputBufferLength != sizeof(SYSDBG_MSR)) + return STATUS_INFO_LENGTH_MISMATCH; + + ReadMsr = (PSYSDBG_MSR)OutputBuffer; + return KdpSysReadMsr(ReadMsr->Address, &ReadMsr->Data); + } + + case SysDbgWriteMsr: + { + PSYSDBG_MSR WriteMsr; + + if (InputBufferLength != sizeof(SYSDBG_MSR)) + return STATUS_INFO_LENGTH_MISMATCH; + + WriteMsr = (PSYSDBG_MSR)InputBuffer; + return KdpSysWriteMsr(WriteMsr->Address, &WriteMsr->Data); + } + + case SysDbgReadBusData: + { + PSYSDBG_BUS_DATA BusData; + ULONG Length; + NTSTATUS ReturnStatus; + + if (OutputBufferLength != sizeof(SYSDBG_BUS_DATA)) + return STATUS_INFO_LENGTH_MISMATCH; + + BusData = (PSYSDBG_BUS_DATA)OutputBuffer; + ReturnStatus = KdpSysReadBusData(BusData->BusDataType, + BusData->BusNumber, + BusData->SlotNumber, + BusData->Address, + BusData->Buffer, + BusData->Request, + &Length); + + /* Return the actual length read */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgWriteBusData: + { + PSYSDBG_BUS_DATA BusData; + ULONG Length; + NTSTATUS ReturnStatus; + + if (InputBufferLength != sizeof(SYSDBG_BUS_DATA)) + return STATUS_INFO_LENGTH_MISMATCH; + + BusData = (PSYSDBG_BUS_DATA)InputBuffer; + ReturnStatus = KdpSysWriteBusData(BusData->BusDataType, + BusData->BusNumber, + BusData->SlotNumber, + BusData->Address, + BusData->Buffer, + BusData->Request, + &Length); + + /* Return the actual length written */ + if (ReturnLength) + *ReturnLength = Length; + return ReturnStatus; + } + + case SysDbgCheckLowMemory: + // return KdpSysCheckLowMemory(); but which flags? + break; + + default: + return STATUS_INVALID_INFO_CLASS; + } + /* Local kernel debugging is not yet supported */ DbgPrint("KdSystemDebugControl is unimplemented!\n"); return STATUS_NOT_IMPLEMENTED;