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 ¶metersPath,
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