Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

936 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. harderr.c
  5. Abstract:
  6. This module implements NT Hard Error APIs
  7. Author:
  8. Mark Lucovsky (markl) 04-Jul-1991
  9. Revision History:
  10. --*/
  11. #include "exp.h"
  12. NTSTATUS
  13. ExpRaiseHardError (
  14. IN NTSTATUS ErrorStatus,
  15. IN ULONG NumberOfParameters,
  16. IN ULONG UnicodeStringParameterMask,
  17. IN PULONG_PTR Parameters,
  18. IN ULONG ValidResponseOptions,
  19. OUT PULONG Response
  20. );
  21. VOID
  22. ExpSystemErrorHandler (
  23. IN NTSTATUS ErrorStatus,
  24. IN ULONG NumberOfParameters,
  25. IN ULONG UnicodeStringParameterMask,
  26. IN PULONG_PTR Parameters,
  27. IN BOOLEAN CallShutdown
  28. );
  29. #if defined(ALLOC_PRAGMA)
  30. #pragma alloc_text(PAGE, NtRaiseHardError)
  31. #pragma alloc_text(PAGE, NtSetDefaultHardErrorPort)
  32. #pragma alloc_text(PAGE, ExRaiseHardError)
  33. #pragma alloc_text(PAGE, ExpRaiseHardError)
  34. #pragma alloc_text(PAGELK, ExpSystemErrorHandler)
  35. #endif
  36. #define HARDERROR_MSG_OVERHEAD (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE))
  37. #define HARDERROR_API_MSG_LENGTH \
  38. sizeof(HARDERROR_MSG)<<16 | (HARDERROR_MSG_OVERHEAD)
  39. PEPROCESS ExpDefaultErrorPortProcess;
  40. #define STARTING 0
  41. #define STARTED 1
  42. #define SHUTDOWN 2
  43. BOOLEAN ExReadyForErrors = FALSE;
  44. ULONG HardErrorState = STARTING;
  45. BOOLEAN ExpTooLateForErrors = FALSE;
  46. HANDLE ExpDefaultErrorPort;
  47. extern PVOID PsSystemDllDllBase;
  48. #ifdef _X86_
  49. #pragma optimize("y", off) // RtlCaptureContext needs EBP to be correct
  50. #endif
  51. VOID
  52. ExpSystemErrorHandler (
  53. IN NTSTATUS ErrorStatus,
  54. IN ULONG NumberOfParameters,
  55. IN ULONG UnicodeStringParameterMask,
  56. IN PULONG_PTR Parameters,
  57. IN BOOLEAN CallShutdown
  58. )
  59. {
  60. ULONG Counter;
  61. ANSI_STRING AnsiString;
  62. NTSTATUS Status;
  63. ULONG_PTR ParameterVector[MAXIMUM_HARDERROR_PARAMETERS];
  64. CHAR DefaultFormatBuffer[32];
  65. CHAR ExpSystemErrorBuffer[256];
  66. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  67. PSZ ErrorCaption;
  68. CHAR const* ErrorFormatString;
  69. ANSI_STRING Astr;
  70. UNICODE_STRING Ustr;
  71. OEM_STRING Ostr;
  72. PSZ OemCaption;
  73. PSZ OemMessage;
  74. static char const* UnknownHardError = "Unknown Hard Error";
  75. CONTEXT ContextSave;
  76. PAGED_CODE();
  77. //
  78. // This handler is called whenever a hard error occurs before the
  79. // default handler has been installed.
  80. //
  81. // This is done regardless of whether or not the process has chosen
  82. // default hard error processing.
  83. //
  84. //
  85. // Capture the callers context as closely as possible into the debugger's
  86. // processor state area of the Prcb
  87. //
  88. // N.B. There may be some prologue code that shuffles registers such that
  89. // they get destroyed.
  90. //
  91. // This code is here only for crash dumps.
  92. //
  93. RtlCaptureContext (&KeGetCurrentPrcb()->ProcessorState.ContextFrame);
  94. KiSaveProcessorControlState (&KeGetCurrentPrcb()->ProcessorState);
  95. ContextSave = KeGetCurrentPrcb()->ProcessorState.ContextFrame;
  96. DefaultFormatBuffer[0] = '\0';
  97. RtlZeroMemory (ParameterVector, sizeof(ParameterVector));
  98. RtlCopyMemory (ParameterVector, Parameters, NumberOfParameters * sizeof (ULONG_PTR));
  99. for (Counter = 0; Counter < NumberOfParameters; Counter += 1) {
  100. if (UnicodeStringParameterMask & 1 << Counter) {
  101. strcat(DefaultFormatBuffer," %s");
  102. Status = RtlUnicodeStringToAnsiString (&AnsiString,
  103. (PUNICODE_STRING)Parameters[Counter],
  104. TRUE);
  105. if (NT_SUCCESS (Status)) {
  106. ParameterVector[Counter] = (ULONG_PTR)AnsiString.Buffer;
  107. } else {
  108. ParameterVector[Counter] = (ULONG_PTR)L"???";
  109. }
  110. }
  111. else {
  112. strcat(DefaultFormatBuffer," %x");
  113. }
  114. }
  115. strcat(DefaultFormatBuffer,"\n");
  116. ErrorFormatString = (char const *)DefaultFormatBuffer;
  117. ErrorCaption = (PSZ) UnknownHardError;
  118. //
  119. // HELP where do I get the resource from !
  120. //
  121. if (PsSystemDllDllBase != NULL) {
  122. try {
  123. //
  124. // If we are on a DBCS code page, we have to use ENGLISH resource
  125. // instead of default resource because HalDisplayString() can only
  126. // display ASCII characters on the blue screen.
  127. //
  128. Status = RtlFindMessage (PsSystemDllDllBase,
  129. 11,
  130. NlsMbCodePageTag ?
  131. MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US) :
  132. 0,
  133. ErrorStatus,
  134. &MessageEntry);
  135. if (!NT_SUCCESS(Status)) {
  136. ErrorCaption = (PSZ) UnknownHardError;
  137. ErrorFormatString = (char const *)UnknownHardError;
  138. }
  139. else {
  140. if (MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE) {
  141. //
  142. // Message resource is Unicode. Convert to ANSI.
  143. //
  144. RtlInitUnicodeString (&Ustr, (PCWSTR)MessageEntry->Text);
  145. Astr.Length = (USHORT) RtlUnicodeStringToAnsiSize (&Ustr);
  146. ErrorCaption = ExAllocatePoolWithTag (NonPagedPool,
  147. Astr.Length+16,
  148. ' rrE');
  149. if (ErrorCaption != NULL) {
  150. Astr.MaximumLength = Astr.Length + 16;
  151. Astr.Buffer = ErrorCaption;
  152. Status = RtlUnicodeStringToAnsiString(&Astr, &Ustr, FALSE);
  153. if (!NT_SUCCESS(Status)) {
  154. ExFreePool(ErrorCaption);
  155. ErrorCaption = (PSZ) UnknownHardError;
  156. ErrorFormatString = (char const *)UnknownHardError;
  157. }
  158. }
  159. else {
  160. ErrorCaption = (PSZ) UnknownHardError;
  161. ErrorFormatString = (char const *) UnknownHardError;
  162. }
  163. }
  164. else {
  165. ErrorCaption = ExAllocatePoolWithTag(NonPagedPool,
  166. strlen((PCHAR)MessageEntry->Text)+16,
  167. ' rrE');
  168. if (ErrorCaption != NULL) {
  169. strcpy(ErrorCaption,(PCHAR)MessageEntry->Text);
  170. }
  171. else {
  172. ErrorFormatString = (char const *)UnknownHardError;
  173. ErrorCaption = (PSZ) UnknownHardError;
  174. }
  175. }
  176. if (ErrorCaption != UnknownHardError) {
  177. //
  178. // It's assumed the Error String from the message table
  179. // is in the format:
  180. //
  181. // {ErrorCaption}\r\n\0ErrorFormatString\0.
  182. //
  183. // Parse out the caption.
  184. //
  185. ErrorFormatString = ErrorCaption;
  186. Counter = (ULONG) strlen(ErrorCaption);
  187. while (Counter && *ErrorFormatString >= ' ') {
  188. ErrorFormatString += 1;
  189. Counter -= 1;
  190. }
  191. *(char*)ErrorFormatString++ = '\0';
  192. Counter -= 1;
  193. while (Counter && *ErrorFormatString && *ErrorFormatString <= ' ') {
  194. ErrorFormatString += 1;
  195. Counter -= 1;
  196. }
  197. }
  198. if (!Counter) {
  199. // Oops - Bad Format String.
  200. ErrorFormatString = (char const *)"";
  201. }
  202. }
  203. }
  204. except (EXCEPTION_EXECUTE_HANDLER) {
  205. ErrorFormatString = (char const *)UnknownHardError;
  206. ErrorCaption = (PSZ) UnknownHardError;
  207. }
  208. }
  209. try {
  210. _snprintf (ExpSystemErrorBuffer,
  211. sizeof (ExpSystemErrorBuffer),
  212. "\nSTOP: %lx %s\n",
  213. ErrorStatus,
  214. ErrorCaption);
  215. }
  216. except(EXCEPTION_EXECUTE_HANDLER) {
  217. _snprintf (ExpSystemErrorBuffer,
  218. sizeof (ExpSystemErrorBuffer),
  219. "\nHardError %lx\n",
  220. ErrorStatus);
  221. }
  222. ASSERT(ExPageLockHandle);
  223. MmLockPagableSectionByHandle(ExPageLockHandle);
  224. //
  225. // Take the caption and convert it to OEM.
  226. //
  227. OemCaption = (PSZ) UnknownHardError;
  228. OemMessage = (PSZ) UnknownHardError;
  229. RtlInitAnsiString (&Astr, ExpSystemErrorBuffer);
  230. Status = RtlAnsiStringToUnicodeString (&Ustr, &Astr, TRUE);
  231. if (!NT_SUCCESS(Status)) {
  232. goto punt1;
  233. }
  234. //
  235. // Allocate the OEM string out of nonpaged pool so that bugcheck
  236. // can read it.
  237. //
  238. Ostr.Length = (USHORT)RtlUnicodeStringToOemSize(&Ustr);
  239. Ostr.MaximumLength = Ostr.Length;
  240. Ostr.Buffer = ExAllocatePoolWithTag(NonPagedPool, Ostr.Length, ' rrE');
  241. OemCaption = Ostr.Buffer;
  242. if (Ostr.Buffer != NULL) {
  243. Status = RtlUnicodeStringToOemString (&Ostr, &Ustr, FALSE);
  244. if (!NT_SUCCESS(Status)) {
  245. goto punt1;
  246. }
  247. }
  248. //
  249. // Can't do much of anything after calling HalDisplayString...
  250. //
  251. punt1:
  252. try {
  253. _snprintf (ExpSystemErrorBuffer, sizeof (ExpSystemErrorBuffer),
  254. (const char *)ErrorFormatString,
  255. ParameterVector[0],
  256. ParameterVector[1],
  257. ParameterVector[2],
  258. ParameterVector[3]);
  259. }
  260. except(EXCEPTION_EXECUTE_HANDLER) {
  261. _snprintf (ExpSystemErrorBuffer, sizeof (ExpSystemErrorBuffer),
  262. "Exception Processing Message %lx Parameters %lx %lx %lx %lx",
  263. ErrorStatus,
  264. ParameterVector[0],
  265. ParameterVector[1],
  266. ParameterVector[2],
  267. ParameterVector[3]);
  268. }
  269. RtlInitAnsiString (&Astr, ExpSystemErrorBuffer);
  270. Status = RtlAnsiStringToUnicodeString (&Ustr, &Astr, TRUE);
  271. if (!NT_SUCCESS(Status)) {
  272. goto punt2;
  273. }
  274. //
  275. // Allocate the OEM string out of nonpaged pool so that bugcheck
  276. // can read it.
  277. //
  278. Ostr.Length = (USHORT) RtlUnicodeStringToOemSize (&Ustr);
  279. Ostr.MaximumLength = Ostr.Length;
  280. Ostr.Buffer = ExAllocatePoolWithTag (NonPagedPool, Ostr.Length, ' rrE');
  281. OemMessage = Ostr.Buffer;
  282. if (Ostr.Buffer) {
  283. Status = RtlUnicodeStringToOemString (&Ostr, &Ustr, FALSE);
  284. if (!NT_SUCCESS(Status)) {
  285. goto punt2;
  286. }
  287. }
  288. punt2:
  289. ASSERT (sizeof(PVOID) == sizeof(ULONG_PTR));
  290. ASSERT (sizeof(ULONG) == sizeof(NTSTATUS));
  291. //
  292. // We don't come back from here.
  293. //
  294. if (CallShutdown) {
  295. PoShutdownBugCheck (TRUE,
  296. FATAL_UNHANDLED_HARD_ERROR,
  297. (ULONG)ErrorStatus,
  298. (ULONG_PTR)&(ParameterVector[0]),
  299. (ULONG_PTR)OemCaption,
  300. (ULONG_PTR)OemMessage);
  301. }
  302. else {
  303. KeBugCheckEx (FATAL_UNHANDLED_HARD_ERROR,
  304. (ULONG)ErrorStatus,
  305. (ULONG_PTR)&(ParameterVector[0]),
  306. (ULONG_PTR)OemCaption,
  307. (ULONG_PTR)OemMessage);
  308. }
  309. }
  310. #ifdef _X86_
  311. #pragma optimize("", on)
  312. #endif
  313. NTSTATUS
  314. ExpRaiseHardError (
  315. IN NTSTATUS ErrorStatus,
  316. IN ULONG NumberOfParameters,
  317. IN ULONG UnicodeStringParameterMask,
  318. IN PULONG_PTR Parameters,
  319. IN ULONG ValidResponseOptions,
  320. OUT PULONG Response
  321. )
  322. {
  323. PTEB Teb;
  324. PETHREAD Thread;
  325. PEPROCESS Process;
  326. ULONG_PTR MessageBuffer[PORT_MAXIMUM_MESSAGE_LENGTH/sizeof(ULONG_PTR)];
  327. PHARDERROR_MSG m;
  328. NTSTATUS Status;
  329. HANDLE ErrorPort;
  330. KPROCESSOR_MODE PreviousMode;
  331. BOOLEAN DoingShutdown;
  332. PAGED_CODE();
  333. m = (PHARDERROR_MSG)&MessageBuffer[0];
  334. PreviousMode = KeGetPreviousMode();
  335. DoingShutdown = FALSE;
  336. if (ValidResponseOptions == OptionShutdownSystem) {
  337. //
  338. // Check to see if the caller has the privilege to make this call.
  339. //
  340. if (!SeSinglePrivilegeCheck (SeShutdownPrivilege, PreviousMode)) {
  341. return STATUS_PRIVILEGE_NOT_HELD;
  342. }
  343. ExReadyForErrors = FALSE;
  344. HardErrorState = SHUTDOWN;
  345. DoingShutdown = TRUE;
  346. }
  347. Thread = PsGetCurrentThread();
  348. Process = PsGetCurrentProcess();
  349. //
  350. // If the default handler is not installed, then
  351. // call the fatal hard error handler if the error
  352. // status is error
  353. //
  354. // Let GDI override this since it does not want to crash the machine
  355. // when a bad driver was loaded via MmLoadSystemImage.
  356. //
  357. if ((Thread->CrossThreadFlags & PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) == 0) {
  358. if (NT_ERROR(ErrorStatus) && (HardErrorState == STARTING || DoingShutdown)) {
  359. ExpSystemErrorHandler (
  360. ErrorStatus,
  361. NumberOfParameters,
  362. UnicodeStringParameterMask,
  363. Parameters,
  364. (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE));
  365. }
  366. }
  367. //
  368. // If the process has an error port, then if it wants default
  369. // handling, use its port. If it disabled default handling, then
  370. // return the error to the caller. If the process does not
  371. // have a port, then use the registered default handler.
  372. //
  373. ErrorPort = NULL;
  374. if (Process->ExceptionPort) {
  375. if (Process->DefaultHardErrorProcessing & 1) {
  376. ErrorPort = Process->ExceptionPort;
  377. } else {
  378. //
  379. // If error processing is disabled, check the error override
  380. // status.
  381. //
  382. if (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE) {
  383. ErrorPort = Process->ExceptionPort;
  384. }
  385. }
  386. } else {
  387. if (Process->DefaultHardErrorProcessing & 1) {
  388. ErrorPort = ExpDefaultErrorPort;
  389. } else {
  390. //
  391. // If error processing is disabled, check the error override
  392. // status.
  393. //
  394. if (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE) {
  395. ErrorPort = ExpDefaultErrorPort;
  396. }
  397. }
  398. }
  399. if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) != 0) {
  400. ErrorPort = NULL;
  401. }
  402. if ((ErrorPort != NULL) && (!IS_SYSTEM_THREAD(Thread))) {
  403. Teb = (PTEB)PsGetCurrentThread()->Tcb.Teb;
  404. try {
  405. if (Teb->HardErrorMode & RTL_ERRORMODE_FAILCRITICALERRORS) {
  406. ErrorPort = NULL;
  407. }
  408. } except (EXCEPTION_EXECUTE_HANDLER) {
  409. ;
  410. }
  411. }
  412. if (ErrorPort == NULL) {
  413. *Response = (ULONG)ResponseReturnToCaller;
  414. return STATUS_SUCCESS;
  415. }
  416. if (Process == ExpDefaultErrorPortProcess) {
  417. if (NT_ERROR(ErrorStatus)) {
  418. ExpSystemErrorHandler (ErrorStatus,
  419. NumberOfParameters,
  420. UnicodeStringParameterMask,
  421. Parameters,
  422. (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE));
  423. }
  424. *Response = (ULONG)ResponseReturnToCaller;
  425. Status = STATUS_SUCCESS;
  426. return Status;
  427. }
  428. m->h.u1.Length = HARDERROR_API_MSG_LENGTH;
  429. m->h.u2.ZeroInit = LPC_ERROR_EVENT;
  430. m->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE;
  431. m->ValidResponseOptions = ValidResponseOptions;
  432. m->UnicodeStringParameterMask = UnicodeStringParameterMask;
  433. m->NumberOfParameters = NumberOfParameters;
  434. if (Parameters != NULL) {
  435. try {
  436. RtlCopyMemory (&m->Parameters,
  437. Parameters,
  438. sizeof(ULONG_PTR)*NumberOfParameters);
  439. } except (EXCEPTION_EXECUTE_HANDLER) {
  440. }
  441. }
  442. KeQuerySystemTime(&m->ErrorTime);
  443. Status = LpcRequestWaitReplyPortEx (ErrorPort,
  444. (PPORT_MESSAGE) m,
  445. (PPORT_MESSAGE) m);
  446. if (NT_SUCCESS(Status)) {
  447. switch (m->Response) {
  448. case ResponseReturnToCaller :
  449. case ResponseNotHandled :
  450. case ResponseAbort :
  451. case ResponseCancel :
  452. case ResponseIgnore :
  453. case ResponseNo :
  454. case ResponseOk :
  455. case ResponseRetry :
  456. case ResponseYes :
  457. case ResponseTryAgain :
  458. case ResponseContinue :
  459. break;
  460. default:
  461. m->Response = (ULONG)ResponseReturnToCaller;
  462. break;
  463. }
  464. *Response = m->Response;
  465. }
  466. return Status;
  467. }
  468. NTSTATUS
  469. NtRaiseHardError (
  470. IN NTSTATUS ErrorStatus,
  471. IN ULONG NumberOfParameters,
  472. IN ULONG UnicodeStringParameterMask,
  473. IN PULONG_PTR Parameters,
  474. IN ULONG ValidResponseOptions,
  475. OUT PULONG Response
  476. )
  477. {
  478. NTSTATUS Status;
  479. ULONG_PTR CapturedParameters[MAXIMUM_HARDERROR_PARAMETERS];
  480. KPROCESSOR_MODE PreviousMode;
  481. ULONG LocalResponse;
  482. UNICODE_STRING CapturedString;
  483. ULONG Counter;
  484. PAGED_CODE();
  485. if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS) {
  486. return STATUS_INVALID_PARAMETER_2;
  487. }
  488. if (ARGUMENT_PRESENT(Parameters) && NumberOfParameters == 0) {
  489. return STATUS_INVALID_PARAMETER_2;
  490. }
  491. PreviousMode = KeGetPreviousMode();
  492. if (PreviousMode != KernelMode) {
  493. switch (ValidResponseOptions) {
  494. case OptionAbortRetryIgnore :
  495. case OptionOk :
  496. case OptionOkCancel :
  497. case OptionRetryCancel :
  498. case OptionYesNo :
  499. case OptionYesNoCancel :
  500. case OptionShutdownSystem :
  501. case OptionOkNoWait :
  502. case OptionCancelTryContinue:
  503. break;
  504. default :
  505. return STATUS_INVALID_PARAMETER_4;
  506. }
  507. try {
  508. ProbeForWriteUlong(Response);
  509. if (ARGUMENT_PRESENT(Parameters)) {
  510. ProbeForRead (Parameters,
  511. sizeof(ULONG_PTR)*NumberOfParameters,
  512. sizeof(ULONG_PTR));
  513. RtlCopyMemory (CapturedParameters,
  514. Parameters,
  515. sizeof(ULONG_PTR)*NumberOfParameters);
  516. //
  517. // Probe all strings.
  518. //
  519. if (UnicodeStringParameterMask) {
  520. for (Counter = 0;Counter < NumberOfParameters; Counter += 1) {
  521. //
  522. // if there is a string in this position,
  523. // then probe and capture the string
  524. //
  525. if (UnicodeStringParameterMask & (1<<Counter)) {
  526. ProbeForReadSmallStructure ((PVOID)CapturedParameters[Counter],
  527. sizeof(UNICODE_STRING),
  528. sizeof(ULONG_PTR));
  529. RtlCopyMemory (&CapturedString,
  530. (PVOID)CapturedParameters[Counter],
  531. sizeof(UNICODE_STRING));
  532. //
  533. // Now probe the string
  534. //
  535. ProbeForRead (CapturedString.Buffer,
  536. CapturedString.MaximumLength,
  537. sizeof(UCHAR));
  538. }
  539. }
  540. }
  541. }
  542. }
  543. except(EXCEPTION_EXECUTE_HANDLER) {
  544. return GetExceptionCode();
  545. }
  546. if ((ErrorStatus == STATUS_SYSTEM_IMAGE_BAD_SIGNATURE) &&
  547. (KdDebuggerEnabled)) {
  548. if ((NumberOfParameters != 0) && (ARGUMENT_PRESENT(Parameters))) {
  549. DbgPrint("****************************************************************\n");
  550. DbgPrint("* The system detected a bad signature on file %wZ\n",(PUNICODE_STRING)CapturedParameters[0]);
  551. DbgPrint("****************************************************************\n");
  552. }
  553. return STATUS_SUCCESS;
  554. }
  555. //
  556. // Call ExpRaiseHardError. All parameters are probed and everything
  557. // should be user-mode.
  558. // ExRaiseHardError will squirt all strings into user-mode
  559. // without any probing
  560. //
  561. Status = ExpRaiseHardError (ErrorStatus,
  562. NumberOfParameters,
  563. UnicodeStringParameterMask,
  564. CapturedParameters,
  565. ValidResponseOptions,
  566. &LocalResponse);
  567. try {
  568. *Response = LocalResponse;
  569. }
  570. except (EXCEPTION_EXECUTE_HANDLER) {
  571. NOTHING;
  572. }
  573. }
  574. else {
  575. Status = ExRaiseHardError (ErrorStatus,
  576. NumberOfParameters,
  577. UnicodeStringParameterMask,
  578. Parameters,
  579. ValidResponseOptions,
  580. &LocalResponse);
  581. *Response = LocalResponse;
  582. }
  583. return Status;
  584. }
  585. NTSTATUS
  586. ExRaiseHardError (
  587. IN NTSTATUS ErrorStatus,
  588. IN ULONG NumberOfParameters,
  589. IN ULONG UnicodeStringParameterMask,
  590. IN PULONG_PTR Parameters,
  591. IN ULONG ValidResponseOptions,
  592. OUT PULONG Response
  593. )
  594. {
  595. NTSTATUS Status;
  596. PULONG_PTR ParameterBlock;
  597. PULONG_PTR UserModeParameterBase;
  598. PUNICODE_STRING UserModeStringsBase;
  599. PUCHAR UserModeStringDataBase;
  600. UNICODE_STRING CapturedStrings[MAXIMUM_HARDERROR_PARAMETERS];
  601. ULONG LocalResponse;
  602. ULONG Counter;
  603. SIZE_T UserModeSize;
  604. PAGED_CODE();
  605. //
  606. // If we are in the process of shutting down the system, do not allow
  607. // hard errors.
  608. //
  609. if (ExpTooLateForErrors) {
  610. *Response = ResponseNotHandled;
  611. return STATUS_SUCCESS;
  612. }
  613. ParameterBlock = NULL;
  614. //
  615. // If the parameters contain strings, we need to capture
  616. // the strings and the string descriptors and push them into
  617. // user-mode.
  618. //
  619. if (ARGUMENT_PRESENT(Parameters)) {
  620. if (UnicodeStringParameterMask) {
  621. //
  622. // We have strings - push them into usermode.
  623. //
  624. UserModeSize = (sizeof(ULONG_PTR)+sizeof(UNICODE_STRING))*MAXIMUM_HARDERROR_PARAMETERS;
  625. UserModeSize += sizeof(UNICODE_STRING);
  626. for (Counter = 0; Counter < NumberOfParameters; Counter += 1) {
  627. //
  628. // If there is a string in this position,
  629. // then probe and capture the string.
  630. //
  631. if (UnicodeStringParameterMask & 1<<Counter) {
  632. RtlCopyMemory (&CapturedStrings[Counter],
  633. (PVOID)Parameters[Counter],
  634. sizeof(UNICODE_STRING));
  635. UserModeSize += CapturedStrings[Counter].MaximumLength;
  636. }
  637. }
  638. //
  639. // Now we have the user-mode size all figured out.
  640. // Allocate some memory and point to it with the
  641. // parameter block. Then go through and copy all
  642. // of the parameters, string descriptors, and
  643. // string data into the memory.
  644. //
  645. Status = ZwAllocateVirtualMemory (NtCurrentProcess(),
  646. (PVOID *)&ParameterBlock,
  647. 0,
  648. &UserModeSize,
  649. MEM_COMMIT,
  650. PAGE_READWRITE);
  651. if (!NT_SUCCESS(Status)) {
  652. return Status;
  653. }
  654. UserModeParameterBase = ParameterBlock;
  655. UserModeStringsBase = (PUNICODE_STRING)((PUCHAR)ParameterBlock + sizeof(ULONG_PTR)*MAXIMUM_HARDERROR_PARAMETERS);
  656. UserModeStringDataBase = (PUCHAR)UserModeStringsBase + sizeof(UNICODE_STRING)*MAXIMUM_HARDERROR_PARAMETERS;
  657. try {
  658. for (Counter = 0; Counter < NumberOfParameters; Counter += 1) {
  659. //
  660. // Copy parameters to user-mode portion of the address space.
  661. //
  662. if (UnicodeStringParameterMask & 1<<Counter) {
  663. //
  664. // Fix the parameter to point at the string descriptor slot
  665. // in the user-mode buffer.
  666. //
  667. UserModeParameterBase[Counter] = (ULONG_PTR)&UserModeStringsBase[Counter];
  668. //
  669. // Copy the string data to user-mode.
  670. //
  671. RtlCopyMemory (UserModeStringDataBase,
  672. CapturedStrings[Counter].Buffer,
  673. CapturedStrings[Counter].MaximumLength);
  674. CapturedStrings[Counter].Buffer = (PWSTR)UserModeStringDataBase;
  675. //
  676. // Copy the string descriptor.
  677. //
  678. RtlCopyMemory (&UserModeStringsBase[Counter],
  679. &CapturedStrings[Counter],
  680. sizeof(UNICODE_STRING));
  681. //
  682. // Adjust the string data base.
  683. //
  684. UserModeStringDataBase += CapturedStrings[Counter].MaximumLength;
  685. }
  686. else {
  687. UserModeParameterBase[Counter] = Parameters[Counter];
  688. }
  689. }
  690. } except (EXCEPTION_EXECUTE_HANDLER) {
  691. }
  692. }
  693. else {
  694. ParameterBlock = Parameters;
  695. }
  696. }
  697. //
  698. // Call the hard error sender.
  699. //
  700. Status = ExpRaiseHardError (ErrorStatus,
  701. NumberOfParameters,
  702. UnicodeStringParameterMask,
  703. ParameterBlock,
  704. ValidResponseOptions,
  705. &LocalResponse);
  706. //
  707. // If the parameter block was allocated, it needs to be freed.
  708. //
  709. if (ParameterBlock && ParameterBlock != Parameters) {
  710. UserModeSize = 0;
  711. ZwFreeVirtualMemory (NtCurrentProcess(),
  712. (PVOID *)&ParameterBlock,
  713. &UserModeSize,
  714. MEM_RELEASE);
  715. }
  716. *Response = LocalResponse;
  717. return Status;
  718. }
  719. NTSTATUS
  720. NtSetDefaultHardErrorPort (
  721. IN HANDLE DefaultHardErrorPort
  722. )
  723. {
  724. NTSTATUS Status;
  725. PAGED_CODE();
  726. if (!SeSinglePrivilegeCheck(SeTcbPrivilege, KeGetPreviousMode())) {
  727. return STATUS_PRIVILEGE_NOT_HELD;
  728. }
  729. if (HardErrorState == STARTED) {
  730. return STATUS_UNSUCCESSFUL;
  731. }
  732. Status = ObReferenceObjectByHandle (DefaultHardErrorPort,
  733. 0,
  734. LpcPortObjectType,
  735. KeGetPreviousMode(),
  736. (PVOID *)&ExpDefaultErrorPort,
  737. NULL);
  738. if (!NT_SUCCESS(Status)) {
  739. return Status;
  740. }
  741. ExReadyForErrors = TRUE;
  742. HardErrorState = STARTED;
  743. ExpDefaultErrorPortProcess = PsGetCurrentProcess();
  744. ObReferenceObject (ExpDefaultErrorPortProcess);
  745. return STATUS_SUCCESS;
  746. }
  747. VOID
  748. __cdecl
  749. _purecall()
  750. {
  751. ASSERTMSG("_purecall() was called", FALSE);
  752. ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
  753. }