/* Check if this error will shutdown the system */
if (ValidResponseOptions == OptionShutdownSystem)
{
- /* Check for privilege */
- if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
+ /*
+ * 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;
if (!Thread->HardErrorsAreDisabled)
{
/* Check if we can't do errors anymore, and this is serious */
- if ((!ExReadyForErrors) && (NT_ERROR(ErrorStatus)))
+ if (!ExReadyForErrors && NT_ERROR(ErrorStatus))
{
/* Use the system handler */
ExpSystemErrorHandler(ErrorStatus,
/* Enable hard error processing if it is enabled for the process
* or if the exception status forces it */
if ((Process->DefaultHardErrorProcessing & 1) ||
- (ErrorStatus & 0x10000000))
+ (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE))
{
/* Check if we have an exception port */
if (Process->ExceptionPort)
if (Thread->HardErrorsAreDisabled) PortHandle = NULL;
/* Now check if we have a port */
- if (PortHandle)
+ if (PortHandle == NULL)
{
- /* 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;
- }
- }
+ /* Just 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 &~ 0x10000000;
- 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,
- (PVOID)Message,
- (PVOID)Message);
- if (NT_SUCCESS(Status))
+ /* 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))
{
- /* 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;
- }
+ /* It is, invoke the system handler */
+ ExpSystemErrorHandler(ErrorStatus,
+ NumberOfParameters,
+ UnicodeStringParameterMask,
+ Parameters,
+ (PreviousMode != KernelMode) ? TRUE: FALSE);
- /* Set the response */
- *Response = Message->Response;
+ /* If we survived, return to caller */
+ *Response = ResponseReturnToCaller;
+ return STATUS_SUCCESS;
}
- else
+ }
+
+ /* 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))
{
- /* Set the response */
- *Response = ResponseReturnToCaller;
+ /* Reset to a default one */
+ Message->Response = ResponseReturnToCaller;
}
+
+ /* Set the response */
+ *Response = Message->Response;
}
else
{
- /* Set defaults */
+ /* Set the response */
*Response = ResponseReturnToCaller;
- Status = STATUS_SUCCESS;
}
/* Return status */
case OptionYesNo:
case OptionYesNoCancel:
case OptionShutdownSystem:
+ case OptionOkNoWait:
+ case OptionCancelTryContinue:
break;
/* Anything else is invalid */
* @implemented
*
* NtSetDefaultHardErrorPort is typically called only once. After call,
- * kernel set BOOLEAN flag named _ExReadyForErrors to TRUE, and all other
+ * kernel set BOOLEAN flag named ExReadyForErrors to TRUE, and all other
* tries to change default port are broken with STATUS_UNSUCCESSFUL error code
* See: http://www.windowsitlibrary.com/Content/356/08/2.html
* http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- /* Check if we have the Privilege */
+ /* Check if we have the privileges */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
{
DPRINT1("NtSetDefaultHardErrorPort: Caller requires "
/* Only called once during bootup, make sure we weren't called yet */
if (!ExReadyForErrors)
{
- /* Reference the port */
+ /* Reference the hard-error port */
Status = ObReferenceObjectByHandle(PortHandle,
0,
LpcPortObjectType,
NULL);
if (NT_SUCCESS(Status))
{
- /* Save the data */
+ /* Keep also a reference to the process handling the hard errors */
ExpDefaultErrorPortProcess = PsGetCurrentProcess();
+ ObReferenceObject(ExpDefaultErrorPortProcess);
ExReadyForErrors = TRUE;
+ Status = STATUS_SUCCESS;
}
}