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.

728 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. triage.c
  5. Abstract:
  6. This module contains the Phase 0 code to triage bugchecks and
  7. automatically enable various system tracing components until the
  8. guilty party is found.
  9. Author:
  10. Landy Wang 13-Jan-1999
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #include "ntiodump.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT,MiTriageSystem)
  17. #pragma alloc_text(INIT,MiTriageAddDrivers)
  18. #endif
  19. //
  20. // Always update this macro when adding triage support for additional bugchecks.
  21. //
  22. #define MI_CAN_TRIAGE_BUGCHECK(BugCheckCode) \
  23. ((BugCheckCode) == NO_MORE_SYSTEM_PTES || \
  24. (BugCheckCode) == BAD_POOL_HEADER || \
  25. (BugCheckCode) == DRIVER_CORRUPTED_SYSPTES || \
  26. (BugCheckCode) == DRIVER_CORRUPTED_EXPOOL || \
  27. (BugCheckCode) == DRIVER_CORRUPTED_MMPOOL)
  28. //
  29. // These are bugchecks that were presumably triggered by either autotriage or
  30. // the admin's registry settings - so don't apply any new rules and in addition,
  31. // keep the old ones unaltered so it can reproduce.
  32. //
  33. #define MI_HOLD_TRIAGE_BUGCHECK(BugCheckCode) \
  34. ((BugCheckCode) == DRIVER_USED_EXCESSIVE_PTES || \
  35. (BugCheckCode) == DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS || \
  36. (BugCheckCode) == PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
  37. (BugCheckCode) == DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
  38. (BugCheckCode) == PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
  39. (BugCheckCode) == DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
  40. (BugCheckCode) == DRIVER_CAUGHT_MODIFYING_FREED_POOL || \
  41. (BugCheckCode) == SYSTEM_PTE_MISUSE)
  42. #define MI_TRACKING_PTES 0x00000002
  43. #define MI_PROTECT_FREED_NONPAGED_POOL 0x00000004
  44. #define MI_VERIFYING_PRENT5_DRIVERS 0x00000008
  45. #define MI_KEEPING_PREVIOUS_SETTINGS 0x00000010
  46. #ifdef ALLOC_DATA_PRAGMA
  47. #pragma const_seg("INITCONST")
  48. #pragma data_seg("INITDATA")
  49. #endif
  50. const PCHAR MiTriageActionStrings[] = {
  51. "Locked pages tracking",
  52. "System PTE usage tracking",
  53. "Making accesses to freed nonpaged pool cause bugchecks",
  54. "Driver Verifying Pre-Windows 2000 built drivers",
  55. "Keeping previous autotriage settings"
  56. };
  57. #if DBG
  58. ULONG MiTriageDebug = 0;
  59. BOOLEAN MiTriageRegardless = FALSE;
  60. #endif
  61. #ifdef ALLOC_DATA_PRAGMA
  62. #pragma const_seg()
  63. #pragma data_seg()
  64. #endif
  65. //
  66. // N.B. The debugger references this.
  67. //
  68. ULONG MmTriageActionTaken;
  69. //
  70. // The Version number must be incremented whenever the MI_TRIAGE_STORAGE
  71. // structure is changed. This enables usermode programs to decode the Mm
  72. // portions of triage dumps regardless of which kernel revision created the
  73. // dump.
  74. //
  75. typedef struct _MI_TRIAGE_STORAGE {
  76. ULONG Version;
  77. ULONG Size;
  78. ULONG MmSpecialPoolTag;
  79. ULONG MiTriageActionTaken;
  80. ULONG MmVerifyDriverLevel;
  81. ULONG KernelVerifier;
  82. ULONG_PTR MmMaximumNonPagedPool;
  83. ULONG_PTR MmAllocatedNonPagedPool;
  84. ULONG_PTR PagedPoolMaximum;
  85. ULONG_PTR PagedPoolAllocated;
  86. ULONG_PTR CommittedPages;
  87. ULONG_PTR CommittedPagesPeak;
  88. ULONG_PTR CommitLimitMaximum;
  89. } MI_TRIAGE_STORAGE, *PMI_TRIAGE_STORAGE;
  90. PKLDR_DATA_TABLE_ENTRY
  91. TriageGetLoaderEntry (
  92. IN PVOID TriageDumpBlock,
  93. IN ULONG ModuleIndex
  94. );
  95. LOGICAL
  96. TriageActUpon(
  97. IN PVOID TriageDumpBlock
  98. );
  99. PVOID
  100. TriageGetMmInformation (
  101. IN PVOID TriageDumpBlock
  102. );
  103. LOGICAL
  104. MiTriageSystem (
  105. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  106. )
  107. /*++
  108. Routine Description:
  109. This routine takes the information from the last bugcheck (if any)
  110. and triages it. Various debugging options are then automatically
  111. enabled.
  112. Arguments:
  113. LoaderBlock - Supplies a pointer to the system loader block.
  114. Return Value:
  115. TRUE if triaging succeeded and options were enabled. FALSE otherwise.
  116. --*/
  117. {
  118. PVOID TriageDumpBlock;
  119. ULONG_PTR BugCheckData[5];
  120. ULONG i;
  121. ULONG ModuleCount;
  122. NTSTATUS Status;
  123. PLIST_ENTRY NextEntry;
  124. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  125. PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
  126. LOGICAL Matched;
  127. ULONG OldDrivers;
  128. ULONG OldDriversNotVerifying;
  129. PMI_TRIAGE_STORAGE TriageInformation;
  130. if (LoaderBlock->Extension == NULL) {
  131. return FALSE;
  132. }
  133. if (LoaderBlock->Extension->Size < sizeof (LOADER_PARAMETER_EXTENSION)) {
  134. return FALSE;
  135. }
  136. TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
  137. Status = TriageGetBugcheckData (TriageDumpBlock,
  138. (PULONG)&BugCheckData[0],
  139. (PUINT_PTR) &BugCheckData[1],
  140. (PUINT_PTR) &BugCheckData[2],
  141. (PUINT_PTR) &BugCheckData[3],
  142. (PUINT_PTR) &BugCheckData[4]);
  143. if (!NT_SUCCESS (Status)) {
  144. return FALSE;
  145. }
  146. //
  147. // Always display at least the bugcheck data from the previous crash.
  148. //
  149. DbgPrint ("MiTriageSystem: Previous bugcheck was %x %p %p %p %p\n",
  150. BugCheckData[0],
  151. BugCheckData[1],
  152. BugCheckData[2],
  153. BugCheckData[3],
  154. BugCheckData[4]);
  155. if (TriageActUpon (TriageDumpBlock) == FALSE) {
  156. DbgPrint ("MiTriageSystem: Triage disabled in registry by administrator\n");
  157. return FALSE;
  158. }
  159. DbgPrint ("MiTriageSystem: Triage ENABLED in registry by administrator\n");
  160. //
  161. // See if the previous bugcheck was one where action can be taken.
  162. // If not, bail now. If so, then march on and verify all the loaded
  163. // module checksums before actually taking action on the bugcheck.
  164. //
  165. if (!MI_CAN_TRIAGE_BUGCHECK(BugCheckData[0])) {
  166. return FALSE;
  167. }
  168. TriageInformation = (PMI_TRIAGE_STORAGE) TriageGetMmInformation (TriageDumpBlock);
  169. if (TriageInformation == NULL) {
  170. return FALSE;
  171. }
  172. Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
  173. if (!NT_SUCCESS (Status)) {
  174. return FALSE;
  175. }
  176. //
  177. // Process module information from the triage dump.
  178. //
  179. #if DBG
  180. if (MiTriageDebug & 0x1) {
  181. DbgPrint ("MiTriageSystem: printing active drivers from triage crash...\n");
  182. }
  183. #endif
  184. OldDrivers = 0;
  185. OldDriversNotVerifying = 0;
  186. for (i = 0; i < ModuleCount; i += 1) {
  187. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  188. if (DumpTableEntry != NULL) {
  189. if ((DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) == 0) {
  190. OldDrivers += 1;
  191. if ((DumpTableEntry->Flags & LDRP_IMAGE_VERIFYING) == 0) {
  192. //
  193. // An NT3 or NT4 driver is in the system and was not
  194. // running under the verifier.
  195. //
  196. OldDriversNotVerifying += 1;
  197. }
  198. }
  199. #if DBG
  200. if (MiTriageDebug & 0x1) {
  201. DbgPrint (" %wZ: base = %p, size = %lx, flags = %lx\n",
  202. &DumpTableEntry->BaseDllName,
  203. DumpTableEntry->DllBase,
  204. DumpTableEntry->SizeOfImage,
  205. DumpTableEntry->Flags);
  206. }
  207. #endif
  208. }
  209. }
  210. //
  211. // Ensure that every driver that is currently loaded is identical to
  212. // the one in the triage dump before proceeding.
  213. //
  214. NextEntry = LoaderBlock->LoadOrderListHead.Flink;
  215. while (NextEntry != &LoaderBlock->LoadOrderListHead) {
  216. DataTableEntry = CONTAINING_RECORD(NextEntry,
  217. KLDR_DATA_TABLE_ENTRY,
  218. InLoadOrderLinks);
  219. Matched = FALSE;
  220. for (i = 0; i < ModuleCount; i += 1) {
  221. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  222. if (DumpTableEntry != NULL) {
  223. if (DataTableEntry->CheckSum == DumpTableEntry->CheckSum) {
  224. Matched = TRUE;
  225. break;
  226. }
  227. }
  228. }
  229. if (Matched == FALSE) {
  230. DbgPrint ("Matching checksum for module %wZ not found in triage dump\n",
  231. &DataTableEntry->BaseDllName);
  232. #if DBG
  233. if (MiTriageRegardless == FALSE)
  234. #endif
  235. return FALSE;
  236. }
  237. NextEntry = NextEntry->Flink;
  238. }
  239. #if DBG
  240. if (MiTriageDebug & 0x1) {
  241. DbgPrint ("MiTriageSystem: OldDrivers = %u, without verification =%u\n",
  242. OldDrivers,
  243. OldDriversNotVerifying);
  244. }
  245. #endif
  246. //
  247. // All boot loaded drivers matched, take action on the triage dump now.
  248. //
  249. if (MI_HOLD_TRIAGE_BUGCHECK(BugCheckData[0])) {
  250. //
  251. // The last bugcheck was presumably triggered by either autotriage or
  252. // the admin's registry settings - so don't apply any new rules
  253. // and in addition, keep the old ones unaltered so it can reproduce.
  254. //
  255. MmTriageActionTaken = TriageInformation->MiTriageActionTaken;
  256. MmTriageActionTaken |= MI_KEEPING_PREVIOUS_SETTINGS;
  257. }
  258. else {
  259. switch (BugCheckData[0]) {
  260. case DRIVER_CORRUPTED_SYSPTES:
  261. //
  262. // Turn on PTE tracking to trigger a SYSTEM_PTE_MISUSE bugcheck.
  263. //
  264. MmTriageActionTaken |= MI_TRACKING_PTES;
  265. break;
  266. case NO_MORE_SYSTEM_PTES:
  267. //
  268. // Turn on PTE tracking so the driver can be identified via a
  269. // DRIVER_USED_EXCESSIVE_PTES bugcheck.
  270. //
  271. if (BugCheckData[1] == SystemPteSpace) {
  272. MmTriageActionTaken |= MI_TRACKING_PTES;
  273. }
  274. break;
  275. case BAD_POOL_HEADER:
  276. case DRIVER_CORRUPTED_EXPOOL:
  277. //
  278. // Turn on the driver verifier and/or special pool.
  279. // Start by enabling it for every driver that isn't built for NT5.
  280. // Override any specified driver verifier options so that only
  281. // special pool is enabled to minimize the performance hit.
  282. //
  283. if (OldDrivers != 0) {
  284. if (OldDriversNotVerifying != 0) {
  285. MmTriageActionTaken |= MI_VERIFYING_PRENT5_DRIVERS;
  286. }
  287. }
  288. break;
  289. case DRIVER_CORRUPTED_MMPOOL:
  290. //
  291. // Protect freed nonpaged pool if the system had less than 128mb
  292. // of nonpaged pool anyway. This is to trigger a
  293. // DRIVER_CAUGHT_MODIFYING_FREED_POOL bugcheck.
  294. //
  295. #define MB128 ((ULONG_PTR)0x80000000 >> PAGE_SHIFT)
  296. if (TriageInformation->MmMaximumNonPagedPool < MB128) {
  297. MmTriageActionTaken |= MI_PROTECT_FREED_NONPAGED_POOL;
  298. }
  299. break;
  300. case IRQL_NOT_LESS_OR_EQUAL:
  301. case DRIVER_IRQL_NOT_LESS_OR_EQUAL:
  302. default:
  303. break;
  304. }
  305. }
  306. //
  307. // For now always show if action was taken from the bugcheck
  308. // data from the crash. This print and the space for the print strings
  309. // will be enabled for checked builds only prior to shipping.
  310. //
  311. if (MmTriageActionTaken != 0) {
  312. if (MmTriageActionTaken & MI_TRACKING_PTES) {
  313. MmTrackPtes |= 0x1;
  314. }
  315. if (MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) {
  316. MmVerifyDriverLevel &= ~DRIVER_VERIFIER_FORCE_IRQL_CHECKING;
  317. MmVerifyDriverLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
  318. }
  319. if (MmTriageActionTaken & MI_PROTECT_FREED_NONPAGED_POOL) {
  320. MmProtectFreedNonPagedPool = TRUE;
  321. }
  322. DbgPrint ("MiTriageSystem: enabling options below to find who caused the last crash\n");
  323. for (i = 0; i < 32; i += 1) {
  324. if (MmTriageActionTaken & (1 << i)) {
  325. DbgPrint (" %s\n", MiTriageActionStrings[i]);
  326. }
  327. }
  328. }
  329. return TRUE;
  330. }
  331. LOGICAL
  332. MiTriageAddDrivers (
  333. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  334. )
  335. /*++
  336. Routine Description:
  337. This routine moves the names of any drivers that autotriage has determined
  338. need verifying from the LoaderBlock into pool.
  339. Arguments:
  340. LoaderBlock - Supplies a pointer to the system loader block.
  341. Return Value:
  342. TRUE if any drivers were added, FALSE if not.
  343. --*/
  344. {
  345. ULONG i;
  346. ULONG ModuleCount;
  347. NTSTATUS Status;
  348. PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
  349. PVOID TriageDumpBlock;
  350. ULONG NameLength;
  351. LOGICAL Added;
  352. PMI_VERIFIER_DRIVER_ENTRY VerifierDriverEntry;
  353. if ((MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) == 0) {
  354. return FALSE;
  355. }
  356. TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
  357. Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
  358. if (!NT_SUCCESS (Status)) {
  359. return FALSE;
  360. }
  361. Added = FALSE;
  362. for (i = 0; i < ModuleCount; i += 1) {
  363. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  364. if (DumpTableEntry == NULL) {
  365. continue;
  366. }
  367. if (DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) {
  368. continue;
  369. }
  370. DbgPrint ("MiTriageAddDrivers: Marking %wZ for verification when it is loaded\n", &DumpTableEntry->BaseDllName);
  371. NameLength = DumpTableEntry->BaseDllName.Length;
  372. VerifierDriverEntry = (PMI_VERIFIER_DRIVER_ENTRY)ExAllocatePoolWithTag (
  373. NonPagedPool,
  374. sizeof (MI_VERIFIER_DRIVER_ENTRY) +
  375. NameLength,
  376. 'dLmM');
  377. if (VerifierDriverEntry == NULL) {
  378. continue;
  379. }
  380. VerifierDriverEntry->Loads = 0;
  381. VerifierDriverEntry->Unloads = 0;
  382. VerifierDriverEntry->BaseName.Buffer = (PWSTR)((PCHAR)VerifierDriverEntry +
  383. sizeof (MI_VERIFIER_DRIVER_ENTRY));
  384. VerifierDriverEntry->BaseName.Length = (USHORT)NameLength;
  385. VerifierDriverEntry->BaseName.MaximumLength = (USHORT)NameLength;
  386. RtlCopyMemory (VerifierDriverEntry->BaseName.Buffer,
  387. DumpTableEntry->BaseDllName.Buffer,
  388. NameLength);
  389. InsertHeadList (&MiSuspectDriverList, &VerifierDriverEntry->Links);
  390. Added = TRUE;
  391. }
  392. return Added;
  393. }
  394. #define MAX_UNLOADED_NAME_LENGTH 24
  395. typedef struct _DUMP_UNLOADED_DRIVERS {
  396. UNICODE_STRING Name;
  397. WCHAR DriverName[MAX_UNLOADED_NAME_LENGTH / sizeof (WCHAR)];
  398. PVOID StartAddress;
  399. PVOID EndAddress;
  400. } DUMP_UNLOADED_DRIVERS, *PDUMP_UNLOADED_DRIVERS;
  401. ULONG
  402. MmSizeOfUnloadedDriverInformation (
  403. VOID
  404. )
  405. /*++
  406. Routine Description:
  407. This routine returns the size of the Mm-internal unloaded driver
  408. information that is stored in the triage dump when (if?) the system crashes.
  409. Arguments:
  410. None.
  411. Return Value:
  412. Size of the Mm-internal unloaded driver information.
  413. --*/
  414. {
  415. if (MmUnloadedDrivers == NULL) {
  416. return sizeof (ULONG_PTR);
  417. }
  418. return sizeof(ULONG_PTR) + MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS);
  419. }
  420. VOID
  421. MmWriteUnloadedDriverInformation (
  422. IN PVOID Destination
  423. )
  424. /*++
  425. Routine Description:
  426. This routine stores the Mm-internal unloaded driver information into
  427. the triage dump.
  428. Arguments:
  429. None.
  430. Return Value:
  431. None.
  432. --*/
  433. {
  434. ULONG i;
  435. ULONG Index;
  436. PUNLOADED_DRIVERS Unloaded;
  437. PDUMP_UNLOADED_DRIVERS DumpUnloaded;
  438. if (MmUnloadedDrivers == NULL) {
  439. *(PULONG)Destination = 0;
  440. }
  441. else {
  442. DumpUnloaded = (PDUMP_UNLOADED_DRIVERS)((PULONG_PTR)Destination + 1);
  443. Unloaded = MmUnloadedDrivers;
  444. //
  445. // Write the list with the most recently unloaded driver first to the
  446. // least recently unloaded driver last.
  447. //
  448. Index = MmLastUnloadedDriver - 1;
  449. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) {
  450. if (Index >= MI_UNLOADED_DRIVERS) {
  451. Index = MI_UNLOADED_DRIVERS - 1;
  452. }
  453. Unloaded = &MmUnloadedDrivers[Index];
  454. DumpUnloaded->Name = Unloaded->Name;
  455. if (Unloaded->Name.Buffer == NULL) {
  456. break;
  457. }
  458. DumpUnloaded->StartAddress = Unloaded->StartAddress;
  459. DumpUnloaded->EndAddress = Unloaded->EndAddress;
  460. if (DumpUnloaded->Name.Length > MAX_UNLOADED_NAME_LENGTH) {
  461. DumpUnloaded->Name.Length = MAX_UNLOADED_NAME_LENGTH;
  462. }
  463. if (DumpUnloaded->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH) {
  464. DumpUnloaded->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH;
  465. }
  466. DumpUnloaded->Name.Buffer = DumpUnloaded->DriverName;
  467. RtlCopyMemory ((PVOID)DumpUnloaded->Name.Buffer,
  468. (PVOID)Unloaded->Name.Buffer,
  469. DumpUnloaded->Name.MaximumLength);
  470. DumpUnloaded += 1;
  471. Index -= 1;
  472. }
  473. *(PULONG)Destination = i;
  474. }
  475. }
  476. ULONG
  477. MmSizeOfTriageInformation (
  478. VOID
  479. )
  480. /*++
  481. Routine Description:
  482. This routine returns the size of the Mm-internal information that is
  483. stored in the triage dump when (if?) the system crashes.
  484. Arguments:
  485. None.
  486. Return Value:
  487. Size of the Mm-internal triage information.
  488. --*/
  489. {
  490. return sizeof (MI_TRIAGE_STORAGE);
  491. }
  492. VOID
  493. MmWriteTriageInformation (
  494. IN PVOID Destination
  495. )
  496. /*++
  497. Routine Description:
  498. This routine stores the Mm-internal information into the triage dump.
  499. Arguments:
  500. None.
  501. Return Value:
  502. None.
  503. --*/
  504. {
  505. MI_TRIAGE_STORAGE TriageInformation;
  506. TriageInformation.Version = 1;
  507. TriageInformation.Size = sizeof (MI_TRIAGE_STORAGE);
  508. TriageInformation.MmSpecialPoolTag = MmSpecialPoolTag;
  509. TriageInformation.MiTriageActionTaken = MmTriageActionTaken;
  510. TriageInformation.MmVerifyDriverLevel = MmVerifierData.Level;
  511. TriageInformation.KernelVerifier = KernelVerifier;
  512. TriageInformation.MmMaximumNonPagedPool = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
  513. TriageInformation.MmAllocatedNonPagedPool = MmAllocatedNonPagedPool;
  514. TriageInformation.PagedPoolMaximum = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
  515. TriageInformation.PagedPoolAllocated = MmPagedPoolInfo.AllocatedPagedPool;
  516. TriageInformation.CommittedPages = MmTotalCommittedPages;
  517. TriageInformation.CommittedPagesPeak = MmPeakCommitment;
  518. TriageInformation.CommitLimitMaximum = MmTotalCommitLimitMaximum;
  519. RtlCopyMemory (Destination,
  520. (PVOID)&TriageInformation,
  521. sizeof (MI_TRIAGE_STORAGE));
  522. }