1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #include <ntverp.h>
5 #include <strsafe.h>
6 #include <driverspecs.h>
7 
8 extern "C" {
9 #include "mx.h"
10 }
11 #include "fxmin.hpp"
12 #include <fxldrUm.h>
13 
14 #include <wdfcxbase.h>
15 #include "wdf20.h"
16 #include "wdf215.h"
17 
18 //
19 // This will cause inclusion of VfWdfFunctions table implementation from header
20 //
21 #define  VF_FX_DYNAMICS_GENERATE_TABLE   1
22 
23 
24 
25 
26 
27 #include "..\version\FxDynamics.h"
28 #include "..\version\vffxdynamics.h"
29 #include "FxLibraryCommon.h"
30 
31 #include "FxTelemetry.hpp"
32 
33 extern "C" {
34 //
35 // Global triage Info for dbgeng and 0x9F work
36 //
37 static WDFOBJECT_TRIAGE_INFO       _WdfObjectTriageInfo = {0};
38 static WDFCONTEXT_TRIAGE_INFO      _WdfContextTriageInfo = {0};
39 static WDFCONTEXTTYPE_TRIAGE_INFO  _WdfContextTypeTriageInfo = {0};
40 static WDFQUEUE_TRIAGE_INFO        _WdfQueueTriageInfo = {0};
41 static WDFIRPQUEUE_TRIAGE_INFO     _WdfIrpQueueTriageInfo = {0};
42 static WDFREQUEST_TRIAGE_INFO      _WdfRequestTriageInfo = {0};
43 static WDFDEVICE_TRIAGE_INFO       _WdfDeviceTriageInfo = {0};
44 static WDFIRP_TRIAGE_INFO          _WdfIrpTriageInfo = {0};
45 static WDFFWDPROGRESS_TRIAGE_INFO  _WdfFwdProgressTriageInfo = {0};
46 
47 WDF_TRIAGE_INFO g_WdfTriageInfo = {
48     //
49     // UMDF Version.
50     //
51     __WUDF_MAJOR_VERSION,
52     __WUDF_MINOR_VERSION,
53 
54     //
55     // Table Version.
56     //
57     WDF_01_TRIAGE_INFO_MAJOR_VERSION,
58     WDF_01_TRIAGE_INFO_MINOR_VERSION,
59 
60     //
61     // Reserved ptr (set to NULL).
62     //
63     NULL,
64 
65     //
66     // WDF objects triage info.
67     //
68     &_WdfObjectTriageInfo,
69     &_WdfContextTriageInfo,
70     &_WdfContextTypeTriageInfo,
71     &_WdfQueueTriageInfo,
72     &_WdfFwdProgressTriageInfo,
73     &_WdfIrpQueueTriageInfo,
74     &_WdfRequestTriageInfo,
75     &_WdfDeviceTriageInfo,
76     &_WdfIrpTriageInfo,
77 };
78 } // extern "C"
79 
80 VOID
81 GetTriageInfo(
82     VOID
83     )
84 {
85     // Object
86     _WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject);
87     _WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type);
88     _WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize);
89     _WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead);
90     _WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry);
91     _WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals);
92     _WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject);
93 
94     // Context Triage Info
95     _WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader);
96     _WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader);
97     _WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object);
98     _WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo);
99     _WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context);
100 
101     // Context type Triage info
102     _WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO);
103     _WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize);
104     _WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName);
105 
106     // WdfRequest Queue
107     _WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue);
108     _WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue);
109     _WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable);
110     _WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled);
111     _WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList);
112     _WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext);
113     _WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo);
114 
115     // Forward Progress
116     _WdfFwdProgressTriageInfo.ReservedRequestList =
117         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList);
118     _WdfFwdProgressTriageInfo.ReservedRequestInUseList =
119         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList);
120     _WdfFwdProgressTriageInfo.PendedIrpList =
121         FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList);
122 
123     // Irp Queue
124     _WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue);
125     _WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue);
126 
127 
128 
129 
130 
131 
132 
133 
134 
135     _WdfIrpQueueTriageInfo.IrpListEntry = 0;
136     _WdfIrpQueueTriageInfo.IrpContext = 0;
137 
138     // WdfRequest
139     _WdfRequestTriageInfo.RequestSize = sizeof(FxRequest);
140     _WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext);
141     _WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp);
142     _WdfRequestTriageInfo.ListEntryQueueOwned =
143         FIELD_OFFSET(FxRequest, m_OwnerListEntry);
144     _WdfRequestTriageInfo.ListEntryQueueOwned2 =
145         FIELD_OFFSET(FxRequest, m_OwnerListEntry2);
146     _WdfRequestTriageInfo.RequestListEntry =
147         FIELD_OFFSET(FxRequest, m_ListEntry);
148     _WdfRequestTriageInfo.FwdProgressList =
149         FIELD_OFFSET(FxRequest, m_ForwardProgressList);
150 
151     // WdfDevice
152     _WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT);
153     _WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver);
154 
155     // FxIrp
156     _WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp);
157     _WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp);
158 }
159 
160 NTSTATUS
161 FxLibraryCommonCommission(
162     VOID
163     )
164 {
165     NTSTATUS   status;
166 
167     __Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n"));
168 
169     //
170     // Commission this version's DLL globals.
171     //
172     status = FxLibraryGlobalsCommission();
173     if (!NT_SUCCESS(status)) {
174         __Print(("FxLibraryGlobalsCommission failed %X\n", status));
175         return status;
176     }
177 
178     //
179     // register for ETW tracing.
180     //
181     RegisterTelemetryProvider();
182 
183     //
184     // Initialize internal WPP tracing.
185     //
186     status = FxTraceInitialize();
187     if (NT_SUCCESS(status)) {
188         FxLibraryGlobals.InternalTracingInitialized = TRUE;
189     }
190     else {
191         __Print(("Failed to initialize tracing for WDF\n"));
192 
193         //
194         // Failure to initialize is not critical enough to fail driver load.
195         //
196         status = STATUS_SUCCESS;
197     }
198 
199     return status;
200 }
201 
202 NTSTATUS
203 FxLibraryCommonDecommission(
204     VOID
205     )
206 {
207     __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n"));
208 
209     //
210     // Uninitialize WPP tracing.
211     //
212     if (FxLibraryGlobals.InternalTracingInitialized) {
213         TraceUninitialize();
214         FxLibraryGlobals.InternalTracingInitialized = FALSE;
215     }
216 
217     //
218     // Unregister telemetry provider.
219     //
220     UnregisterTelemetryProvider();
221 
222     EventUnregisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance();
223 
224     //
225     // Decommission this version's DLL globals.
226     //
227     FxLibraryGlobalsDecommission();
228 
229     //
230     // Note: This is the absolute last action from WDF library (dynamic or static).
231     //       The image is likely to be deleted after returning.
232     //
233     __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n"));
234 
235     return STATUS_SUCCESS;
236 }
237 
238 
239 NTSTATUS
240 FxLibraryCommonRegisterClient(
241     PWDF_BIND_INFO        Info,
242     PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
243     PCLIENT_INFO          ClientInfo
244     )
245 {
246     NTSTATUS           status;
247 
248     status = STATUS_INVALID_PARAMETER;
249 
250     __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
251 
252     ASSERT(Info != NULL && Info->FuncCount != 0);
253     ASSERT(WdfDriverGlobals != 0);
254 
255     if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) {
256         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
257                  ": NULL parameter -- %s\n",
258                  (Info == NULL)             ? "PWDF_BIND_INFO" :
259                  (WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" :
260                  (Info->FuncTable == NULL)  ? "PWDF_BIND_INFO->FuncTable" :
261                                               "unknown" ));
262         goto Done;
263     }
264 
265     *WdfDriverGlobals = NULL;
266 
267     ASSERT(Info->FuncCount <= WdfVersion.FuncCount);
268 
269     //
270     // WdfVersion.Count is initialized in FxDynamics.h and is never changed.
271     // Prefast is unable to make that determination.
272     //
273     __assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID));
274 
275     if (Info->FuncCount > WdfVersion.FuncCount) {
276         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
277                  ": version mismatch detected in function table count: client"
278                  "has 0x%x,  library has 0x%x\n",
279                  Info->FuncCount, WdfVersion.FuncCount));
280         goto Done;
281     }
282 
283     if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_15) {
284 
285         switch (Info->FuncCount) {
286 
287         case WdfFunctionTableNumEntries_V2_15:
288         case WdfFunctionTableNumEntries_V2_0:
289             break;
290 
291         default:
292             __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
293                      ": Function table count 0x%x doesn't match any previously "
294                      "released framework version table size\n",
295                      Info->FuncCount));
296             goto Done;
297         }
298     }
299     else {
300         //
301         // Client version is same as framework version. Make
302         // sure table count is exact.
303         //
304         // Note that in order for build-to-build upgrade to work, the following
305         // check should be commented out during active development.
306         //
307         // DO CHANGE it to a real failure towards the tail end of release to
308         // prevent cases where a driver sneaks out into public after being built
309         // with a non-RTM version of WDF and has a function count less than the
310         // final count. An HCK test has been added to ensure such drivers are
311         // caught early. This check is an additional prevention.
312         //
313         if (Info->FuncCount != WdfFunctionTableNumEntries) {
314             __Print(("Framework function table size (%d) doesn't match "
315                    "with client (%d). Rebuild the client driver.",
316                    WdfFunctionTableNumEntries, Info->FuncCount));
317 
318             ASSERT(FALSE);
319             goto Done;
320         }
321     }
322 
323     //
324     // Allocate an new FxDriverGlobals area for this driver.
325     //
326     *WdfDriverGlobals = FxAllocateDriverGlobals();
327 
328     if (*WdfDriverGlobals) {
329         BOOLEAN isFunctinTableHookingOn  = FALSE;
330         BOOLEAN isPerformanceAnalysisOn  = FALSE;
331         PFX_DRIVER_GLOBALS fxDriverGlobals = NULL;
332         //
333         // Check the registry to see if Enhanced verifier is on for this driver.
334         // if registry read fails, options value remains unchanged.
335         // store enhanced verifier options in driver globals
336         //
337         fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
338         GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions);
339         isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals);
340         isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals);
341 
342         //
343         // Set-up the function table. Enhanced verifier and Performance analysis is off by default.
344         //
345         if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) {
346             //
347             // Set-up the function table
348             //
349             // Starting in 2.15 we reference a copy of the DDI table in WDF01000,
350             // prior to that we copy the entire table to local memory.
351             //
352             if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) {
353                 RtlCopyMemory( Info->FuncTable,
354                                &WdfVersion.Functions,
355                                Info->FuncCount * sizeof(PVOID) );
356             }
357             else {
358                 //
359                 // FuncTable arrives with a ptr to &WdfFunctions, so we update
360                 // what WdfFunctions points to
361                 //
362                 *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions;
363             }
364         }
365         else {
366             __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
367                      ": Enhanced Verification is ON \n"));
368 
369             if (Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle == NULL)
370             {
371                 EventRegisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance();
372             }
373 
374             //
375             // Enhanced verification is on. Return verifier function table
376             //
377             // Starting in 1.15 we reference a copy of the DDI table in WDF01000,
378             // prior to that we copy the entire table to local memory.
379             //
380             if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) {
381                 RtlCopyMemory( Info->FuncTable,
382                                &VfWdfVersion.Functions,
383                                Info->FuncCount * sizeof(PVOID) );
384             }
385             else {
386                 //
387                 // FuncTable arrives with a ptr to &WdfFunctions, so we update
388                 // what WdfFunctions points to.
389                 //
390                 *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions;
391             }
392         }
393 
394         status = STATUS_SUCCESS;
395 
396         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
397                  ": WdfFunctions %p\n", Info->FuncTable));
398     }
399 
400 Done:
401     __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
402              ": exit: status %X\n", status));
403 
404     if (!NT_SUCCESS(status)) {
405         FX_VERIFY(DRIVER(BadArgument, TODO),
406             TRAPMSG("Version mismatch detected in function table count. Recompile"
407             " driver with correct headers"));
408     }
409 
410     return status;
411 }
412 
413 NTSTATUS
414 FxLibraryCommonUnregisterClient(
415     PWDF_BIND_INFO        Info,
416     PWDF_DRIVER_GLOBALS   WdfDriverGlobals
417     )
418 {
419     NTSTATUS status;
420 
421     __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n"));
422 
423     ASSERT(Info != NULL);
424     ASSERT(WdfDriverGlobals != NULL);
425 
426     if (Info != NULL && WdfDriverGlobals != NULL) {
427         PFX_DRIVER_GLOBALS pFxDriverGlobals;
428 
429         status = STATUS_SUCCESS;
430 
431         pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals);
432 
433         //
434         // Destroy this FxDriver instance, if its still indicated.
435         //
436         if (pFxDriverGlobals->Driver != NULL) {
437             //
438             // Association support, we are a root with no parent
439             //
440             pFxDriverGlobals->Driver->DeleteObject();
441 
442             FxDestroy(pFxDriverGlobals);
443         }
444 
445         //
446         // Stop IFR logging
447         //
448         FxIFRStop(pFxDriverGlobals);
449 
450         //
451         // This will free the client's FxDriverGlobals area
452         //
453         FxFreeDriverGlobals(WdfDriverGlobals);
454     }
455     else {
456         status = STATUS_UNSUCCESSFUL;
457     }
458 
459     __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT)
460              ": exit: status %X\n", status));
461 
462     return status;
463 }
464 
465 VOID
466 GetEnhancedVerifierOptions(
467     PCLIENT_INFO ClientInfo,
468     PULONG Options
469     )
470 {
471     NTSTATUS status;
472     ULONG value;
473     FxAutoRegKey hWdf;
474     DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME);
475 
476     *Options = 0;
477     if (ClientInfo == NULL                       ||
478         ClientInfo->Size != sizeof(CLIENT_INFO)  ||
479         ClientInfo->RegistryPath == NULL         ||
480         ClientInfo->RegistryPath->Length == 0    ||
481         ClientInfo->RegistryPath->Buffer == NULL ||
482         Options == NULL) {
483 
484         __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
485                  ": Invalid ClientInfo received from wudfldr \n"));
486         return;
487     }
488 
489     status = FxRegKey::_OpenKey(NULL,
490                                 ClientInfo->RegistryPath,
491                                 &hWdf.m_Key,
492                                 KEY_READ);
493     if (!NT_SUCCESS(status)) {
494         return;
495     }
496 
497     status = FxRegKey::_QueryULong(
498         hWdf.m_Key, &valueName, &value);
499 
500     //
501     // Examine key values and set Options only on success.
502     //
503     if (NT_SUCCESS(status)) {
504         if (value) {
505             *Options = value;
506         }
507     }
508 }
509