Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ex/harderr.c * PURPOSE: Error Functions and Status/Exception Dispatching/Raising * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* GLOBALS ******************************************************************/
BOOLEAN ExReadyForErrors = FALSE;PVOID ExpDefaultErrorPort = NULL;PEPROCESS ExpDefaultErrorPortProcess = NULL;
/* FUNCTIONS ****************************************************************/
/*++* @name ExpSystemErrorHandler** For now it's a stub** @param ErrorStatus* FILLME** @param NumberOfParameters* FILLME** @param UnicodeStringParameterMask* FILLME** @param Parameters* FILLME** @param ValidResponseOptions* FILLME** @param Response* FILLME** @return None** @remarks None**--*/NTSTATUSNTAPIExpSystemErrorHandler(IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG_PTR Parameters, IN BOOLEAN Shutdown){ ULONG_PTR BugCheckParameters[MAXIMUM_HARDERROR_PARAMETERS] = {0, 0, 0, 0}; ULONG i;
/* Sanity check */ ASSERT(NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
/* * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters, * but we might get called with less, so use a local buffer here. */ for (i = 0; i < NumberOfParameters; i++) { /* Copy them over */ BugCheckParameters[i] = Parameters[i]; }
/* FIXME: STUB */ KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR, ErrorStatus, (ULONG_PTR)BugCheckParameters, 0, 0); return STATUS_SUCCESS;}
/*++ * @name ExpRaiseHardError * @implemented * * See ExRaiseHardError and NtRaiseHardError, same parameters. * * This function performs the central work for both ExRaiseHardError * and NtRaiseHardError. ExRaiseHardError is the service for kernel-mode * that copies the parameters to user-mode, and NtRaiseHardError is the * service for both kernel-mode and user-mode that performs parameters * validation and capture if necessary. * *--*/NTSTATUSNTAPIExpRaiseHardError(IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG_PTR Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response){ NTSTATUS Status; PEPROCESS Process = PsGetCurrentProcess(); PETHREAD Thread = PsGetCurrentThread(); UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; PHARDERROR_MSG Message = (PHARDERROR_MSG)Buffer; HANDLE PortHandle; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PAGED_CODE();
/* Check if this error will shutdown the system */ if (ValidResponseOptions == OptionShutdownSystem) { /* * Check if we have the privileges. * * NOTE: In addition to the Shutdown privilege we also check whether * the caller has the Tcb privilege. The purpose is to allow only * SYSTEM processes to "shutdown" the system on hard errors (BSOD) * while forbidding regular processes to do so. This behaviour differs * from Windows, where any user-mode process, as soon as it has the * Shutdown privilege, can trigger a hard-error BSOD. */ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode) || !SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) { /* No rights */ *Response = ResponseNotHandled; return STATUS_PRIVILEGE_NOT_HELD; }
/* Don't handle any new hard errors */ ExReadyForErrors = FALSE; }
/* Check if hard errors are not disabled */ if (!Thread->HardErrorsAreDisabled) { /* Check if we can't do errors anymore, and this is serious */ if (!ExReadyForErrors && NT_ERROR(ErrorStatus)) { /* Use the system handler */ ExpSystemErrorHandler(ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, Parameters, (PreviousMode != KernelMode) ? TRUE : FALSE); } }
/* * Enable hard error processing if it is enabled for the process * or if the exception status forces it. */ if ((Process->DefaultHardErrorProcessing & SEM_FAILCRITICALERRORS) || (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE)) { /* Check if we have an exception port */ if (Process->ExceptionPort) { /* Use the port */ PortHandle = Process->ExceptionPort; } else { /* Use our default system port */ PortHandle = ExpDefaultErrorPort; } } else { /* Don't process the error */ PortHandle = NULL; }
/* If hard errors are disabled, do nothing */ if (Thread->HardErrorsAreDisabled) PortHandle = NULL;
/* * If this is not the system thread, check whether hard errors are * disabled for this thread on user-mode side, and if so, do nothing. */ if (!Thread->SystemThread && (PortHandle != NULL)) { /* Check if we have a TEB */ PTEB Teb = PsGetCurrentThread()->Tcb.Teb; if (Teb) { _SEH2_TRY { if (Teb->HardErrorMode & RTL_SEM_FAILCRITICALERRORS) { PortHandle = NULL; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { NOTHING; } _SEH2_END; } }
/* Now check if we have a port */ if (PortHandle == NULL) { /* Just return to caller */ *Response = ResponseReturnToCaller; return STATUS_SUCCESS; }
/* Check if this is the default process */ if (Process == ExpDefaultErrorPortProcess) { /* We can't handle the error, check if this is critical */ if (NT_ERROR(ErrorStatus)) { /* It is, invoke the system handler */ ExpSystemErrorHandler(ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, Parameters, (PreviousMode != KernelMode) ? TRUE : FALSE);
/* If we survived, return to caller */ *Response = ResponseReturnToCaller; return STATUS_SUCCESS; } }
/* Setup the LPC Message */ Message->h.u1.Length = (sizeof(HARDERROR_MSG) << 16) | (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE)); Message->h.u2.ZeroInit = 0; Message->h.u2.s2.Type = LPC_ERROR_EVENT; Message->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE; Message->ValidResponseOptions = ValidResponseOptions; Message->UnicodeStringParameterMask = UnicodeStringParameterMask; Message->NumberOfParameters = NumberOfParameters; KeQuerySystemTime(&Message->ErrorTime);
/* Copy the parameters */ if (Parameters) { RtlMoveMemory(&Message->Parameters, Parameters, sizeof(ULONG_PTR) * NumberOfParameters); }
/* Send the LPC Message */ Status = LpcRequestWaitReplyPort(PortHandle, (PPORT_MESSAGE)Message, (PPORT_MESSAGE)Message); if (NT_SUCCESS(Status)) { /* Check what kind of response we got */ if ((Message->Response != ResponseReturnToCaller) && (Message->Response != ResponseNotHandled) && (Message->Response != ResponseAbort) && (Message->Response != ResponseCancel) && (Message->Response != ResponseIgnore) && (Message->Response != ResponseNo) && (Message->Response != ResponseOk) && (Message->Response != ResponseRetry) && (Message->Response != ResponseYes) && (Message->Response != ResponseTryAgain) && (Message->Response != ResponseContinue)) { /* Reset to a default one */ Message->Response = ResponseReturnToCaller; }
/* Set the response */ *Response = Message->Response; } else { /* Set the response */ *Response = ResponseReturnToCaller; }
/* Return status */ return Status;}
/*++ * @name ExRaiseAccessViolation * @implemented * * The ExRaiseAccessViolation routine can be used with structured exception * handling to throw a driver-determined exception for a memory access * violation that occurs when a driver processes I/O requests. * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true (DEAD_LINK) * https://web.archive.org/web/20081231000748/http://www.osronline.com/ddkx/kmarch/k102_814i.htm * * @return None * * @remarks None * *--*/VOIDNTAPIExRaiseAccessViolation(VOID){ /* Raise the Right Status */ RtlRaiseStatus(STATUS_ACCESS_VIOLATION);}
/*++ * @name ExRaiseDatatypeMisalignment * @implemented * * ExRaiseDatatypeMisalignment raises an exception with the exception * code set to STATUS_DATATYPE_MISALIGNMENT * See: MSDN / DDK * https://web.archive.org/web/20081231000748/http://www.osronline.com/ddkx/kmarch/k102_814i.htm * * @return None * * @remarks None * *--*/VOIDNTAPIExRaiseDatatypeMisalignment(VOID){ /* Raise the Right Status */ RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);}
/*++ * @name ExSystemExceptionFilter * @implemented * * TODO: Add description * * @return FILLME * * @remarks None * *--*/LONGNTAPIExSystemExceptionFilter(VOID){ return KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;}
/*++ * @name ExRaiseHardError * @implemented * * See NtRaiseHardError and ExpRaiseHardError. * * @param ErrorStatus * Error Code * * @param NumberOfParameters * Number of optional parameters in Parameters array * * @param UnicodeStringParameterMask * Optional string parameter (can be only one per error code) * * @param Parameters * Array of ULONG parameters for use in error message string * * @param ValidResponseOptions * See HARDERROR_RESPONSE_OPTION for possible values description * * @param Response * Pointer to HARDERROR_RESPONSE enumeration * * @return Status * *--*/NTSTATUSNTAPIExRaiseHardError(IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG_PTR Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response){ NTSTATUS Status; SIZE_T Size; UNICODE_STRING CapturedParams[MAXIMUM_HARDERROR_PARAMETERS]; ULONG i; PVOID UserData = NULL; PHARDERROR_USER_PARAMETERS UserParams; PWSTR BufferBase; ULONG SafeResponse = ResponseNotHandled;
PAGED_CODE();
/* Check if we have parameters */ if (Parameters) { /* Check if we have strings */ if (UnicodeStringParameterMask) { /* Calculate the required size */ Size = FIELD_OFFSET(HARDERROR_USER_PARAMETERS, Buffer[0]);
/* Loop each parameter */ for (i = 0; i < NumberOfParameters; i++) { /* Check if it's part of the mask */ if (UnicodeStringParameterMask & (1 << i)) { /* Copy it */ RtlMoveMemory(&CapturedParams[i], (PVOID)Parameters[i], sizeof(UNICODE_STRING));
/* Increase the size */ Size += CapturedParams[i].MaximumLength; } }
/* Allocate the user data region */ Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserData, 0, &Size, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { /* Return failure */ *Response = ResponseNotHandled; return Status; }
/* Set the pointers to our data */ UserParams = UserData; BufferBase = UserParams->Buffer;
/* Enter SEH block as we are writing to user-mode space */ _SEH2_TRY { /* Loop parameters again */ for (i = 0; i < NumberOfParameters; i++) { /* Check if we are in the mask */ if (UnicodeStringParameterMask & (1 << i)) { /* Update the base */ UserParams->Parameters[i] = (ULONG_PTR)&UserParams->Strings[i];
/* Copy the string buffer */ RtlMoveMemory(BufferBase, CapturedParams[i].Buffer, CapturedParams[i].MaximumLength);
/* Set buffer */ CapturedParams[i].Buffer = BufferBase;
/* Copy the string structure */ UserParams->Strings[i] = CapturedParams[i];
/* Update the pointer */ BufferBase += CapturedParams[i].MaximumLength; } else { /* No need to copy any strings */ UserParams->Parameters[i] = Parameters[i]; } } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ Status = _SEH2_GetExceptionCode(); DPRINT1("ExRaiseHardError - Exception when writing data to user-mode, Status 0x%08lx\n", Status); } _SEH2_END; } else { /* Just keep the data as is */ UserData = Parameters; } }
/* Now call the worker function */ Status = ExpRaiseHardError(ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, UserData, ValidResponseOptions, &SafeResponse);
/* Check if we had done user-mode allocation */ if ((UserData) && (UserData != Parameters)) { /* We did! Delete it */ Size = 0; ZwFreeVirtualMemory(NtCurrentProcess(), &UserData, &Size, MEM_RELEASE); }
/* Return status and the response */ *Response = SafeResponse; return Status;}
/*++ * @name NtRaiseHardError * @implemented * * This function sends HARDERROR_MSG LPC message to a hard-error listener, * typically CSRSS.EXE. See NtSetDefaultHardErrorPort for more information. * See also: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html * * @param ErrorStatus * Error Code * * @param NumberOfParameters * Number of optional parameters in Parameters array * * @param UnicodeStringParameterMask * Optional string parameter (can be only one per error code) * * @param Parameters * Array of ULONG_PTR parameters for use in error message string * * @param ValidResponseOptions * See HARDERROR_RESPONSE_OPTION for possible values description * * @param Response * Pointer to HARDERROR_RESPONSE enumeration * * @return Status * * @remarks NtRaiseHardError constitutes an easy way to display messages * in GUI without loading any Win32 API libraries. * *--*/NTSTATUSNTAPINtRaiseHardError(IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG_PTR Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response){ NTSTATUS Status = STATUS_SUCCESS; PULONG_PTR SafeParams = NULL; ULONG SafeResponse = ResponseNotHandled; UNICODE_STRING SafeString; ULONG i; ULONG ParamSize = 0; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PAGED_CODE();
/* Validate parameter count */ if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS) { /* Fail */ return STATUS_INVALID_PARAMETER_2; }
/* Make sure we have some at least */ if ((Parameters != NULL) && (NumberOfParameters == 0)) { /* Fail */ return STATUS_INVALID_PARAMETER_2; }
/* Check if we were called from user-mode */ if (PreviousMode != KernelMode) { /* First validate the responses */ switch (ValidResponseOptions) { /* Check all valid cases */ case OptionAbortRetryIgnore: case OptionOk: case OptionOkCancel: case OptionRetryCancel: case OptionYesNo: case OptionYesNoCancel: case OptionShutdownSystem: case OptionOkNoWait: case OptionCancelTryContinue: break;
/* Anything else is invalid */ default: return STATUS_INVALID_PARAMETER_4; }
/* Check if we have parameters */ if (Parameters) { /* Calculate size of the parameters */ ParamSize = sizeof(ULONG_PTR) * NumberOfParameters;
/* Allocate a safe buffer */ SafeParams = ExAllocatePoolWithTag(PagedPool, ParamSize, TAG_ERR); if (!SafeParams) { return STATUS_INSUFFICIENT_RESOURCES; } }
/* Enter SEH Block */ _SEH2_TRY { /* Validate the response pointer */ ProbeForWriteUlong(Response);
/* Check if we have parameters */ if (Parameters) { /* Validate the parameter pointers */ ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR));
/* Copy them */ RtlCopyMemory(SafeParams, Parameters, ParamSize);
/* Now check if there's strings in it */ if (UnicodeStringParameterMask) { /* Loop every string */ for (i = 0; i < NumberOfParameters; i++) { /* Check if this parameter is a string */ if (UnicodeStringParameterMask & (1 << i)) { /* Probe the structure */ ProbeForRead((PVOID)SafeParams[i], sizeof(UNICODE_STRING), sizeof(ULONG_PTR));
/* Capture it */ RtlCopyMemory(&SafeString, (PVOID)SafeParams[i], sizeof(UNICODE_STRING));
/* Probe the buffer */ ProbeForRead(SafeString.Buffer, SafeString.MaximumLength, sizeof(UCHAR)); } } } } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Free captured buffer */ if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
/* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Call the system function directly, because we probed */ Status = ExpRaiseHardError(ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, SafeParams, ValidResponseOptions, &SafeResponse);
/* Free captured buffer */ if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
/* Enter SEH Block to return the response */ _SEH2_TRY { /* Return the response */ *Response = SafeResponse; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END; } else { /* Reuse variable */ SafeParams = Parameters;
/* * Call the Executive Function. It will probe * and copy pointers to user-mode. */ Status = ExRaiseHardError(ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, SafeParams, ValidResponseOptions, &SafeResponse);
/* Return the response */ *Response = SafeResponse; }
/* Return status */ return Status;}
/*++ * @name NtSetDefaultHardErrorPort * @implemented * * NtSetDefaultHardErrorPort is typically called only once. After the call, * the kernel sets a BOOLEAN flag named ExReadyForErrors to TRUE, and all other * attempts to change the default port fail with STATUS_UNSUCCESSFUL error code. * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html * https://web.archive.org/web/20070716133753/http://www.windowsitlibrary.com/Content/356/08/2.html * * @param PortHandle * Handle to named port object * * @return Status * * @remarks Privileges: SE_TCB_PRIVILEGE * *--*/NTSTATUSNTAPINtSetDefaultHardErrorPort(IN HANDLE PortHandle){ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status = STATUS_UNSUCCESSFUL;
PAGED_CODE();
/* Check if we have the privileges */ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) { DPRINT1("NtSetDefaultHardErrorPort: Caller requires " "the SeTcbPrivilege privilege!\n"); return STATUS_PRIVILEGE_NOT_HELD; }
/* Only called once during bootup, make sure we weren't called yet */ if (!ExReadyForErrors) { /* Reference the hard-error port */ Status = ObReferenceObjectByHandle(PortHandle, 0, LpcPortObjectType, PreviousMode, (PVOID*)&ExpDefaultErrorPort, NULL); if (NT_SUCCESS(Status)) { /* Keep also a reference to the process handling the hard errors */ ExpDefaultErrorPortProcess = PsGetCurrentProcess(); ObReferenceObject(ExpDefaultErrorPortProcess); ExReadyForErrors = TRUE; Status = STATUS_SUCCESS; } }
/* Return status to caller */ return Status;}
VOID__cdecl_purecall(VOID){ /* Not supported in Kernel Mode */ RtlRaiseStatus(STATUS_NOT_IMPLEMENTED);}
/* EOF */