1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 
5 extern "C" {
6 #include <ntddk.h>
7 }
8 
9 //
10 // This will cause inclusion of VfWdfFunctions table implementation from header
11 //
12 #define  VF_FX_DYNAMICS_GENERATE_TABLE   1
13 
14 //
15 // Compute the length based on the max. service name length and the rest of the
16 // error string as seen in ReportDdiFunctionCountMismatch
17 //
18 #define EVTLOG_DDI_COUNT_ERROR_MAX_LEN (53 + MAX_PATH)
19 
20 #include "fx.hpp"
21 #include "fxldr.h"
22 #include "fxlibrarycommon.h"
23 #include "fxtelemetry.hpp"
24 #include "wdfversionlog.h"
25 #include "minwindef.h"
26 
27 extern "C" {
28 //
29 // Global triage Info for dbgeng and 0x9F work
30 //
31 static WDFOBJECT_TRIAGE_INFO       _WdfObjectTriageInfo = {0};
32 static WDFCONTEXT_TRIAGE_INFO      _WdfContextTriageInfo = {0};
33 static WDFCONTEXTTYPE_TRIAGE_INFO  _WdfContextTypeTriageInfo = {0};
34 static WDFQUEUE_TRIAGE_INFO        _WdfQueueTriageInfo = {0};
35 static WDFIRPQUEUE_TRIAGE_INFO     _WdfIrpQueueTriageInfo = {0};
36 static WDFREQUEST_TRIAGE_INFO      _WdfRequestTriageInfo = {0};
37 static WDFDEVICE_TRIAGE_INFO       _WdfDeviceTriageInfo = {0};
38 static WDFIRP_TRIAGE_INFO          _WdfIrpTriageInfo = {0};
39 static WDFFWDPROGRESS_TRIAGE_INFO  _WdfFwdProgressTriageInfo = {0};
40 
41 WDF_TRIAGE_INFO g_WdfTriageInfo = {
42     //
43     // KMDF Version.
44     //
45     __WDF_MAJOR_VERSION,
46     __WDF_MINOR_VERSION,
47 
48     //
49     // Table Version.
50     //
51     WDF_01_TRIAGE_INFO_MAJOR_VERSION,
52     WDF_01_TRIAGE_INFO_MINOR_VERSION,
53 
54     //
55     // Reserved ptr (set to NULL).
56     //
57     NULL,
58 
59     //
60     // WDF objects triage info.
61     //
62     &_WdfObjectTriageInfo,
63     &_WdfContextTriageInfo,
64     &_WdfContextTypeTriageInfo,
65     &_WdfQueueTriageInfo,
66     &_WdfFwdProgressTriageInfo,
67     &_WdfIrpQueueTriageInfo,
68     &_WdfRequestTriageInfo,
69     &_WdfDeviceTriageInfo,
70     &_WdfIrpTriageInfo,
71 };
72 } // extern "C"
73 
74 VOID
GetTriageInfo(VOID)75 GetTriageInfo(
76     VOID
77     )
78 {
79     // Object
80     _WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject);
81     _WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type);
82     _WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize);
83     _WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead);
84     _WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry);
85     _WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals);
86     _WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject);
87 
88     // Context Triage Info
89     _WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader);
90     _WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader);
91     _WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object);
92     _WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo);
93     _WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context);
94 
95     // Context type Triage info
96     _WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO);
97     _WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize);
98     _WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName);
99 
100     // WdfRequest Queue
101     _WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue);
102     _WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue);
103     _WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable);
104     _WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled);
105     _WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList);
106     _WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext);
107     _WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo);
108 
109     // Forward Progress
110     _WdfFwdProgressTriageInfo.ReservedRequestList =
111         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList);
112     _WdfFwdProgressTriageInfo.ReservedRequestInUseList =
113         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList);
114     _WdfFwdProgressTriageInfo.PendedIrpList =
115         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList);
116 
117     // Irp Queue
118     _WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue);
119     _WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue);
120     _WdfIrpQueueTriageInfo.IrpListEntry = FIELD_OFFSET(IRP, Tail.Overlay.ListEntry);
121     _WdfIrpQueueTriageInfo.IrpContext = FIELD_OFFSET(IRP,
122         Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY]);
123 
124     // WdfRequest
125     _WdfRequestTriageInfo.RequestSize = sizeof(FxRequest);
126     _WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext);
127     _WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp);
128     _WdfRequestTriageInfo.ListEntryQueueOwned =
129         FIELD_OFFSET(FxRequest, m_OwnerListEntry);
130     _WdfRequestTriageInfo.ListEntryQueueOwned2 =
131         FIELD_OFFSET(FxRequest, m_OwnerListEntry2);
132     _WdfRequestTriageInfo.RequestListEntry =
133         FIELD_OFFSET(FxRequest, m_ListEntry);
134     _WdfRequestTriageInfo.FwdProgressList =
135         FIELD_OFFSET(FxRequest, m_ForwardProgressList);
136 
137     // WdfDevice
138     _WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT);
139     _WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver);
140 
141     // FxIrp
142     _WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp);
143     _WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp);
144 }
145 
146 BOOLEAN
IsClientInfoValid(_In_ PCLIENT_INFO ClientInfo)147 IsClientInfoValid(
148     _In_ PCLIENT_INFO ClientInfo
149     )
150 {
151     if (ClientInfo == NULL ||
152         ClientInfo->Size != sizeof(CLIENT_INFO) ||
153         ClientInfo->RegistryPath == NULL ||
154         ClientInfo->RegistryPath->Length == 0 ||
155         ClientInfo->RegistryPath->Buffer == NULL) {
156         return FALSE;
157     }
158     return TRUE;
159 }
160 
161 VOID
ReportDdiFunctionCountMismatch(_In_ PCUNICODE_STRING ServiceName,_In_ ULONG ActualFunctionCount,_In_ ULONG ExpectedFunctionCount)162 ReportDdiFunctionCountMismatch(
163     _In_ PCUNICODE_STRING ServiceName,
164     _In_ ULONG ActualFunctionCount,
165     _In_ ULONG ExpectedFunctionCount
166     )
167 {
168     WCHAR    insertString[EVTLOG_DDI_COUNT_ERROR_MAX_LEN] = { 0 };
169     NTSTATUS status;
170 
171     //
172     // NOTE: Any single call to DbgPrintEx will only transmit 512 bytes of
173     // information.
174     //
175     DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL,
176             "\n\n************************* \n"
177             "* DDI function table mismatch detected in KMDF driver. The \n"
178             "* driver will not load until it is re-compiled using a \n"
179             "* newer version of the Windows Driver Kit (WDK). \n"
180             );
181 
182     DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL,
183             "* Service name                 : %wZ\n"
184             "* Actual function table count  : %d \n"
185             "* Expected function table count: %d \n"
186             "*************************** \n\n",
187             ServiceName,
188             ActualFunctionCount,
189             ExpectedFunctionCount
190             );
191 
192     //
193     // Report a warning level ETW event to the system event log. "Wdf01000" is
194     // the listed event provider.
195     //
196     status = RtlStringCchPrintfW(insertString,
197                             RTL_NUMBER_OF(insertString),
198                             L"Service:%wZ Count:Actual %d Expected %d",
199                             ServiceName,
200                             ActualFunctionCount,
201                             ExpectedFunctionCount);
202     if (NT_SUCCESS(status)) {
203         LibraryLogEvent(FxLibraryGlobals.DriverObject,
204                     WDFVER_CLIENT_INVALID_DDI_COUNT,
205                     STATUS_INVALID_PARAMETER,
206                     insertString,
207                     NULL,
208                     0);
209     }
210 
211     //
212     // Report a telemetry event that can be used to proactively fix drivers
213     //
214     TraceLoggingWrite(g_TelemetryProvider,
215                     "KmdfClientFunctionCountMismatch",
216                     WDF_TELEMETRY_EVT_KEYWORDS,
217                     TraceLoggingUnicodeString(ServiceName, "ServiceName"),
218                     TraceLoggingUInt32(ActualFunctionCount, "FunctionCount"),
219                     TraceLoggingUInt32(ExpectedFunctionCount, "ExpectedCount"));
220 }
221 
222 _Must_inspect_result_
223 NTSTATUS
FxLibraryCommonCommission(VOID)224 FxLibraryCommonCommission(
225     VOID
226     )
227 {
228     DECLARE_CONST_UNICODE_STRING(usName, L"RtlGetVersion");
229     PFN_RTL_GET_VERSION pRtlGetVersion = NULL;
230     NTSTATUS   status;
231 
232     __Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n"));
233 
234     //
235     // Commission this version's DLL globals.
236     //
237     status = FxLibraryGlobalsCommission();
238 
239     if (!NT_SUCCESS(status)) {
240         __Print(("FxLibraryGlobalsCommission failed %X\n", status));
241         return status;
242     }
243 
244     //
245     // register telemetry provider.
246     //
247     RegisterTelemetryProvider();
248 
249     //
250     // Initialize internal WPP tracing.
251     //
252     status = FxTraceInitialize();
253     if (NT_SUCCESS(status)) {
254         FxLibraryGlobals.InternalTracingInitialized = TRUE;
255     }
256     else {
257         __Print(("Failed to initialize tracing for WDF\n"));
258 
259         //
260         // Failure to initialize is not critical enough to fail driver load.
261         //
262         status = STATUS_SUCCESS;
263     }
264 
265     //
266     // Attempt to load RtlGetVersion (works for > w2k).
267     //
268     pRtlGetVersion = (PFN_RTL_GET_VERSION) MmGetSystemRoutineAddress(
269         (PUNICODE_STRING) &usName
270         );
271 
272     //
273     // Now attempt to get this OS's version.
274     //
275     if (pRtlGetVersion != NULL) {
276         pRtlGetVersion(&gOsVersion);
277     }
278 
279     __Print(("OsVersion(%d.%d)\n",
280              gOsVersion.dwMajorVersion,
281              gOsVersion.dwMinorVersion ));
282 
283     //
284     // Init triage info for 9f bugcheck analysis.
285     //
286     GetTriageInfo();
287 
288     return STATUS_SUCCESS;
289 }
290 
291 _Must_inspect_result_
292 NTSTATUS
FxLibraryCommonDecommission(VOID)293 FxLibraryCommonDecommission(
294     VOID
295     )
296 {
297     __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n"));
298 
299     //
300     // Uninitialize WPP tracing.
301     //
302     if (FxLibraryGlobals.InternalTracingInitialized) {
303         TraceUninitialize();
304         FxLibraryGlobals.InternalTracingInitialized = FALSE;
305     }
306 
307     //
308     // Unregister telemetry provider.
309     //
310     UnregisterTelemetryProvider();
311 
312     EventUnregisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance();
313 
314     //
315     // Decommission this version's DLL globals.
316     //
317     FxLibraryGlobalsDecommission();
318 
319     //
320     // Note: This is the absolute last action from WDF library (dynamic or static).
321     //       The image is likely to be deleted after returning.
322     //
323     __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n"));
324 
325     return STATUS_SUCCESS;
326 }
327 
328 _Must_inspect_result_
329 NTSTATUS
FxLibraryCommonRegisterClient(__inout PWDF_BIND_INFO Info,__deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals,__in_opt PCLIENT_INFO ClientInfo)330 FxLibraryCommonRegisterClient(
331     __inout PWDF_BIND_INFO        Info,
332     __deref_out PWDF_DRIVER_GLOBALS *WdfDriverGlobals,
333     __in_opt PCLIENT_INFO          ClientInfo
334     )
335 {
336     NTSTATUS           status;
337     UNICODE_STRING serviceName = { 0 };
338 
339     status = STATUS_INVALID_PARAMETER;
340 
341     __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
342 
343     if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) {
344         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
345                  ": NULL parameter -- %s\n",
346                  (Info == NULL)             ? "PWDF_BIND_INFO" :
347                  (WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" :
348                  (Info->FuncTable == NULL)  ? "PWDF_BIND_INFO->FuncTable" :
349                                               "unknown" ));
350         goto Done;
351     }
352 
353     ASSERT(Info->FuncCount);
354 
355 
356     *WdfDriverGlobals = NULL;
357 
358     //
359     // WdfVersion.Count is initialized in FxDynamics.h and is never changed.
360     // Prefast is unable to make that determination.
361     //
362     __assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID));
363 
364     if (Info->FuncCount > WdfVersion.FuncCount) {
365         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
366                  ": version mismatch detected in function table count: client"
367                  "has 0x%x,  library has 0x%x\n",
368                  Info->FuncCount, WdfVersion.FuncCount));
369         goto Done;
370     }
371 
372     if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_15) {
373         //
374         // Make sure table count matches exactly with previously
375         // released framework version table sizes.
376         //
377         switch (Info->FuncCount) {
378 
379         case WdfFunctionTableNumEntries_V1_15:
380         case WdfFunctionTableNumEntries_V1_13:
381         case WdfFunctionTableNumEntries_V1_11:
382         case WdfFunctionTableNumEntries_V1_9:
383      // case WdfFunctionTableNumEntries_V1_7:  // both 1.7 and 1.5 have 387 functions
384         case WdfFunctionTableNumEntries_V1_5:
385         case WdfFunctionTableNumEntries_V1_1:
386         case WdfFunctionTableNumEntries_V1_0:
387             break;
388 
389         default:
390             __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
391                      ": Function table count 0x%x doesn't match any previously "
392                      "released framework version table size\n",
393                      Info->FuncCount));
394             goto Done;
395         }
396     }
397     else {
398 
399 
400 
401 
402 
403 
404 
405 
406         // Client version is same as framework version. Make
407         // sure table count is exact.
408         if (Info->FuncCount != WdfFunctionTableNumEntries) {
409             RtlZeroMemory(&serviceName, sizeof(UNICODE_STRING));
410 
411             if (IsClientInfoValid(ClientInfo)) {
412                 GetNameFromPath(ClientInfo->RegistryPath, &serviceName);
413             }
414             else {
415                 RtlInitUnicodeString(&serviceName, L"Unknown");
416             }
417 
418             //
419             // Report a DbgPrint message, telemetry event and an ETW event that
420             // will serve as diagnostic aid.
421             //
422             ReportDdiFunctionCountMismatch((PCUNICODE_STRING)&serviceName,
423                                         Info->FuncCount,
424                                         WdfFunctionTableNumEntries);
425 
426             //
427             // If loader diagnostics are enabled and KD is connected, break-in
428             //
429             if (WdfLdrDbgPrintOn && KD_DEBUGGER_ENABLED &&
430                 !KD_DEBUGGER_NOT_PRESENT) {
431                 DbgBreakPoint();
432             }
433             goto Done;
434         }
435     }
436 
437     //
438     // Allocate an new FxDriverGlobals area for this driver.
439     //
440     *WdfDriverGlobals = FxAllocateDriverGlobals();
441 
442     if (*WdfDriverGlobals) {
443         BOOLEAN isFunctinTableHookingOn  = FALSE;
444         BOOLEAN isPerformanceAnalysisOn  = FALSE;
445         PFX_DRIVER_GLOBALS fxDriverGlobals = NULL;
446 
447         //
448         // Check the registry to see if Enhanced verifier is on for this driver.
449         // if registry read fails, options value remains unchanged.
450         // store enhanced verifier options in driver globals
451         //
452         fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
453         GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions);
454         isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals);
455         isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals);
456 
457         //
458         // Set-up the function table. Enhanced verifier and Performance analysis is off by default.
459         //
460         if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) {
461 
462             //
463             // Starting in 1.15 we reference a copy of the DDI table in WDF01000,
464             // prior to that we copy the entire table to local memory.
465             //
466             if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) {
467                 RtlCopyMemory( Info->FuncTable,
468                                &WdfVersion.Functions,
469                                Info->FuncCount * sizeof(PVOID) );
470             }
471             else {
472                 //
473                 // FuncTable arrives with a ptr to &WdfFunctions, so we update
474                 // what WdfFunctions points to.
475                 //
476                 *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions;
477             }
478         }
479         else {
480             __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
481                      ": Enhanced Verification is ON \n"));
482 
483             LockVerifierSection(fxDriverGlobals, ClientInfo->RegistryPath);
484 
485             if (Microsoft_Windows_DriverFrameworks_KernelMode_PerformanceHandle == NULL) {
486                 EventRegisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance();
487             }
488 
489             //
490             // Enhanced verification is on. Return verifier function table
491             //
492             // Starting in 1.15 we reference a copy of the DDI table in WDF01000,
493             // prior to that we copy the entire table to local memory.
494             //
495             if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) {
496                 RtlCopyMemory( Info->FuncTable,
497                                &VfWdfVersion.Functions,
498                                Info->FuncCount * sizeof(PVOID) );
499             }
500             else {
501                 //
502                 // FuncTable arrives with a ptr to &WdfFunctions, so we update
503                 // what WdfFunctions points to.
504                 //
505                 *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions;
506             }
507         }
508 
509         status = STATUS_SUCCESS;
510 
511         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
512                  ": WdfFunctions %p\n", Info->FuncTable));
513     }
514 
515 Done:
516     __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
517              ": exit: status %X\n", status));
518 
519     return status;
520 }
521 
522 _Must_inspect_result_
523 NTSTATUS
FxLibraryCommonUnregisterClient(__in PWDF_BIND_INFO Info,__in PWDF_DRIVER_GLOBALS WdfDriverGlobals)524 FxLibraryCommonUnregisterClient(
525     __in PWDF_BIND_INFO        Info,
526     __in PWDF_DRIVER_GLOBALS   WdfDriverGlobals
527     )
528 {
529     NTSTATUS status;
530 
531     __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n"));
532 
533     ASSERT(Info);
534     ASSERT(WdfDriverGlobals);
535 
536     if (Info != NULL && WdfDriverGlobals != NULL) {
537         PFX_DRIVER_GLOBALS pFxDriverGlobals;
538 
539         status = STATUS_SUCCESS;
540 
541         pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals);
542 
543         //
544         // Destroy this FxDriver instance, if its still indicated.
545         //
546         if (pFxDriverGlobals->Driver != NULL) {
547             //
548             // Association support, we are a root with no parent
549             //
550             pFxDriverGlobals->Driver->DeleteObject();
551 
552             FxDestroy(pFxDriverGlobals);
553         }
554 
555         //
556         // Stop IFR logging
557         //
558         FxIFRStop(pFxDriverGlobals);
559 
560         //
561         // unlock enhanced-verifier image sections
562         //
563         if (IsFxVerifierFunctionTableHooking(pFxDriverGlobals)) {
564             UnlockVerifierSection(pFxDriverGlobals);
565         }
566 
567         //
568         // This will free the client's FxDriverGlobals area
569         //
570         FxFreeDriverGlobals(WdfDriverGlobals);
571     }
572     else {
573         status = STATUS_UNSUCCESSFUL;
574     }
575 
576     __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT)
577              ": exit: status %X\n", status));
578 
579     return status;
580 }
581 
582 VOID
GetEnhancedVerifierOptions(__in PCLIENT_INFO ClientInfo,__out PULONG Options)583 GetEnhancedVerifierOptions(
584     __in PCLIENT_INFO ClientInfo,
585     __out PULONG Options
586     )
587 {
588     NTSTATUS status;
589     ULONG value;
590     FxAutoRegKey hKey, hWdf;
591     DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
592     DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME);
593 
594     *Options = 0;
595     if (!IsClientInfoValid(ClientInfo) ||
596         Options == NULL) {
597 
598         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
599                  ": Invalid ClientInfo received from wdfldr \n"));
600         return;
601     }
602 
603     status = FxRegKey::_OpenKey(NULL,
604                                 ClientInfo->RegistryPath,
605                                 &hWdf.m_Key,
606                                 KEY_READ);
607     if (!NT_SUCCESS(status)) {
608         return;
609     }
610 
611     status = FxRegKey::_OpenKey(hWdf.m_Key,
612                                 &parametersPath,
613                                 &hKey.m_Key,
614                                 KEY_READ);
615     if (!NT_SUCCESS(status)) {
616         return;
617     }
618 
619     status = FxRegKey::_QueryULong(
620         hKey.m_Key, &valueName, &value);
621 
622     //
623     // Examine key values and set Options only on success.
624     //
625     if (NT_SUCCESS(status)) {
626         if (value) {
627             *Options = value;
628         }
629     }
630 }
631 
632 VOID
LibraryLogEvent(__in PDRIVER_OBJECT DriverObject,__in NTSTATUS ErrorCode,__in NTSTATUS FinalStatus,__in PWSTR ErrorInsertionString,__in_bcount (RawDataLen)PVOID RawDataBuf,__in USHORT RawDataLen)633 LibraryLogEvent(
634     __in PDRIVER_OBJECT DriverObject,
635     __in NTSTATUS       ErrorCode,
636     __in NTSTATUS       FinalStatus,
637     __in PWSTR          ErrorInsertionString,
638     __in_bcount(RawDataLen) PVOID    RawDataBuf,
639     __in USHORT         RawDataLen
640     )
641 /*++
642 
643 
644 Routine Description:
645 
646     Logs an error to the system event log.
647 
648     Arguments:
649 
650     DriverObject - Pointer to driver object reporting the error.
651 
652     ErrorCode    - Indicates the type of error, system or driver-defined.
653 
654     ErrorInsertionString - Null-terminated Unicode string inserted into error
655     description, as defined by error code.
656 
657 Return Value:
658 
659 None.
660 
661 --*/
662 {
663     PIO_ERROR_LOG_PACKET errorLogEntry;
664     size_t               errorLogEntrySize;                  // [including null]
665     size_t               errorInsertionStringByteSize = 0;
666 
667     if (ErrorInsertionString) {
668         errorInsertionStringByteSize = wcslen(ErrorInsertionString) * sizeof(WCHAR);
669         errorInsertionStringByteSize += sizeof(UNICODE_NULL);
670     }
671 
672     errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen + errorInsertionStringByteSize;
673 
674     //
675     // Log an error.
676     //
677     //
678     // prefast complains about comparison of constant with constant here
679     //
680 #pragma prefast(suppress:__WARNING_CONST_CONST_COMP, "If ErrorInsertionString is not null then this is not a constant")
681     if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
682 
683         errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DriverObject,
684             (UCHAR)errorLogEntrySize);
685 
686         if (errorLogEntry != NULL) {
687 
688             RtlZeroMemory(errorLogEntry, errorLogEntrySize);
689 
690             errorLogEntry->ErrorCode = ErrorCode;
691             errorLogEntry->FinalStatus = FinalStatus;
692             errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
693             errorLogEntry->DumpDataSize = RawDataLen;
694             errorLogEntry->StringOffset = (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) + errorLogEntry->DumpDataSize;
695 
696             //
697             // Insertion strings follow dumpdata and since there is no dumpdata we place the
698             // insertion string at the start offset of the dumpdata.
699             //
700             if (RawDataBuf) {
701                 RtlCopyMemory(errorLogEntry->DumpData,
702                     RawDataBuf,
703                     RawDataLen);
704             }
705 
706             if (ErrorInsertionString) {
707                 RtlCopyMemory(((PCHAR)errorLogEntry->DumpData) + RawDataLen,
708                     ErrorInsertionString,
709                     errorInsertionStringByteSize);
710             }
711 
712             IoWriteErrorLogEntry(errorLogEntry);
713         }
714     }
715 
716     return;
717 }
718