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.

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