1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/harderr.c
5 * PURPOSE: Error Functions and Status/Exception Dispatching/Raising
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ******************************************************************/
16
17 BOOLEAN ExReadyForErrors = FALSE;
18 PVOID ExpDefaultErrorPort = NULL;
19 PEPROCESS ExpDefaultErrorPortProcess = NULL;
20
21 /* FUNCTIONS ****************************************************************/
22
23 /*++
24 * @name ExpSystemErrorHandler
25 *
26 * For now it's a stub
27 *
28 * @param ErrorStatus
29 * FILLME
30 *
31 * @param NumberOfParameters
32 * FILLME
33 *
34 * @param UnicodeStringParameterMask
35 * FILLME
36 *
37 * @param Parameters
38 * FILLME
39 *
40 * @param ValidResponseOptions
41 * FILLME
42 *
43 * @param Response
44 * FILLME
45 *
46 * @return None
47 *
48 * @remarks None
49 *
50 *--*/
51 NTSTATUS
52 NTAPI
ExpSystemErrorHandler(IN NTSTATUS ErrorStatus,IN ULONG NumberOfParameters,IN ULONG UnicodeStringParameterMask,IN PULONG_PTR Parameters,IN BOOLEAN Shutdown)53 ExpSystemErrorHandler(IN NTSTATUS ErrorStatus,
54 IN ULONG NumberOfParameters,
55 IN ULONG UnicodeStringParameterMask,
56 IN PULONG_PTR Parameters,
57 IN BOOLEAN Shutdown)
58 {
59 ULONG_PTR BugCheckParameters[MAXIMUM_HARDERROR_PARAMETERS] = {0, 0, 0, 0};
60 ULONG i;
61
62 /* Sanity check */
63 ASSERT(NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
64
65 /*
66 * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters,
67 * but we might get called with less, so use a local buffer here.
68 */
69 for (i = 0; i < NumberOfParameters; i++)
70 {
71 /* Copy them over */
72 BugCheckParameters[i] = Parameters[i];
73 }
74
75 /* FIXME: STUB */
76 KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR,
77 ErrorStatus,
78 (ULONG_PTR)BugCheckParameters,
79 0,
80 0);
81 return STATUS_SUCCESS;
82 }
83
84 /*++
85 * @name ExpRaiseHardError
86 * @implemented
87 *
88 * See ExRaiseHardError and NtRaiseHardError, same parameters.
89 *
90 * This function performs the central work for both ExRaiseHardError
91 * and NtRaiseHardError. ExRaiseHardError is the service for kernel-mode
92 * that copies the parameters to user-mode, and NtRaiseHardError is the
93 * service for both kernel-mode and user-mode that performs parameters
94 * validation and capture if necessary.
95 *
96 *--*/
97 NTSTATUS
98 NTAPI
ExpRaiseHardError(IN NTSTATUS ErrorStatus,IN ULONG NumberOfParameters,IN ULONG UnicodeStringParameterMask,IN PULONG_PTR Parameters,IN ULONG ValidResponseOptions,OUT PULONG Response)99 ExpRaiseHardError(IN NTSTATUS ErrorStatus,
100 IN ULONG NumberOfParameters,
101 IN ULONG UnicodeStringParameterMask,
102 IN PULONG_PTR Parameters,
103 IN ULONG ValidResponseOptions,
104 OUT PULONG Response)
105 {
106 NTSTATUS Status;
107 PEPROCESS Process = PsGetCurrentProcess();
108 PETHREAD Thread = PsGetCurrentThread();
109 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH];
110 PHARDERROR_MSG Message = (PHARDERROR_MSG)Buffer;
111 HANDLE PortHandle;
112 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
113
114 PAGED_CODE();
115
116 /* Check if this error will shutdown the system */
117 if (ValidResponseOptions == OptionShutdownSystem)
118 {
119 /*
120 * Check if we have the privileges.
121 *
122 * NOTE: In addition to the Shutdown privilege we also check whether
123 * the caller has the Tcb privilege. The purpose is to allow only
124 * SYSTEM processes to "shutdown" the system on hard errors (BSOD)
125 * while forbidding regular processes to do so. This behaviour differs
126 * from Windows, where any user-mode process, as soon as it has the
127 * Shutdown privilege, can trigger a hard-error BSOD.
128 */
129 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode) ||
130 !SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
131 {
132 /* No rights */
133 *Response = ResponseNotHandled;
134 return STATUS_PRIVILEGE_NOT_HELD;
135 }
136
137 /* Don't handle any new hard errors */
138 ExReadyForErrors = FALSE;
139 }
140
141 /* Check if hard errors are not disabled */
142 if (!Thread->HardErrorsAreDisabled)
143 {
144 /* Check if we can't do errors anymore, and this is serious */
145 if (!ExReadyForErrors && NT_ERROR(ErrorStatus))
146 {
147 /* Use the system handler */
148 ExpSystemErrorHandler(ErrorStatus,
149 NumberOfParameters,
150 UnicodeStringParameterMask,
151 Parameters,
152 (PreviousMode != KernelMode) ? TRUE : FALSE);
153 }
154 }
155
156 /*
157 * Enable hard error processing if it is enabled for the process
158 * or if the exception status forces it.
159 */
160 if ((Process->DefaultHardErrorProcessing & SEM_FAILCRITICALERRORS) ||
161 (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE))
162 {
163 /* Check if we have an exception port */
164 if (Process->ExceptionPort)
165 {
166 /* Use the port */
167 PortHandle = Process->ExceptionPort;
168 }
169 else
170 {
171 /* Use our default system port */
172 PortHandle = ExpDefaultErrorPort;
173 }
174 }
175 else
176 {
177 /* Don't process the error */
178 PortHandle = NULL;
179 }
180
181 /* If hard errors are disabled, do nothing */
182 if (Thread->HardErrorsAreDisabled) PortHandle = NULL;
183
184 /*
185 * If this is not the system thread, check whether hard errors are
186 * disabled for this thread on user-mode side, and if so, do nothing.
187 */
188 if (!Thread->SystemThread && (PortHandle != NULL))
189 {
190 /* Check if we have a TEB */
191 PTEB Teb = PsGetCurrentThread()->Tcb.Teb;
192 if (Teb)
193 {
194 _SEH2_TRY
195 {
196 if (Teb->HardErrorMode & RTL_SEM_FAILCRITICALERRORS)
197 {
198 PortHandle = NULL;
199 }
200 }
201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
202 {
203 NOTHING;
204 }
205 _SEH2_END;
206 }
207 }
208
209 /* Now check if we have a port */
210 if (PortHandle == NULL)
211 {
212 /* Just return to caller */
213 *Response = ResponseReturnToCaller;
214 return STATUS_SUCCESS;
215 }
216
217 /* Check if this is the default process */
218 if (Process == ExpDefaultErrorPortProcess)
219 {
220 /* We can't handle the error, check if this is critical */
221 if (NT_ERROR(ErrorStatus))
222 {
223 /* It is, invoke the system handler */
224 ExpSystemErrorHandler(ErrorStatus,
225 NumberOfParameters,
226 UnicodeStringParameterMask,
227 Parameters,
228 (PreviousMode != KernelMode) ? TRUE : FALSE);
229
230 /* If we survived, return to caller */
231 *Response = ResponseReturnToCaller;
232 return STATUS_SUCCESS;
233 }
234 }
235
236 /* Setup the LPC Message */
237 Message->h.u1.Length = (sizeof(HARDERROR_MSG) << 16) |
238 (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE));
239 Message->h.u2.ZeroInit = 0;
240 Message->h.u2.s2.Type = LPC_ERROR_EVENT;
241 Message->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE;
242 Message->ValidResponseOptions = ValidResponseOptions;
243 Message->UnicodeStringParameterMask = UnicodeStringParameterMask;
244 Message->NumberOfParameters = NumberOfParameters;
245 KeQuerySystemTime(&Message->ErrorTime);
246
247 /* Copy the parameters */
248 if (Parameters)
249 {
250 RtlMoveMemory(&Message->Parameters,
251 Parameters,
252 sizeof(ULONG_PTR) * NumberOfParameters);
253 }
254
255 /* Send the LPC Message */
256 Status = LpcRequestWaitReplyPort(PortHandle,
257 (PPORT_MESSAGE)Message,
258 (PPORT_MESSAGE)Message);
259 if (NT_SUCCESS(Status))
260 {
261 /* Check what kind of response we got */
262 if ((Message->Response != ResponseReturnToCaller) &&
263 (Message->Response != ResponseNotHandled) &&
264 (Message->Response != ResponseAbort) &&
265 (Message->Response != ResponseCancel) &&
266 (Message->Response != ResponseIgnore) &&
267 (Message->Response != ResponseNo) &&
268 (Message->Response != ResponseOk) &&
269 (Message->Response != ResponseRetry) &&
270 (Message->Response != ResponseYes) &&
271 (Message->Response != ResponseTryAgain) &&
272 (Message->Response != ResponseContinue))
273 {
274 /* Reset to a default one */
275 Message->Response = ResponseReturnToCaller;
276 }
277
278 /* Set the response */
279 *Response = Message->Response;
280 }
281 else
282 {
283 /* Set the response */
284 *Response = ResponseReturnToCaller;
285 }
286
287 /* Return status */
288 return Status;
289 }
290
291 /*++
292 * @name ExRaiseAccessViolation
293 * @implemented
294 *
295 * The ExRaiseAccessViolation routine can be used with structured exception
296 * handling to throw a driver-determined exception for a memory access
297 * violation that occurs when a driver processes I/O requests.
298 * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true
299 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
300 *
301 * @return None
302 *
303 * @remarks None
304 *
305 *--*/
306 VOID
307 NTAPI
ExRaiseAccessViolation(VOID)308 ExRaiseAccessViolation(VOID)
309 {
310 /* Raise the Right Status */
311 RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
312 }
313
314 /*++
315 * @name ExRaiseDatatypeMisalignment
316 * @implemented
317 *
318 * ExRaiseDatatypeMisalignment raises an exception with the exception
319 * code set to STATUS_DATATYPE_MISALIGNMENT
320 * See: MSDN / DDK
321 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm
322 *
323 * @return None
324 *
325 * @remarks None
326 *
327 *--*/
328 VOID
329 NTAPI
ExRaiseDatatypeMisalignment(VOID)330 ExRaiseDatatypeMisalignment(VOID)
331 {
332 /* Raise the Right Status */
333 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
334 }
335
336 /*++
337 * @name ExSystemExceptionFilter
338 * @implemented
339 *
340 * TODO: Add description
341 *
342 * @return FILLME
343 *
344 * @remarks None
345 *
346 *--*/
347 LONG
348 NTAPI
ExSystemExceptionFilter(VOID)349 ExSystemExceptionFilter(VOID)
350 {
351 return KeGetPreviousMode() != KernelMode ?
352 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
353 }
354
355 /*++
356 * @name ExRaiseHardError
357 * @implemented
358 *
359 * See NtRaiseHardError and ExpRaiseHardError.
360 *
361 * @param ErrorStatus
362 * Error Code
363 *
364 * @param NumberOfParameters
365 * Number of optional parameters in Parameters array
366 *
367 * @param UnicodeStringParameterMask
368 * Optional string parameter (can be only one per error code)
369 *
370 * @param Parameters
371 * Array of ULONG parameters for use in error message string
372 *
373 * @param ValidResponseOptions
374 * See HARDERROR_RESPONSE_OPTION for possible values description
375 *
376 * @param Response
377 * Pointer to HARDERROR_RESPONSE enumeration
378 *
379 * @return Status
380 *
381 *--*/
382 NTSTATUS
383 NTAPI
ExRaiseHardError(IN NTSTATUS ErrorStatus,IN ULONG NumberOfParameters,IN ULONG UnicodeStringParameterMask,IN PULONG_PTR Parameters,IN ULONG ValidResponseOptions,OUT PULONG Response)384 ExRaiseHardError(IN NTSTATUS ErrorStatus,
385 IN ULONG NumberOfParameters,
386 IN ULONG UnicodeStringParameterMask,
387 IN PULONG_PTR Parameters,
388 IN ULONG ValidResponseOptions,
389 OUT PULONG Response)
390 {
391 NTSTATUS Status;
392 SIZE_T Size;
393 UNICODE_STRING CapturedParams[MAXIMUM_HARDERROR_PARAMETERS];
394 ULONG i;
395 PVOID UserData = NULL;
396 PHARDERROR_USER_PARAMETERS UserParams;
397 PWSTR BufferBase;
398 ULONG SafeResponse = ResponseNotHandled;
399
400 PAGED_CODE();
401
402 /* Check if we have parameters */
403 if (Parameters)
404 {
405 /* Check if we have strings */
406 if (UnicodeStringParameterMask)
407 {
408 /* Calculate the required size */
409 Size = FIELD_OFFSET(HARDERROR_USER_PARAMETERS, Buffer[0]);
410
411 /* Loop each parameter */
412 for (i = 0; i < NumberOfParameters; i++)
413 {
414 /* Check if it's part of the mask */
415 if (UnicodeStringParameterMask & (1 << i))
416 {
417 /* Copy it */
418 RtlMoveMemory(&CapturedParams[i],
419 (PVOID)Parameters[i],
420 sizeof(UNICODE_STRING));
421
422 /* Increase the size */
423 Size += CapturedParams[i].MaximumLength;
424 }
425 }
426
427 /* Allocate the user data region */
428 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
429 &UserData,
430 0,
431 &Size,
432 MEM_COMMIT,
433 PAGE_READWRITE);
434 if (!NT_SUCCESS(Status))
435 {
436 /* Return failure */
437 *Response = ResponseNotHandled;
438 return Status;
439 }
440
441 /* Set the pointers to our data */
442 UserParams = UserData;
443 BufferBase = UserParams->Buffer;
444
445 /* Enter SEH block as we are writing to user-mode space */
446 _SEH2_TRY
447 {
448 /* Loop parameters again */
449 for (i = 0; i < NumberOfParameters; i++)
450 {
451 /* Check if we are in the mask */
452 if (UnicodeStringParameterMask & (1 << i))
453 {
454 /* Update the base */
455 UserParams->Parameters[i] = (ULONG_PTR)&UserParams->Strings[i];
456
457 /* Copy the string buffer */
458 RtlMoveMemory(BufferBase,
459 CapturedParams[i].Buffer,
460 CapturedParams[i].MaximumLength);
461
462 /* Set buffer */
463 CapturedParams[i].Buffer = BufferBase;
464
465 /* Copy the string structure */
466 UserParams->Strings[i] = CapturedParams[i];
467
468 /* Update the pointer */
469 BufferBase += CapturedParams[i].MaximumLength;
470 }
471 else
472 {
473 /* No need to copy any strings */
474 UserParams->Parameters[i] = Parameters[i];
475 }
476 }
477 }
478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
479 {
480 /* Return the exception code */
481 Status = _SEH2_GetExceptionCode();
482 DPRINT1("ExRaiseHardError - Exception when writing data to user-mode, Status 0x%08lx\n", Status);
483 }
484 _SEH2_END;
485 }
486 else
487 {
488 /* Just keep the data as is */
489 UserData = Parameters;
490 }
491 }
492
493 /* Now call the worker function */
494 Status = ExpRaiseHardError(ErrorStatus,
495 NumberOfParameters,
496 UnicodeStringParameterMask,
497 UserData,
498 ValidResponseOptions,
499 &SafeResponse);
500
501 /* Check if we had done user-mode allocation */
502 if ((UserData) && (UserData != Parameters))
503 {
504 /* We did! Delete it */
505 Size = 0;
506 ZwFreeVirtualMemory(NtCurrentProcess(),
507 &UserData,
508 &Size,
509 MEM_RELEASE);
510 }
511
512 /* Return status and the response */
513 *Response = SafeResponse;
514 return Status;
515 }
516
517 /*++
518 * @name NtRaiseHardError
519 * @implemented
520 *
521 * This function sends HARDERROR_MSG LPC message to a hard-error listener,
522 * typically CSRSS.EXE. See NtSetDefaultHardErrorPort for more information.
523 * See also: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html
524 *
525 * @param ErrorStatus
526 * Error Code
527 *
528 * @param NumberOfParameters
529 * Number of optional parameters in Parameters array
530 *
531 * @param UnicodeStringParameterMask
532 * Optional string parameter (can be only one per error code)
533 *
534 * @param Parameters
535 * Array of ULONG_PTR parameters for use in error message string
536 *
537 * @param ValidResponseOptions
538 * See HARDERROR_RESPONSE_OPTION for possible values description
539 *
540 * @param Response
541 * Pointer to HARDERROR_RESPONSE enumeration
542 *
543 * @return Status
544 *
545 * @remarks NtRaiseHardError constitutes an easy way to display messages
546 * in GUI without loading any Win32 API libraries.
547 *
548 *--*/
549 NTSTATUS
550 NTAPI
NtRaiseHardError(IN NTSTATUS ErrorStatus,IN ULONG NumberOfParameters,IN ULONG UnicodeStringParameterMask,IN PULONG_PTR Parameters,IN ULONG ValidResponseOptions,OUT PULONG Response)551 NtRaiseHardError(IN NTSTATUS ErrorStatus,
552 IN ULONG NumberOfParameters,
553 IN ULONG UnicodeStringParameterMask,
554 IN PULONG_PTR Parameters,
555 IN ULONG ValidResponseOptions,
556 OUT PULONG Response)
557 {
558 NTSTATUS Status = STATUS_SUCCESS;
559 PULONG_PTR SafeParams = NULL;
560 ULONG SafeResponse = ResponseNotHandled;
561 UNICODE_STRING SafeString;
562 ULONG i;
563 ULONG ParamSize = 0;
564 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
565
566 PAGED_CODE();
567
568 /* Validate parameter count */
569 if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS)
570 {
571 /* Fail */
572 return STATUS_INVALID_PARAMETER_2;
573 }
574
575 /* Make sure we have some at least */
576 if ((Parameters != NULL) && (NumberOfParameters == 0))
577 {
578 /* Fail */
579 return STATUS_INVALID_PARAMETER_2;
580 }
581
582 /* Check if we were called from user-mode */
583 if (PreviousMode != KernelMode)
584 {
585 /* First validate the responses */
586 switch (ValidResponseOptions)
587 {
588 /* Check all valid cases */
589 case OptionAbortRetryIgnore:
590 case OptionOk:
591 case OptionOkCancel:
592 case OptionRetryCancel:
593 case OptionYesNo:
594 case OptionYesNoCancel:
595 case OptionShutdownSystem:
596 case OptionOkNoWait:
597 case OptionCancelTryContinue:
598 break;
599
600 /* Anything else is invalid */
601 default:
602 return STATUS_INVALID_PARAMETER_4;
603 }
604
605 /* Check if we have parameters */
606 if (Parameters)
607 {
608 /* Calculate size of the parameters */
609 ParamSize = sizeof(ULONG_PTR) * NumberOfParameters;
610
611 /* Allocate a safe buffer */
612 SafeParams = ExAllocatePoolWithTag(PagedPool, ParamSize, TAG_ERR);
613 if (!SafeParams)
614 {
615 return STATUS_INSUFFICIENT_RESOURCES;
616 }
617 }
618
619 /* Enter SEH Block */
620 _SEH2_TRY
621 {
622 /* Validate the response pointer */
623 ProbeForWriteUlong(Response);
624
625 /* Check if we have parameters */
626 if (Parameters)
627 {
628 /* Validate the parameter pointers */
629 ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR));
630
631 /* Copy them */
632 RtlCopyMemory(SafeParams, Parameters, ParamSize);
633
634 /* Now check if there's strings in it */
635 if (UnicodeStringParameterMask)
636 {
637 /* Loop every string */
638 for (i = 0; i < NumberOfParameters; i++)
639 {
640 /* Check if this parameter is a string */
641 if (UnicodeStringParameterMask & (1 << i))
642 {
643 /* Probe the structure */
644 ProbeForRead((PVOID)SafeParams[i],
645 sizeof(UNICODE_STRING),
646 sizeof(ULONG_PTR));
647
648 /* Capture it */
649 RtlCopyMemory(&SafeString,
650 (PVOID)SafeParams[i],
651 sizeof(UNICODE_STRING));
652
653 /* Probe the buffer */
654 ProbeForRead(SafeString.Buffer,
655 SafeString.MaximumLength,
656 sizeof(UCHAR));
657 }
658 }
659 }
660 }
661 }
662 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
663 {
664 /* Free captured buffer */
665 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
666
667 /* Return the exception code */
668 _SEH2_YIELD(return _SEH2_GetExceptionCode());
669 }
670 _SEH2_END;
671
672 /* Call the system function directly, because we probed */
673 Status = ExpRaiseHardError(ErrorStatus,
674 NumberOfParameters,
675 UnicodeStringParameterMask,
676 SafeParams,
677 ValidResponseOptions,
678 &SafeResponse);
679
680 /* Free captured buffer */
681 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR);
682
683 /* Enter SEH Block to return the response */
684 _SEH2_TRY
685 {
686 /* Return the response */
687 *Response = SafeResponse;
688 }
689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
690 {
691 /* Get the exception code */
692 Status = _SEH2_GetExceptionCode();
693 }
694 _SEH2_END;
695 }
696 else
697 {
698 /* Reuse variable */
699 SafeParams = Parameters;
700
701 /*
702 * Call the Executive Function. It will probe
703 * and copy pointers to user-mode.
704 */
705 Status = ExRaiseHardError(ErrorStatus,
706 NumberOfParameters,
707 UnicodeStringParameterMask,
708 SafeParams,
709 ValidResponseOptions,
710 &SafeResponse);
711
712 /* Return the response */
713 *Response = SafeResponse;
714 }
715
716 /* Return status */
717 return Status;
718 }
719
720 /*++
721 * @name NtSetDefaultHardErrorPort
722 * @implemented
723 *
724 * NtSetDefaultHardErrorPort is typically called only once. After the call,
725 * the kernel sets a BOOLEAN flag named ExReadyForErrors to TRUE, and all other
726 * attempts to change the default port fail with STATUS_UNSUCCESSFUL error code.
727 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html
728 * https://web.archive.org/web/20070716133753/http://www.windowsitlibrary.com/Content/356/08/2.html
729 *
730 * @param PortHandle
731 * Handle to named port object
732 *
733 * @return Status
734 *
735 * @remarks Privileges: SE_TCB_PRIVILEGE
736 *
737 *--*/
738 NTSTATUS
739 NTAPI
NtSetDefaultHardErrorPort(IN HANDLE PortHandle)740 NtSetDefaultHardErrorPort(IN HANDLE PortHandle)
741 {
742 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
743 NTSTATUS Status = STATUS_UNSUCCESSFUL;
744
745 PAGED_CODE();
746
747 /* Check if we have the privileges */
748 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
749 {
750 DPRINT1("NtSetDefaultHardErrorPort: Caller requires "
751 "the SeTcbPrivilege privilege!\n");
752 return STATUS_PRIVILEGE_NOT_HELD;
753 }
754
755 /* Only called once during bootup, make sure we weren't called yet */
756 if (!ExReadyForErrors)
757 {
758 /* Reference the hard-error port */
759 Status = ObReferenceObjectByHandle(PortHandle,
760 0,
761 LpcPortObjectType,
762 PreviousMode,
763 (PVOID*)&ExpDefaultErrorPort,
764 NULL);
765 if (NT_SUCCESS(Status))
766 {
767 /* Keep also a reference to the process handling the hard errors */
768 ExpDefaultErrorPortProcess = PsGetCurrentProcess();
769 ObReferenceObject(ExpDefaultErrorPortProcess);
770 ExReadyForErrors = TRUE;
771 Status = STATUS_SUCCESS;
772 }
773 }
774
775 /* Return status to caller */
776 return Status;
777 }
778
779 VOID
780 __cdecl
_purecall(VOID)781 _purecall(VOID)
782 {
783 /* Not supported in Kernel Mode */
784 RtlRaiseStatus(STATUS_NOT_IMPLEMENTED);
785 }
786
787 /* EOF */
788