Source code of Windows XP (NT5)
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.

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