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.

1220 lines
30 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. PpDrvDB.c
  5. Abstract:
  6. This module containst PnP routines related to Defective Driver Database
  7. (DDB) support.
  8. Author:
  9. Santosh S. Jodh - 22 Jan 2001
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "pnpmgrp.h"
  15. #include "windef.h"
  16. #include "winerror.h"
  17. #include "shimdb.h"
  18. #pragma hdrstop
  19. // Bit 0 indicates policy for filters (0 = critical, 1 = non-critical)
  20. #define DDB_DRIVER_POLICY_CRITICAL_BIT (1 << 0)
  21. // Bit 1 indicates policy for user-mode setup blocking (0 = block, 1 = no-block)
  22. #define DDB_DRIVER_POLICY_SETUP_NO_BLOCK_BIT (1 << 1)
  23. #define DDB_BOOT_NOT_LOADED_ERROR (1 << 0)
  24. #define DDB_BOOT_OUT_OF_MEMORY_ERROR (1 << 1)
  25. #define DDB_BOOT_INIT_ERROR (1 << 2)
  26. #define DDB_DRIVER_PATH_ERROR (1 << 3)
  27. #define DDB_OPEN_FILE_ERROR (1 << 4)
  28. #define DDB_CREATE_SECTION_ERROR (1 << 5)
  29. #define DDB_MAP_SECTION_ERROR (1 << 6)
  30. #define DDB_MAPPED_INIT_ERROR (1 << 7)
  31. #define DDB_READ_INFORMATION_ERROR (1 << 8)
  32. //#define USE_HANDLES 0
  33. extern BOOLEAN ExpInTextModeSetup;
  34. #define INVALID_HANDLE_VALUE ((HANDLE)-1)
  35. typedef struct _DDBCACHE_ENTRY {
  36. //
  37. // These fields are used as matching critereon for cache lookup.
  38. //
  39. UNICODE_STRING Name; // Driver name
  40. ULONG TimeDateStamp; // Link date of the driver
  41. //
  42. // Reference data for the cached entry.
  43. //
  44. NTSTATUS Status; // Status from the DDB lookup
  45. GUID Guid;
  46. } DDBCACHE_ENTRY, *PDDBCACHE_ENTRY;
  47. #ifdef ALLOC_DATA_PRAGMA
  48. #pragma data_seg("PAGEDATA")
  49. #pragma const_seg("PAGECONST")
  50. #endif
  51. //
  52. // Constants.
  53. //
  54. const PWSTR PiSetupDDBPath = TEXT("\\$WIN_NT$.~BT\\drvmain.sdb");
  55. const PWSTR PiNormalDDBPath = TEXT("\\SystemRoot\\AppPatch\\drvmain.sdb");
  56. //
  57. // Data.
  58. //
  59. // Handle to the driver database.
  60. //
  61. HSDB PpDDBHandle = NULL;
  62. //
  63. // Copy to the in memory image of driver database. Used only during boot.
  64. //
  65. PVOID PpBootDDB = NULL;
  66. //
  67. // Lock for synchronizing access to the driver database.
  68. //
  69. ERESOURCE PiDDBLock;
  70. //
  71. // We use RTL AVL table for our cache.
  72. //
  73. RTL_GENERIC_TABLE PiDDBCacheTable;
  74. //
  75. // Number of drivers blocked this boot.
  76. //
  77. ULONG PpBlockedDriverCount = 0;
  78. //
  79. // Path for the DDB.
  80. //
  81. PWSTR PiDDBPath = NULL;
  82. //
  83. // Mask to record already logged events.
  84. //
  85. ULONG PiLoggedErrorEventsMask = 0;
  86. #ifdef ALLOC_DATA_PRAGMA
  87. #pragma data_seg()
  88. #pragma const_seg()
  89. #endif
  90. NTSTATUS
  91. PiLookupInDDB(
  92. IN PUNICODE_STRING FullPath,
  93. IN PVOID ImageBase,
  94. IN ULONG ImageSize,
  95. IN BOOLEAN IsFilter,
  96. OUT LPGUID EntryGuid
  97. );
  98. NTSTATUS
  99. PiIsDriverBlocked(
  100. IN HSDB SdbHandle,
  101. IN PUNICODE_STRING FullPath,
  102. IN PVOID ImageBase,
  103. IN ULONG ImageSize,
  104. IN BOOLEAN IsFilter,
  105. OUT LPGUID EntryGuid
  106. );
  107. VOID
  108. PiLogDriverBlockedEvent(
  109. IN PWCHAR InsertionString,
  110. IN PVOID Data,
  111. IN ULONG DataLength,
  112. IN NTSTATUS Status
  113. );
  114. NTSTATUS
  115. PiInitializeDDBCache(
  116. VOID
  117. );
  118. RTL_GENERIC_COMPARE_RESULTS
  119. NTAPI
  120. PiCompareDDBCacheEntries(
  121. IN PRTL_GENERIC_TABLE Table,
  122. IN PVOID FirstStruct,
  123. IN PVOID SecondStruct
  124. );
  125. NTSTATUS
  126. PiLookupInDDBCache(
  127. IN PUNICODE_STRING FullPath,
  128. IN PVOID ImageBase,
  129. IN ULONG ImageSize,
  130. OUT LPGUID EntryGuid
  131. );
  132. VOID
  133. PiUpdateDriverDBCache(
  134. IN PUNICODE_STRING FullPath,
  135. IN PVOID ImageBase,
  136. IN ULONG ImageSize,
  137. IN NTSTATUS Status,
  138. IN GUID *Guid
  139. );
  140. #ifdef ALLOC_PRAGMA
  141. #pragma alloc_text(INIT, PpInitializeBootDDB)
  142. #pragma alloc_text(PAGE, PpReleaseBootDDB)
  143. #pragma alloc_text(PAGE, PpCheckInDriverDatabase)
  144. #pragma alloc_text(PAGE, PiLookupInDDB)
  145. #pragma alloc_text(PAGE, PiIsDriverBlocked)
  146. #pragma alloc_text(PAGE, PiLogDriverBlockedEvent)
  147. #pragma alloc_text(PAGE, PiInitializeDDBCache)
  148. #pragma alloc_text(PAGE, PiCompareDDBCacheEntries)
  149. #pragma alloc_text(PAGE, PiLookupInDDBCache)
  150. #pragma alloc_text(PAGE, PiUpdateDriverDBCache)
  151. #pragma alloc_text(PAGE, PpGetBlockedDriverList)
  152. #endif
  153. NTSTATUS
  154. PpInitializeBootDDB(
  155. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  156. )
  157. /*++
  158. Routine Description:
  159. This routine initializes the DDB from the image copied by ntldr.
  160. Arguments:
  161. LoaderBlock - Pointer to loader block.
  162. Return Value:
  163. NTSTATUS.
  164. --*/
  165. {
  166. PAGED_CODE();
  167. PpBlockedDriverCount = 0;
  168. PpDDBHandle = NULL;
  169. PpBootDDB = NULL;
  170. //
  171. // Initialize the lock for serializing access to the DDB.
  172. //
  173. ExInitializeResource(&PiDDBLock);
  174. PiDDBPath = (ExpInTextModeSetup)? PiSetupDDBPath : PiNormalDDBPath;
  175. //
  176. // Initialize DDB cache.
  177. //
  178. PiInitializeDDBCache();
  179. //
  180. // Return failure if the loader did not load the database.
  181. //
  182. if (LoaderBlock->Extension->DrvDBSize == 0 ||
  183. LoaderBlock->Extension->DrvDBImage == NULL) {
  184. if (!(PiLoggedErrorEventsMask & DDB_BOOT_NOT_LOADED_ERROR)) {
  185. IopDbgPrint((IOP_ERROR_LEVEL,
  186. "PpInitializeDriverDB: Driver database not loaded!\n"));
  187. PiLoggedErrorEventsMask |= DDB_BOOT_NOT_LOADED_ERROR;
  188. PiLogDriverBlockedEvent(
  189. TEXT("DATABASE NOT LOADED"),
  190. NULL,
  191. 0,
  192. STATUS_DRIVER_DATABASE_ERROR);
  193. }
  194. return STATUS_UNSUCCESSFUL;
  195. }
  196. //
  197. // Make a copy of the database in pageable memory since the loader memory
  198. // will soon get claimed.
  199. // If this becomes a perf issue, we need to add
  200. // support for a new loader memory type (PAGEABLE DATA).
  201. //
  202. PpBootDDB = ExAllocatePool(PagedPool, LoaderBlock->Extension->DrvDBSize);
  203. if (PpBootDDB == NULL) {
  204. IopDbgPrint((IOP_ERROR_LEVEL,
  205. "PpInitializeDriverDB: Failed to allocate memory to copy driver database!\n"));
  206. ASSERT(PpBootDDB);
  207. if (!(PiLoggedErrorEventsMask & DDB_BOOT_OUT_OF_MEMORY_ERROR)) {
  208. PiLoggedErrorEventsMask |= DDB_BOOT_OUT_OF_MEMORY_ERROR;
  209. PiLogDriverBlockedEvent(
  210. TEXT("OUT OF MEMORY"),
  211. NULL,
  212. 0,
  213. STATUS_DRIVER_DATABASE_ERROR);
  214. }
  215. return STATUS_INSUFFICIENT_RESOURCES;
  216. }
  217. RtlCopyMemory(PpBootDDB, LoaderBlock->Extension->DrvDBImage, LoaderBlock->Extension->DrvDBSize);
  218. //
  219. // Initialize the database from the memory image.
  220. //
  221. PpDDBHandle = SdbInitDatabaseInMemory(PpBootDDB, LoaderBlock->Extension->DrvDBSize);
  222. if (PpDDBHandle == NULL) {
  223. ExFreePool(PpBootDDB);
  224. PpBootDDB = NULL;
  225. IopDbgPrint((IOP_ERROR_LEVEL,
  226. "PpInitializeDriverDB: Failed to initialize driver database!\n"));
  227. ASSERT(PpDDBHandle);
  228. if (!(PiLoggedErrorEventsMask & DDB_BOOT_INIT_ERROR)) {
  229. PiLoggedErrorEventsMask |= DDB_BOOT_INIT_ERROR;
  230. PiLogDriverBlockedEvent(
  231. TEXT("INIT DATABASE FAILED"),
  232. NULL,
  233. 0,
  234. STATUS_DRIVER_DATABASE_ERROR);
  235. }
  236. return STATUS_UNSUCCESSFUL;
  237. }
  238. return STATUS_SUCCESS;
  239. }
  240. NTSTATUS
  241. PpReleaseBootDDB(
  242. VOID
  243. )
  244. /*++
  245. Routine Description:
  246. This routine frees up the boot DDB once we are dont loading most drivers
  247. during boot.
  248. Arguments:
  249. None.
  250. Return Value:
  251. NTSTATUS.
  252. --*/
  253. {
  254. NTSTATUS status;
  255. PAGED_CODE();
  256. //
  257. // Lock the DDB before freeing it.
  258. //
  259. KeEnterCriticalRegion();
  260. ExAcquireResourceExclusiveLite(&PiDDBLock, TRUE);
  261. //
  262. // Free the DDB if any.
  263. //
  264. if (PpDDBHandle) {
  265. ASSERT(PpBootDDB);
  266. SdbReleaseDatabase(PpDDBHandle);
  267. PpDDBHandle = NULL;
  268. ExFreePool(PpBootDDB);
  269. PpBootDDB = NULL;
  270. status = STATUS_SUCCESS;
  271. } else {
  272. IopDbgPrint((IOP_WARNING_LEVEL,
  273. "PpReleaseBootDDB called with uninitialized database!\n"));
  274. status = STATUS_UNSUCCESSFUL;
  275. }
  276. //
  277. // Unlock the DDB.
  278. //
  279. ExReleaseResourceLite(&PiDDBLock);
  280. KeLeaveCriticalRegion();
  281. return status;
  282. }
  283. NTSTATUS
  284. PpCheckInDriverDatabase(
  285. IN PUNICODE_STRING KeyName,
  286. IN HANDLE KeyHandle,
  287. IN PVOID ImageBase,
  288. IN ULONG ImageSize,
  289. IN BOOLEAN IsFilter,
  290. OUT LPGUID EntryGuid
  291. )
  292. /*++
  293. Routine Description:
  294. This routine checks the DDB for the presence of this driver.
  295. Arguments:
  296. KeyName - Supplies a pointer to the driver's service key unicode string
  297. KeyHandle - Supplies a handle to the driver service node in the registry
  298. that describes the driver to be loaded.
  299. Header - Driver image header.
  300. IsFilter - Specifies whether this is a filter driver or not.
  301. Return Value:
  302. NTSTATUS.
  303. --*/
  304. {
  305. NTSTATUS status;
  306. UNICODE_STRING fullPath;
  307. PAGED_CODE();
  308. //
  309. // No driver blocking during textmode setup.
  310. //
  311. if (ExpInTextModeSetup) {
  312. return STATUS_SUCCESS;
  313. }
  314. status = IopBuildFullDriverPath(KeyName, KeyHandle, &fullPath);
  315. if (NT_SUCCESS(status)) {
  316. //
  317. // Lock the database access.
  318. //
  319. KeEnterCriticalRegion();
  320. ExAcquireResourceExclusiveLite(&PiDDBLock, TRUE);
  321. //
  322. // First check the cache.
  323. //
  324. status = PiLookupInDDBCache(&fullPath, ImageBase, ImageSize, EntryGuid);
  325. if (status == STATUS_UNSUCCESSFUL) {
  326. //
  327. // Cache miss, try the database.
  328. //
  329. status = PiLookupInDDB(&fullPath, ImageBase, ImageSize, IsFilter, EntryGuid);
  330. }
  331. //
  332. // Unlock the database.
  333. //
  334. ExReleaseResourceLite(&PiDDBLock);
  335. KeLeaveCriticalRegion();
  336. ExFreePool(fullPath.Buffer);
  337. } else {
  338. IopDbgPrint((IOP_ERROR_LEVEL,
  339. "IopCheckInDriverDatabase: Failed to build full driver path!\n"));
  340. ASSERT(NT_SUCCESS(status));
  341. if (!(PiLoggedErrorEventsMask & DDB_DRIVER_PATH_ERROR)) {
  342. PiLoggedErrorEventsMask |= DDB_DRIVER_PATH_ERROR;
  343. PiLogDriverBlockedEvent(
  344. TEXT("BUILD DRIVER PATH FAILED"),
  345. NULL,
  346. 0,
  347. STATUS_DRIVER_DATABASE_ERROR);
  348. }
  349. }
  350. //
  351. // Ingore errors.
  352. //
  353. if (status != STATUS_DRIVER_BLOCKED &&
  354. status != STATUS_DRIVER_BLOCKED_CRITICAL) {
  355. status = STATUS_SUCCESS;
  356. }
  357. return status;
  358. }
  359. NTSTATUS
  360. PiLookupInDDB(
  361. IN PUNICODE_STRING FullPath,
  362. IN PVOID ImageBase,
  363. IN ULONG ImageSize,
  364. IN BOOLEAN IsFilter,
  365. OUT LPGUID EntryGuid
  366. )
  367. /*++
  368. Routine Description:
  369. This routine checks the DDB for the presence of this driver. During BOOT,
  370. it uses the boot DDB loaded by ntldr. Once the system is booted, it maps the
  371. DDB in memory.
  372. Arguments:
  373. FullPath - Full driver path
  374. Header - Driver image header.
  375. IsFilter - Specifies whether this is a filter driver or not.
  376. Return Value:
  377. NTSTATUS.
  378. --*/
  379. {
  380. UNICODE_STRING fileName;
  381. OBJECT_ATTRIBUTES objectAttributes;
  382. HANDLE sectionHandle, fileHandle;
  383. NTSTATUS status, unmapStatus;
  384. IO_STATUS_BLOCK ioStatus;
  385. PVOID ddbAddress;
  386. SIZE_T ddbSize;
  387. PAGED_CODE();
  388. fileHandle = (HANDLE)0;
  389. sectionHandle = (HANDLE)0;
  390. ddbAddress = NULL;
  391. if (PpDDBHandle == NULL) {
  392. //
  393. // Map the database in memory and initialize it.
  394. //
  395. RtlInitUnicodeString(&fileName, PiDDBPath);
  396. InitializeObjectAttributes(&objectAttributes,
  397. &fileName,
  398. (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),
  399. NULL,
  400. NULL);
  401. status = ZwOpenFile (&fileHandle,
  402. GENERIC_READ,
  403. &objectAttributes,
  404. &ioStatus,
  405. FILE_SHARE_READ | FILE_SHARE_DELETE,
  406. 0);
  407. if (!NT_SUCCESS(status)) {
  408. if (!(PiLoggedErrorEventsMask & DDB_OPEN_FILE_ERROR)) {
  409. IopDbgPrint((IOP_ERROR_LEVEL,
  410. "PiLookupInDDB: Failed to open driver database %wZ!\n", &fileName));
  411. PiLoggedErrorEventsMask |= DDB_OPEN_FILE_ERROR;
  412. PiLogDriverBlockedEvent(
  413. TEXT("DATABASE OPEN FAILED"),
  414. NULL,
  415. 0,
  416. STATUS_DRIVER_DATABASE_ERROR);
  417. }
  418. goto Cleanup;
  419. }
  420. status = ZwCreateSection(
  421. &sectionHandle,
  422. SECTION_MAP_READ,
  423. NULL,
  424. NULL,
  425. PAGE_READONLY,
  426. SEC_COMMIT,
  427. fileHandle);
  428. if (!NT_SUCCESS(status)) {
  429. IopDbgPrint((IOP_ERROR_LEVEL,
  430. "PiLookupInDDB: Failed to create section to map driver database %wZ!\n", &fileName));
  431. ASSERT(NT_SUCCESS(status));
  432. if (!(PiLoggedErrorEventsMask & DDB_CREATE_SECTION_ERROR)) {
  433. PiLoggedErrorEventsMask |= DDB_CREATE_SECTION_ERROR;
  434. PiLogDriverBlockedEvent(
  435. TEXT("DATABASE SECTION FAILED"),
  436. NULL,
  437. 0,
  438. STATUS_DRIVER_DATABASE_ERROR);
  439. }
  440. goto Cleanup;
  441. }
  442. ddbSize = 0;
  443. status = ZwMapViewOfSection(
  444. sectionHandle,
  445. NtCurrentProcess(),
  446. &ddbAddress,
  447. 0,
  448. 0,
  449. NULL,
  450. &ddbSize,
  451. ViewShare,
  452. 0,
  453. PAGE_READONLY
  454. );
  455. if (!NT_SUCCESS(status)) {
  456. IopDbgPrint((IOP_ERROR_LEVEL,
  457. "PiLookupInDDB: Failed to map driver database %wZ!\n", &fileName));
  458. ASSERT(NT_SUCCESS(status));
  459. if (!(PiLoggedErrorEventsMask & DDB_MAP_SECTION_ERROR)) {
  460. PiLoggedErrorEventsMask |= DDB_MAP_SECTION_ERROR;
  461. PiLogDriverBlockedEvent(
  462. TEXT("DATABASE MAPPING FAILED"),
  463. NULL,
  464. 0,
  465. STATUS_DRIVER_DATABASE_ERROR);
  466. }
  467. goto Cleanup;
  468. }
  469. PpDDBHandle = SdbInitDatabaseInMemory(ddbAddress, (ULONG)ddbSize);
  470. if (PpDDBHandle == NULL) {
  471. IopDbgPrint((IOP_ERROR_LEVEL,
  472. "PiLookupInDDB: Failed to initialize mapped driver database %wZ!\n", &fileName));
  473. status = STATUS_UNSUCCESSFUL;
  474. ASSERT(PpDDBHandle);
  475. if (!(PiLoggedErrorEventsMask & DDB_MAPPED_INIT_ERROR)) {
  476. PiLoggedErrorEventsMask |= DDB_MAPPED_INIT_ERROR;
  477. PiLogDriverBlockedEvent(
  478. TEXT("INIT DATABASE FAILED"),
  479. NULL,
  480. 0,
  481. STATUS_DRIVER_DATABASE_ERROR);
  482. }
  483. goto Cleanup;
  484. }
  485. }
  486. //
  487. // Lookup the driver in the DDB.
  488. //
  489. status = PiIsDriverBlocked(PpDDBHandle, FullPath, ImageBase, ImageSize, IsFilter, EntryGuid);
  490. if (ddbAddress) {
  491. SdbReleaseDatabase(PpDDBHandle);
  492. PpDDBHandle = NULL;
  493. }
  494. Cleanup:
  495. if (ddbAddress) {
  496. unmapStatus = ZwUnmapViewOfSection(NtCurrentProcess(), ddbAddress);
  497. ASSERT(NT_SUCCESS(unmapStatus));
  498. }
  499. if (sectionHandle) {
  500. ZwClose(sectionHandle);
  501. }
  502. if (fileHandle) {
  503. ZwClose(fileHandle);
  504. }
  505. return status;
  506. }
  507. NTSTATUS
  508. PiIsDriverBlocked(
  509. IN HSDB SdbHandle,
  510. IN PUNICODE_STRING FullPath,
  511. IN PVOID ImageBase,
  512. IN ULONG ImageSize,
  513. IN BOOLEAN IsFilter,
  514. OUT LPGUID EntryGuid
  515. )
  516. /*++
  517. Routine Description:
  518. This routine checks the DDB for the presence of this driver. During BOOT,
  519. it uses the boot DDB loaded by ntldr. Once the system is booted, it maps the
  520. DDB in memory.
  521. Arguments:
  522. SdbHandle - Handle to the DDB to be used.
  523. FullPath - Full driver path
  524. Header - Driver image header.
  525. IsFilter - Specifies whether this is a filter driver or not.
  526. Return Value:
  527. NTSTATUS.
  528. --*/
  529. {
  530. NTSTATUS status;
  531. TAGREF driverTag;
  532. SDBENTRYINFO entryInfo;
  533. ULONG type, size, policy;
  534. HANDLE fileHandle;
  535. PWCHAR fileName;
  536. #ifdef USE_HANDLES
  537. UNICODE_STRING fileName;
  538. OBJECT_ATTRIBUTES objectAttributes;
  539. IO_STATUS_BLOCK ioStatus;
  540. #endif
  541. PAGED_CODE();
  542. fileHandle = INVALID_HANDLE_VALUE;
  543. ASSERT(ARGUMENT_PRESENT(EntryGuid));
  544. #ifdef USE_HANDLES
  545. if (PnPBootDriversInitialized) {
  546. RtlInitUnicodeString(&fileName, FullPath->Buffer);
  547. InitializeObjectAttributes(&objectAttributes,
  548. &fileName,
  549. (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),
  550. NULL,
  551. NULL);
  552. status = ZwOpenFile (&fileHandle,
  553. GENERIC_READ,
  554. &objectAttributes,
  555. &ioStatus,
  556. FILE_SHARE_READ | FILE_SHARE_DELETE,
  557. 0);
  558. if (!NT_SUCCESS(status)) {
  559. IopDbgPrint((IOP_ERROR_LEVEL,
  560. "PiIsDriverBlocked: Failed to open driver %wZ!\n", FullPath));
  561. ASSERT(NT_SUCCESS(status));
  562. fileHandle = INVALID_HANDLE_VALUE;
  563. }
  564. }
  565. #endif
  566. ASSERT(SdbHandle != NULL);
  567. driverTag = SdbGetDatabaseMatch(SdbHandle, FullPath->Buffer, fileHandle, ImageBase, ImageSize);
  568. if (TAGREF_NULL != driverTag) {
  569. //
  570. // Read the driver policy (we care only about bit 0).
  571. //
  572. size = sizeof(policy);
  573. type = REG_DWORD;
  574. if ( SdbQueryDriverInformation( SdbHandle,
  575. driverTag,
  576. L"Policy",
  577. &type,
  578. &policy,
  579. &size) != ERROR_SUCCESS ||
  580. (policy & DDB_DRIVER_POLICY_CRITICAL_BIT) == 0 || IsFilter == FALSE) {
  581. status = STATUS_DRIVER_BLOCKED_CRITICAL;
  582. } else {
  583. //
  584. // Bit 0 of POLICY==1 for a filter, means ok to start the devnode minus this filter.
  585. //
  586. status = STATUS_DRIVER_BLOCKED;
  587. }
  588. if (!SdbReadDriverInformation(SdbHandle, driverTag, &entryInfo)) {
  589. IopDbgPrint((IOP_ERROR_LEVEL,
  590. "PiIsDriverBlocked: Failed to read the GUID from the database for driver %wZ!\n", FullPath));
  591. ASSERT(0);
  592. if (!(PiLoggedErrorEventsMask & DDB_READ_INFORMATION_ERROR)) {
  593. PiLoggedErrorEventsMask |= DDB_READ_INFORMATION_ERROR;
  594. PiLogDriverBlockedEvent(
  595. TEXT("READ DRIVER ID FAILED"),
  596. NULL,
  597. 0,
  598. STATUS_DRIVER_DATABASE_ERROR);
  599. }
  600. } else {
  601. IopDbgPrint((IOP_INFO_LEVEL,
  602. "PiIsDriverBlocked: Driver entry GUID = {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  603. entryInfo.guidID.Data1,
  604. entryInfo.guidID.Data2,
  605. entryInfo.guidID.Data3,
  606. entryInfo.guidID.Data4[0],
  607. entryInfo.guidID.Data4[1],
  608. entryInfo.guidID.Data4[2],
  609. entryInfo.guidID.Data4[3],
  610. entryInfo.guidID.Data4[4],
  611. entryInfo.guidID.Data4[5],
  612. entryInfo.guidID.Data4[6],
  613. entryInfo.guidID.Data4[7]
  614. ));
  615. }
  616. } else {
  617. //
  618. // Driver not found in the database.
  619. //
  620. status = STATUS_SUCCESS;
  621. }
  622. //
  623. // Write an entry to the event log.
  624. //
  625. if (status == STATUS_DRIVER_BLOCKED_CRITICAL ||
  626. status == STATUS_DRIVER_BLOCKED) {
  627. IopDbgPrint((IOP_ERROR_LEVEL,
  628. "PiIsDriverBlocked: %wZ blocked from loading!!!\n", FullPath));
  629. fileName = wcsrchr(FullPath->Buffer, L'\\');
  630. if (fileName == NULL) {
  631. fileName = FullPath->Buffer;
  632. } else {
  633. fileName++;
  634. }
  635. PiLogDriverBlockedEvent(
  636. fileName,
  637. &entryInfo.guidID,
  638. sizeof(entryInfo.guidID),
  639. status);
  640. }
  641. //
  642. // Update the cache if neccessary.
  643. //
  644. if (status == STATUS_DRIVER_BLOCKED_CRITICAL ||
  645. status == STATUS_DRIVER_BLOCKED ||
  646. status == STATUS_SUCCESS) {
  647. //
  648. // Update our cache with the results.
  649. //
  650. PiUpdateDriverDBCache(
  651. FullPath,
  652. ImageBase,
  653. ImageSize,
  654. status,
  655. &entryInfo.guidID);
  656. }
  657. //
  658. // If the driver was blocked, return the entry GUID.
  659. //
  660. if ((status == STATUS_DRIVER_BLOCKED_CRITICAL ||
  661. status == STATUS_DRIVER_BLOCKED) && (ARGUMENT_PRESENT(EntryGuid))) {
  662. RtlCopyMemory(EntryGuid, &entryInfo.guidID, sizeof(GUID));
  663. }
  664. if (fileHandle != INVALID_HANDLE_VALUE) {
  665. ZwClose(fileHandle);
  666. }
  667. return status;
  668. }
  669. VOID
  670. PiLogDriverBlockedEvent(
  671. IN PWCHAR InsertionString,
  672. IN PVOID Data,
  673. IN ULONG DataLength,
  674. IN NTSTATUS Status
  675. )
  676. /*++
  677. Routine Description:
  678. This routine logs the driver block event.
  679. Arguments:
  680. FullPath - Full driver path
  681. Data - Data to be logged
  682. DataLength - Length of data (in bytes)
  683. Status - Status code to be logged
  684. Return Value:
  685. None.
  686. --*/
  687. {
  688. PWCHAR name;
  689. ULONG size, stringLength;
  690. PIO_ERROR_LOG_PACKET errorLogEntry;
  691. PAGED_CODE();
  692. stringLength = (wcslen(InsertionString) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
  693. size = (sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG)) +
  694. DataLength + stringLength;
  695. if (size <= ERROR_LOG_MAXIMUM_SIZE) {
  696. errorLogEntry = IoAllocateGenericErrorLogEntry((UCHAR)size);
  697. if (errorLogEntry) {
  698. RtlZeroMemory(errorLogEntry, size);
  699. errorLogEntry->ErrorCode = Status;
  700. errorLogEntry->FinalStatus = Status;
  701. errorLogEntry->DumpDataSize = (USHORT)DataLength;
  702. if (Data) {
  703. RtlCopyMemory(&errorLogEntry->DumpData[0], Data, DataLength);
  704. }
  705. errorLogEntry->NumberOfStrings = 1;
  706. errorLogEntry->StringOffset = (USHORT)(((PUCHAR)&errorLogEntry->DumpData[0] + errorLogEntry->DumpDataSize) - (PUCHAR)errorLogEntry);
  707. RtlCopyMemory(((PUCHAR)errorLogEntry + errorLogEntry->StringOffset), InsertionString, stringLength);
  708. IoWriteErrorLogEntry(errorLogEntry);
  709. }
  710. } else {
  711. ASSERT(size <= ERROR_LOG_MAXIMUM_SIZE);
  712. }
  713. }
  714. NTSTATUS
  715. PiInitializeDDBCache(
  716. VOID
  717. )
  718. /*++
  719. Routine Description:
  720. This routine initializes the RTL Generic table that is used as the cache
  721. layer on top of DDB.
  722. Arguments:
  723. None
  724. Return Value:
  725. None.
  726. --*/
  727. {
  728. PAGED_CODE();
  729. RtlInitializeGenericTable(
  730. &PiDDBCacheTable,
  731. PiCompareDDBCacheEntries,
  732. PiAllocateGenericTableEntry,
  733. PiFreeGenericTableEntry,
  734. NULL);
  735. return STATUS_SUCCESS;
  736. }
  737. RTL_GENERIC_COMPARE_RESULTS
  738. NTAPI
  739. PiCompareDDBCacheEntries(
  740. IN PRTL_GENERIC_TABLE Table,
  741. IN PVOID FirstStruct,
  742. IN PVOID SecondStruct
  743. )
  744. /*++
  745. Routine Description:
  746. This routine is the callback for the generic table routines.
  747. Arguments:
  748. Table - Table for which this is invoked.
  749. FirstStruct - An element in the table to compare.
  750. SecondStruct - Another element in the table to compare.
  751. Return Value:
  752. RTL_GENERIC_COMPARE_RESULTS.
  753. --*/
  754. {
  755. PDDBCACHE_ENTRY lhs = (PDDBCACHE_ENTRY)FirstStruct;
  756. PDDBCACHE_ENTRY rhs = (PDDBCACHE_ENTRY)SecondStruct;
  757. LONG result;
  758. PAGED_CODE();
  759. result = RtlCompareUnicodeString(&lhs->Name, &rhs->Name, TRUE);
  760. if (result < 0) {
  761. return GenericLessThan;
  762. } else if (result > 0) {
  763. return GenericGreaterThan;
  764. }
  765. if (!Table->TableContext) {
  766. //
  767. // Link date as other matching criteria.
  768. //
  769. if (lhs->TimeDateStamp < rhs->TimeDateStamp) {
  770. return GenericLessThan;
  771. } else if (lhs->TimeDateStamp > rhs->TimeDateStamp) {
  772. return GenericGreaterThan;
  773. }
  774. }
  775. return GenericEqual;
  776. }
  777. NTSTATUS
  778. PiLookupInDDBCache(
  779. IN PUNICODE_STRING FullPath,
  780. IN PVOID ImageBase,
  781. IN ULONG ImageSize,
  782. OUT LPGUID EntryGuid
  783. )
  784. /*++
  785. Routine Description:
  786. This routine looks up the driver in the DDB cache.
  787. Arguments:
  788. FullPath - Full driver path
  789. Header - Driver image header
  790. Return Value:
  791. NTSTATUS.
  792. --*/
  793. {
  794. NTSTATUS status;
  795. PDDBCACHE_ENTRY cachedEntry;
  796. DDBCACHE_ENTRY key;
  797. PIMAGE_NT_HEADERS header;
  798. PAGED_CODE();
  799. ASSERT(ARGUMENT_PRESENT(EntryGuid));
  800. status = STATUS_UNSUCCESSFUL;
  801. PiDDBCacheTable.TableContext = NULL;
  802. if (!RtlIsGenericTableEmpty(&PiDDBCacheTable)) {
  803. //
  804. // Lookup in the cache.
  805. //
  806. header = RtlImageNtHeader(ImageBase);
  807. key.Name.Buffer = wcsrchr(FullPath->Buffer, L'\\');
  808. if (!key.Name.Buffer) {
  809. key.Name.Buffer = FullPath->Buffer;
  810. }
  811. key.Name.Length = wcslen(key.Name.Buffer) * sizeof(WCHAR);
  812. key.Name.MaximumLength = key.Name.Length + sizeof(UNICODE_NULL);
  813. key.TimeDateStamp = header->FileHeader.TimeDateStamp;
  814. cachedEntry = (PDDBCACHE_ENTRY)RtlLookupElementGenericTable(
  815. &PiDDBCacheTable,
  816. &key);
  817. if (cachedEntry) {
  818. IopDbgPrint((IOP_WARNING_LEVEL,
  819. "PiLookupInDDBCache: Found cached entry for %ws (status = %08x)!\n",
  820. cachedEntry->Name.Buffer,
  821. cachedEntry->Status));
  822. status = cachedEntry->Status;
  823. if (ARGUMENT_PRESENT(EntryGuid)) {
  824. RtlCopyMemory(EntryGuid, &cachedEntry->Guid, sizeof(GUID));
  825. }
  826. }
  827. }
  828. return status;
  829. }
  830. VOID
  831. PiUpdateDriverDBCache(
  832. IN PUNICODE_STRING FullPath,
  833. IN PVOID ImageBase,
  834. IN ULONG ImageSize,
  835. IN NTSTATUS Status,
  836. IN GUID *Guid
  837. )
  838. /*++
  839. Routine Description:
  840. This routine updates the DDB cache with information about this driver.
  841. Arguments:
  842. FullPath - Full driver path
  843. Header - Driver image header
  844. Status - Lookup status to be cached.
  845. Return Value:
  846. NTSTATUS.
  847. --*/
  848. {
  849. PDDBCACHE_ENTRY cachedEntry;
  850. DDBCACHE_ENTRY key;
  851. PWCHAR name;
  852. PIMAGE_NT_HEADERS header;
  853. PAGED_CODE();
  854. header = RtlImageNtHeader(ImageBase);
  855. //
  856. // We only want to match using name while updating the cache.
  857. //
  858. PiDDBCacheTable.TableContext = (PVOID)1;
  859. key.Name = *FullPath;
  860. cachedEntry = (PDDBCACHE_ENTRY)RtlLookupElementGenericTable(
  861. &PiDDBCacheTable,
  862. &key);
  863. if (cachedEntry) {
  864. IopDbgPrint((IOP_INFO_LEVEL,
  865. "PiUpdateDriverDBCache: Found previously cached entry for %wZ with status=%08x!\n",
  866. &cachedEntry->Name,
  867. cachedEntry->Status));
  868. if (cachedEntry->Status != STATUS_SUCCESS) {
  869. PpBlockedDriverCount--;
  870. }
  871. //
  872. // Remove any previous entry.
  873. //
  874. name = cachedEntry->Name.Buffer;
  875. RtlDeleteElementGenericTable(&PiDDBCacheTable, &key);
  876. ExFreePool(name);
  877. }
  878. //
  879. // Cache the new entry.
  880. //
  881. key.Guid = *Guid;
  882. key.Status = Status;
  883. key.TimeDateStamp = header->FileHeader.TimeDateStamp;
  884. name = wcsrchr(FullPath->Buffer, L'\\');
  885. if (!name) {
  886. name = FullPath->Buffer;
  887. }
  888. key.Name.Length = key.Name.MaximumLength = wcslen(name) * sizeof(WCHAR);
  889. key.Name.Buffer = ExAllocatePool(PagedPool, key.Name.MaximumLength);
  890. if (key.Name.Buffer) {
  891. RtlCopyMemory(key.Name.Buffer, name, key.Name.Length);
  892. RtlInsertElementGenericTable(
  893. &PiDDBCacheTable,
  894. (PVOID)&key,
  895. (CLONG)sizeof(DDBCACHE_ENTRY),
  896. NULL);
  897. } else {
  898. IopDbgPrint((IOP_WARNING_LEVEL,
  899. "PiUpdateDriverDBCache: Could not allocate memory to update driver database cache!\n"));
  900. }
  901. if (Status != STATUS_SUCCESS) {
  902. PpBlockedDriverCount++;
  903. }
  904. }
  905. NTSTATUS
  906. PpGetBlockedDriverList(
  907. IN OUT GUID *Buffer,
  908. IN OUT PULONG Size,
  909. IN ULONG Flags
  910. )
  911. /*++
  912. Routine Description:
  913. This routine returns the MULTI_SZ list of currently blocked drivers.
  914. Arguments:
  915. Buffer - Recieves the MULTI_SZ list of drivers blocked.
  916. Size - Buffer size on input, the actual size gets returned in this (both in
  917. characters).
  918. Return Value:
  919. NTSTATUS.
  920. --*/
  921. {
  922. PDDBCACHE_ENTRY ptr;
  923. ULONG resultSize;
  924. GUID *result;
  925. NTSTATUS status;
  926. PAGED_CODE();
  927. resultSize = 0;
  928. //
  929. // Lock the database access.
  930. //
  931. KeEnterCriticalRegion();
  932. ExAcquireResourceExclusiveLite(&PiDDBLock, TRUE);
  933. //
  934. // Enumerate all entries in our cache and compute the buffer size to hold
  935. // the MULTI_SZ string.
  936. //
  937. for (ptr = (PDDBCACHE_ENTRY)RtlEnumerateGenericTable(&PiDDBCacheTable, TRUE);
  938. ptr != NULL;
  939. ptr = (PDDBCACHE_ENTRY)RtlEnumerateGenericTable(&PiDDBCacheTable, FALSE)) {
  940. if (ptr->Status != STATUS_SUCCESS) {
  941. resultSize += sizeof(GUID);
  942. }
  943. }
  944. if (*Size >= resultSize) {
  945. //
  946. // Enumerate all entries in our cache.
  947. //
  948. result = Buffer;
  949. for (ptr = (PDDBCACHE_ENTRY)RtlEnumerateGenericTable(&PiDDBCacheTable, TRUE);
  950. ptr != NULL;
  951. ptr = (PDDBCACHE_ENTRY)RtlEnumerateGenericTable(&PiDDBCacheTable, FALSE)) {
  952. if (ptr->Status != STATUS_SUCCESS) {
  953. *result = ptr->Guid;
  954. result++;
  955. }
  956. }
  957. *Size = resultSize;
  958. status = STATUS_SUCCESS;
  959. } else {
  960. *Size = resultSize;
  961. status = STATUS_BUFFER_TOO_SMALL;
  962. }
  963. //
  964. // Unlock the database.
  965. //
  966. ExReleaseResourceLite(&PiDDBLock);
  967. KeLeaveCriticalRegion();
  968. return status;
  969. }