2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/error.c
5 * PURPOSE: Error Functions and Status/Exception Dispatching/Raising
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *****************************************************************/
15 #define TAG_ERR ' rrE'
17 /* GLOBALS ****************************************************************/
19 BOOLEAN ExReadyForErrors
= FALSE
;
20 PVOID ExpDefaultErrorPort
= NULL
;
21 PEPROCESS ExpDefaultErrorPortProcess
= NULL
;
23 /* FUNCTIONS ****************************************************************/
26 * @name ExpSystemErrorHandler
33 * @param NumberOfParameters
36 * @param UnicodeStringParameterMask
42 * @param ValidResponseOptions
55 ExpSystemErrorHandler(IN NTSTATUS ErrorStatus
,
56 IN ULONG NumberOfParameters
,
57 IN ULONG UnicodeStringParameterMask
,
58 IN PULONG_PTR Parameters
,
61 ULONG_PTR BugCheckParameters
[MAXIMUM_HARDERROR_PARAMETERS
] = {0, 0, 0, 0};
65 ASSERT(NumberOfParameters
<= MAXIMUM_HARDERROR_PARAMETERS
);
68 * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters,
69 * but we might get called with less, so use a local buffer here.
71 for (i
= 0; i
< NumberOfParameters
; i
++)
74 BugCheckParameters
[i
] = Parameters
[i
];
78 KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR
,
80 (ULONG_PTR
)BugCheckParameters
,
83 return STATUS_SUCCESS
;
87 * @name ExpRaiseHardError
94 * @param NumberOfParameters
97 * @param UnicodeStringParameterMask
103 * @param ValidResponseOptions
116 ExpRaiseHardError(IN NTSTATUS ErrorStatus
,
117 IN ULONG NumberOfParameters
,
118 IN ULONG UnicodeStringParameterMask
,
119 IN PULONG_PTR Parameters
,
120 IN ULONG ValidResponseOptions
,
123 PEPROCESS Process
= PsGetCurrentProcess();
124 PETHREAD Thread
= PsGetCurrentThread();
125 UCHAR Buffer
[PORT_MAXIMUM_MESSAGE_LENGTH
];
126 PHARDERROR_MSG Message
= (PHARDERROR_MSG
)Buffer
;
129 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
132 /* Check if this error will shutdown the system */
133 if (ValidResponseOptions
== OptionShutdownSystem
)
135 /* Check for privilege */
136 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
139 return STATUS_PRIVILEGE_NOT_HELD
;
142 /* Don't handle any new hard errors */
143 ExReadyForErrors
= FALSE
;
146 /* Check if hard errors are not disabled */
147 if (!Thread
->HardErrorsAreDisabled
)
149 /* Check if we can't do errors anymore, and this is serious */
150 if ((!ExReadyForErrors
) && (NT_ERROR(ErrorStatus
)))
152 /* Use the system handler */
153 ExpSystemErrorHandler(ErrorStatus
,
155 UnicodeStringParameterMask
,
157 (PreviousMode
!= KernelMode
) ? TRUE
: FALSE
);
161 /* Check if we have an exception port */
162 if (Process
->ExceptionPort
)
164 /* Check if hard errors should be processed */
165 if (Process
->DefaultHardErrorProcessing
& 1)
168 PortHandle
= Process
->ExceptionPort
;
172 /* It's disabled, check if the error overrides it */
173 if (ErrorStatus
& 0x10000000)
175 /* Use the port anyway */
176 PortHandle
= Process
->ExceptionPort
;
187 /* Check if hard errors are enabled */
188 if (Process
->DefaultHardErrorProcessing
& 1)
190 /* Use our default system port */
191 PortHandle
= ExpDefaultErrorPort
;
195 /* It's disabled, check if the error overrides it */
196 if (ErrorStatus
& 0x10000000)
198 /* Use the port anyway */
199 PortHandle
= ExpDefaultErrorPort
;
209 /* If hard errors are disabled, do nothing */
210 if (Thread
->HardErrorsAreDisabled
) PortHandle
= NULL
;
212 /* Now check if we have a port */
215 /* Check if this is the default process */
216 if (Process
== ExpDefaultErrorPortProcess
)
218 /* We can't handle the error, check if this is critical */
219 if (NT_ERROR(ErrorStatus
))
221 /* It is, invoke the system handler */
222 ExpSystemErrorHandler(ErrorStatus
,
224 UnicodeStringParameterMask
,
226 (PreviousMode
!= KernelMode
) ? TRUE
: FALSE
);
228 /* If we survived, return to caller */
229 *Response
= ResponseReturnToCaller
;
230 return STATUS_SUCCESS
;
234 /* Setup the LPC Message */
235 Message
->h
.u1
.Length
= (sizeof(HARDERROR_MSG
) << 16) |
236 (sizeof(HARDERROR_MSG
) - sizeof(PORT_MESSAGE
));
237 Message
->h
.u2
.ZeroInit
= 0;
238 Message
->h
.u2
.s2
.Type
= LPC_ERROR_EVENT
;
239 Message
->Status
= ErrorStatus
&~ 0x10000000;
240 Message
->ValidResponseOptions
= ValidResponseOptions
;
241 Message
->UnicodeStringParameterMask
= UnicodeStringParameterMask
;
242 Message
->NumberOfParameters
= NumberOfParameters
;
243 KeQuerySystemTime(&Message
->ErrorTime
);
245 /* Copy the parameters */
246 if (Parameters
) RtlMoveMemory(&Message
->Parameters
,
248 sizeof(ULONG_PTR
) * NumberOfParameters
);
250 /* Send the LPC Message */
251 Status
= LpcRequestWaitReplyPort(PortHandle
,
254 if (NT_SUCCESS(Status
))
256 /* Check what kind of response we got */
257 if ((Message
->Response
!= ResponseReturnToCaller
) &&
258 (Message
->Response
!= ResponseNotHandled
) &&
259 (Message
->Response
!= ResponseAbort
) &&
260 (Message
->Response
!= ResponseCancel
) &&
261 (Message
->Response
!= ResponseIgnore
) &&
262 (Message
->Response
!= ResponseNo
) &&
263 (Message
->Response
!= ResponseOk
) &&
264 (Message
->Response
!= ResponseRetry
) &&
265 (Message
->Response
!= ResponseYes
) &&
266 (Message
->Response
!= ResponseTryAgain
) &&
267 (Message
->Response
!= ResponseContinue
))
269 /* Reset to a default one */
270 Message
->Response
= ResponseReturnToCaller
;
273 /* Set the response */
274 *Response
= Message
->Response
;
280 *Response
= ResponseReturnToCaller
;
281 Status
= STATUS_SUCCESS
;
289 * @name ExRaiseAccessViolation
292 * The ExRaiseAccessViolation routine can be used with structured exception
293 * handling to throw a driver-determined exception for a memory access
294 * violation that occurs when a driver processes I/O requests.
295 * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true
296 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
305 ExRaiseAccessViolation(VOID
)
307 /* Raise the Right Status */
308 RtlRaiseStatus(STATUS_ACCESS_VIOLATION
);
312 * @name ExRaiseDatatypeMisalignment
315 * ExRaiseDatatypeMisalignment raises an exception with the exception
316 * code set to STATUS_DATATYPE_MISALIGNMENT
318 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
327 ExRaiseDatatypeMisalignment(VOID
)
329 /* Raise the Right Status */
330 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT
);
334 * @name ExSystemExceptionFilter
337 * TODO: Add description
346 ExSystemExceptionFilter(VOID
)
348 return KeGetPreviousMode() != KernelMode
?
349 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
;
353 * @name ExRaiseHardError
356 * See NtRaiseHardError
361 * @param NumberOfParameters
362 * Number of optional parameters in Parameters array
364 * @param UnicodeStringParameterMask
365 * Optional string parameter (can be only one per error code)
368 * Array of ULONG parameters for use in error message string
370 * @param ValidResponseOptions
371 * See HARDERROR_RESPONSE_OPTION for possible values description
374 * Pointer to HARDERROR_RESPONSE enumeration
383 ExRaiseHardError(IN NTSTATUS ErrorStatus
,
384 IN ULONG NumberOfParameters
,
385 IN ULONG UnicodeStringParameterMask
,
386 IN PULONG_PTR Parameters
,
387 IN ULONG ValidResponseOptions
,
391 UNICODE_STRING CapturedParams
[MAXIMUM_HARDERROR_PARAMETERS
];
393 PULONG_PTR UserData
= NULL
, ParameterBase
;
394 PUNICODE_STRING StringBase
;
400 /* Check if we have parameters */
403 /* Check if we have strings */
404 if (UnicodeStringParameterMask
)
406 /* Add the maximum possible size */
407 Size
= (sizeof(ULONG_PTR
) + sizeof(UNICODE_STRING
)) *
408 MAXIMUM_HARDERROR_PARAMETERS
+ sizeof(UNICODE_STRING
);
410 /* Loop each parameter */
411 for (i
= 0; i
< NumberOfParameters
; i
++)
413 /* Check if it's part of the mask */
414 if (UnicodeStringParameterMask
& (1 << i
))
417 RtlMoveMemory(&CapturedParams
[i
],
419 sizeof(UNICODE_STRING
));
421 /* Increase the size */
422 Size
+= CapturedParams
[i
].MaximumLength
;
426 /* Allocate the user data region */
427 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
433 if (!NT_SUCCESS(Status
)) return Status
;
435 /* Set the pointers to our various data */
436 ParameterBase
= UserData
;
437 StringBase
= (PVOID
)((ULONG_PTR
)UserData
+
439 MAXIMUM_HARDERROR_PARAMETERS
);
440 BufferBase
= (PVOID
)((ULONG_PTR
)StringBase
+
441 sizeof(UNICODE_STRING
) *
442 MAXIMUM_HARDERROR_PARAMETERS
);
444 /* Loop parameters again */
445 for (i
= 0; i
< NumberOfParameters
; i
++)
447 /* Check if we're in the mask */
448 if (UnicodeStringParameterMask
& (1 << i
))
450 /* Update the base */
451 ParameterBase
[i
] = (ULONG_PTR
)&StringBase
[i
];
453 /* Copy the string buffer */
454 RtlMoveMemory(BufferBase
,
455 CapturedParams
[i
].Buffer
,
456 CapturedParams
[i
].MaximumLength
);
459 CapturedParams
[i
].Buffer
= BufferBase
;
461 /* Copy the string structure */
462 RtlMoveMemory(&StringBase
[i
],
464 sizeof(UNICODE_STRING
));
466 /* Update the pointer */
467 BufferBase
+= CapturedParams
[i
].MaximumLength
;
471 /* No need to copy any strings */
472 ParameterBase
[i
] = Parameters
[i
];
478 /* Just keep the data as is */
479 UserData
= Parameters
;
483 /* Now call the worker function */
484 Status
= ExpRaiseHardError(ErrorStatus
,
486 UnicodeStringParameterMask
,
488 ValidResponseOptions
,
491 /* Check if we had done user-mode allocation */
492 if ((UserData
) && (UserData
!= Parameters
))
494 /* We did! Delete it */
496 ZwFreeVirtualMemory(NtCurrentProcess(),
502 /* Return status and the response */
503 *Response
= SafeResponse
;
508 * @name NtRaiseHardError
511 * This function sends HARDERROR_MSG LPC message to listener
512 * (typically CSRSS.EXE). See NtSetDefaultHardErrorPort for more information
513 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html
518 * @param NumberOfParameters
519 * Number of optional parameters in Parameters array
521 * @param UnicodeStringParameterMask
522 * Optional string parameter (can be only one per error code)
525 * Array of ULONG_PTR parameters for use in error message string
527 * @param ValidResponseOptions
528 * See HARDERROR_RESPONSE_OPTION for possible values description
531 * Pointer to HARDERROR_RESPONSE enumeration
535 * @remarks NtRaiseHardError is easy way to display message in GUI
536 * without loading Win32 API libraries
541 NtRaiseHardError(IN NTSTATUS ErrorStatus
,
542 IN ULONG NumberOfParameters
,
543 IN ULONG UnicodeStringParameterMask
,
544 IN PULONG_PTR Parameters
,
545 IN ULONG ValidResponseOptions
,
548 NTSTATUS Status
= STATUS_SUCCESS
;
549 PULONG_PTR SafeParams
= NULL
;
551 UNICODE_STRING SafeString
;
554 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
556 /* Validate parameter count */
557 if (NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
560 return STATUS_INVALID_PARAMETER_2
;
563 /* Make sure we have some at least */
564 if ((Parameters
) && !(NumberOfParameters
))
567 return STATUS_INVALID_PARAMETER_2
;
570 /* Check if we were called from user-mode */
571 if (PreviousMode
!= KernelMode
)
573 /* First validate the responses */
574 switch (ValidResponseOptions
)
576 /* Check all valid cases */
577 case OptionAbortRetryIgnore
:
580 case OptionRetryCancel
:
582 case OptionYesNoCancel
:
583 case OptionShutdownSystem
:
586 /* Anything else is invalid */
588 return STATUS_INVALID_PARAMETER_4
;
591 /* Enter SEH Block */
594 /* Validate the response pointer */
595 ProbeForWriteUlong(Response
);
597 /* Check if we have parameters */
600 /* Validate the parameter pointers */
601 ParamSize
= sizeof(ULONG_PTR
) * NumberOfParameters
;
602 ProbeForRead(Parameters
, ParamSize
, sizeof(ULONG_PTR
));
604 /* Allocate a safe buffer */
605 SafeParams
= ExAllocatePoolWithTag(PagedPool
,
610 RtlCopyMemory(SafeParams
, Parameters
, ParamSize
);
612 /* Nowo check if there's strings in it */
613 if (UnicodeStringParameterMask
)
615 /* Loop every string */
616 for (i
= 0; i
< NumberOfParameters
; i
++)
618 /* Check if this parameter is a string */
619 if (UnicodeStringParameterMask
& (1 << i
))
621 /* Probe the structure */
622 ProbeForRead((PVOID
)SafeParams
[i
],
623 sizeof(UNICODE_STRING
),
627 RtlCopyMemory(&SafeString
,
628 (PVOID
)SafeParams
[i
],
629 sizeof(UNICODE_STRING
));
631 /* Probe the buffer */
632 ProbeForRead(SafeString
.Buffer
,
633 SafeString
.MaximumLength
,
640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
642 /* Free captured buffer */
643 if (SafeParams
) ExFreePool(SafeParams
);
645 /* Return the exception code */
646 _SEH2_YIELD(return _SEH2_GetExceptionCode());
650 /* Call the system function directly, because we probed */
651 ExpRaiseHardError(ErrorStatus
,
653 UnicodeStringParameterMask
,
655 ValidResponseOptions
,
661 SafeParams
= Parameters
;
664 * Call the Executive Function. It will probe and copy pointers to
667 ExRaiseHardError(ErrorStatus
,
669 UnicodeStringParameterMask
,
671 ValidResponseOptions
,
675 /* Check if we were called in user-mode */
676 if (PreviousMode
!= KernelMode
)
678 /* That means we have a buffer to free */
679 if (SafeParams
) ExFreePool(SafeParams
);
681 /* Enter SEH Block for return */
684 /* Return the response */
685 *Response
= SafeResponse
;
687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
689 /* Get the exception code */
690 Status
= _SEH2_GetExceptionCode();
696 /* Return the response */
697 *Response
= SafeResponse
;
705 * @name NtSetDefaultHardErrorPort
708 * NtSetDefaultHardErrorPort is typically called only once. After call,
709 * kernel set BOOLEAN flag named _ExReadyForErrors to TRUE, and all other
710 * tries to change default port are broken with STATUS_UNSUCCESSFUL error code
711 * See: http://www.windowsitlibrary.com/Content/356/08/2.html
712 * http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html
715 * Handle to named port object
719 * @remarks Privileges: SE_TCB_PRIVILEGE
724 NtSetDefaultHardErrorPort(IN HANDLE PortHandle
)
726 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
727 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
729 /* Check if we have the Privilege */
730 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
732 DPRINT1("NtSetDefaultHardErrorPort: Caller requires "
733 "the SeTcbPrivilege privilege!\n");
734 return STATUS_PRIVILEGE_NOT_HELD
;
737 /* Only called once during bootup, make sure we weren't called yet */
738 if (!ExReadyForErrors
)
740 /* Reference the port */
741 Status
= ObReferenceObjectByHandle(PortHandle
,
745 (PVOID
*)&ExpDefaultErrorPort
,
747 if (NT_SUCCESS(Status
))
750 ExpDefaultErrorPortProcess
= PsGetCurrentProcess();
751 ExReadyForErrors
= TRUE
;
755 /* Return status to caller */
763 /* Not supported in Kernel Mode */
764 RtlRaiseStatus(STATUS_NOT_IMPLEMENTED
);