1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxVerifierLock.hpp
8 
9 Abstract:
10 
11     This is the C++ header for the verifier FxLock
12 
13     This separate object allows the verifier overhead
14     to only be allocated when WdfVerifierLock is on.
15 
16 Author:
17 
18 
19 
20 Revision History:
21 
22 
23         Made it mode agnostic
24 
25         New failure paths:
26             m_Mutex/m_Lock initialize
27             To enforce initialization hidden constructors
28             Callers are forced to use CreateAndInitialize methods
29 
30 --*/
31 
32 #ifndef _FXVERIFIERLOCK_HPP_
33 #define _FXVERIFIERLOCK_HPP_
34 
35 extern "C" {
36 #if defined(EVENT_TRACING)
37 #include "FxVerifierLock.hpp.tmh"
38 #endif
39 }
40 
41 /**
42  *  These define the lock order used by verifier
43  *  for basic objects internal to the driver frameworks.
44  *
45  *  Higher numbers are "lower" locks in the hierachy, which means
46  *  a lock can be acquired if its number greater than or equal
47  *  to the current one.
48  *
49  *  Correct Order:
50  *
51  *  FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_REQUEST
52  *
53  * Incorrect Order:
54  *
55  *  FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_DEVICE
56  *
57  * FX_LOCK_ORDER_UNKNOWN represents an object who has not (yet)
58  * defined a lock order. It has the highest number, meaning it
59  * can be acquired holding any other locks, including itself.
60  * At some point in time, this will cause a verifier break point,
61  * otherwise we can not fully test the frameworks.
62  *
63  * FX_LOCK_ORDER_NONE is a statement by the object that it will
64  * not use its Lock/Unlock routines. Use of locks on this object
65  * under verifier will cause a verifier breakpoint.
66  *
67  * There is a table mapping these from FX_TYPE_* to the lock orders
68  * define here in fx\core\FxVerifierLock.cpp
69  *
70  */
71 
72 //
73 // These locks are driver frameworks "internal" object
74 // locks and are not intended to be held across callbacks
75 // to the driver.
76 //
77 // They are acquired and released as the result of driver
78 // calls into the frameworks, which may be holding a driver
79 // callback lock.
80 //
81 #define FX_LOCK_ORDER_NONE                0x0000
82 #define FX_LOCK_ORDER_UNKNOWN             0xFFFF
83 
84 #define FX_LOCK_ORDER_PACKAGE_PDO         0x1000
85 #define FX_LOCK_ORDER_PACKAGE_FDO         0x1000
86 #define FX_LOCK_ORDER_WMI_IRP_HANDLER     0x1000
87 #define FX_LOCK_ORDER_PACKAGE_GENERAL     0x1000
88 
89 #define FX_LOCK_ORDER_IO_TARGET           0x1000
90 
91 #define FX_LOCK_ORDER_WMI_PROVIDER        0x1001
92 #define FX_LOCK_ORDER_WMI_INSTANCE        0x1002
93 
94 #define FX_LOCK_ORDER_DMA_ENABLER         0x1000
95 #define FX_LOCK_ORDER_DMA_TRANSACTION     0x1001
96 #define FX_LOCK_ORDER_COMMON_BUFFER       0x1001
97 
98 //
99 // A USB device owns a bunch of pipes, so make sure that device can acquire a
100 // pipe lock while locked, but not vice versa
101 //
102 #define FX_LOCK_ORDER_USB_DEVICE_IO_TARGET 0x1000
103 #define FX_LOCK_ORDER_USB_PIPE_IO_TARGET   0x1001
104 
105 
106 #define FX_LOCK_ORDER_DRIVER              0x1010
107 #define FX_LOCK_ORDER_DEVICE              0x1020
108 #define FX_LOCK_ORDER_MP_DEVICE           0x1020
109 #define FX_LOCK_ORDER_DEFAULT_IRP_HANDLER 0x1030
110 #define FX_LOCK_ORDER_QUEUE               0x1030
111 #define FX_LOCK_ORDER_PACKAGE_IO          0x1031
112 #define FX_LOCK_ORDER_REQUEST             0x1040
113 #define FX_LOCK_ORDER_IRPQUEUE            0x1051
114 #define FX_LOCK_ORDER_TIMER               0x1059
115 #define FX_LOCK_ORDER_DPC                 0x1060
116 #define FX_LOCK_ORDER_WORKITEM            0x1060
117 #define FX_LOCK_ORDER_CLEANUPLIST         0x1060
118 #define FX_LOCK_ORDER_INTERRUPT           0x1060
119 #define FX_LOCK_ORDER_FILEOBJECT          0x1060
120 #define FX_LOCK_ORDER_DEVICE_LIST         0x1061
121 #define FX_LOCK_ORDER_COLLECTION          0x1070 // collection can be used in any
122                                                  // of the above object's callbacks
123 #define FX_LOCK_ORDER_USEROBJECT          0x2000
124 
125 // dispose list is very far down in the list because pretty much any item can
126 // be added to the dispose list while that object's lock is being held
127 #define FX_LOCK_ORDER_DISPOSELIST         0x8000
128 
129 #define FX_LOCK_ORDER_SYSTEMWORKITEM      FX_LOCK_ORDER_UNKNOWN
130 #define FX_LOCK_ORDER_SYSTEMTHREAD        FX_LOCK_ORDER_UNKNOWN // No lock level
131 
132 //
133 // These are the device driver callback locks
134 // used to synchronize callback to the device
135 // driver. They are "higher" than the internal
136 // frameworks locks since an internal frameworks lock
137 // should not be held when these are acquired.
138 //
139 // (which should only be due to FxCallback.Invoke to a driver
140 //  event handler)
141 //
142 // This means they must have a lower number than the internal frameworks
143 // locks.
144 //
145 // They may be held when a device driver is calling into a frameworks
146 // DDI while in an event callback handler.
147 //
148 // These levels enforce not only the level of locks acquired
149 // and released by and for the driver, but also the rules
150 // about holding internal frameworks locks when calling into
151 // a driver. If a frameworks bug is holding a frameworks lock
152 // when it goes to do a callback, the attempt to acquire the
153 // lower numbered lock will raise the error.
154 //
155 #define FX_CALLBACKLOCK_ORDER_DRIVER      0x10
156 #define FX_CALLBACKLOCK_ORDER_DEVICE      0x20
157 #define FX_CALLBACKLOCK_ORDER_PACKAGE     0x30
158 #define FX_CALLBACKLOCK_ORDER_QUEUE       0x31
159 
160 #define FX_VERIFIER_LOCK_ENTRY(FX_OBJECT_TYPE, FX_LOCK_ORDER) { FX_OBJECT_TYPE, FX_LOCK_ORDER }
161 
162 // Internal FxLock spinlock entries
163 #define FX_VERIFIER_LOCK_ENTRIES()                                                                  \
164             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER,              FX_LOCK_ORDER_DRIVER),              \
165             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE,              FX_LOCK_ORDER_DEVICE),              \
166             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_MP_DEVICE,           FX_LOCK_ORDER_MP_DEVICE),           \
167             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO,          FX_LOCK_ORDER_PACKAGE_IO),          \
168             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_INSTANCE,        FX_LOCK_ORDER_WMI_INSTANCE),        \
169             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_PROVIDER,        FX_LOCK_ORDER_WMI_PROVIDER),        \
170             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE,               FX_LOCK_ORDER_QUEUE),               \
171             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_REQUEST,             FX_LOCK_ORDER_REQUEST),             \
172             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IRPQUEUE,            FX_LOCK_ORDER_IRPQUEUE),            \
173             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_PDO,         FX_LOCK_ORDER_PACKAGE_PDO),         \
174             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_FDO,         FX_LOCK_ORDER_PACKAGE_FDO),         \
175             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_IRP_HANDLER,     FX_LOCK_ORDER_WMI_IRP_HANDLER),     \
176             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_GENERAL,     FX_LOCK_ORDER_PACKAGE_GENERAL),     \
177             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_ENABLER,         FX_LOCK_ORDER_DMA_ENABLER),         \
178             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_TRANSACTION,     FX_LOCK_ORDER_DMA_TRANSACTION),     \
179             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COMMON_BUFFER,       FX_LOCK_ORDER_COMMON_BUFFER),       \
180             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET,           FX_LOCK_ORDER_IO_TARGET),           \
181             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_SELF,      FX_LOCK_ORDER_IO_TARGET),           \
182             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_DEVICE,FX_LOCK_ORDER_USB_DEVICE_IO_TARGET),\
183             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_PIPE,  FX_LOCK_ORDER_USB_PIPE_IO_TARGET),  \
184             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DPC,                 FX_LOCK_ORDER_DPC),                 \
185             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WORKITEM,            FX_LOCK_ORDER_WORKITEM),            \
186             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMTHREAD,        FX_LOCK_ORDER_SYSTEMTHREAD),        \
187             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CLEANUPLIST,         FX_LOCK_ORDER_CLEANUPLIST),         \
188             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_INTERRUPT,           FX_LOCK_ORDER_INTERRUPT),           \
189             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_TIMER,               FX_LOCK_ORDER_TIMER),               \
190             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_FILEOBJECT,          FX_LOCK_ORDER_FILEOBJECT),          \
191             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CHILD_LIST,         FX_LOCK_ORDER_DEVICE_LIST),          \
192             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMWORKITEM,      FX_LOCK_ORDER_SYSTEMWORKITEM),      \
193             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEFAULT_IRP_HANDLER, FX_LOCK_ORDER_DEFAULT_IRP_HANDLER), \
194             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COLLECTION,          FX_LOCK_ORDER_COLLECTION),          \
195             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DISPOSELIST,         FX_LOCK_ORDER_DISPOSELIST),         \
196             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_USEROBJECT,          FX_LOCK_ORDER_USEROBJECT),         \
197             FX_VERIFIER_LOCK_ENTRY(0,                           0)
198 
199 // Device Driver Callback lock entries
200 #define FX_VERIFIER_CALLBACKLOCK_ENTRIES()                                                \
201             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER,     FX_CALLBACKLOCK_ORDER_DRIVER),     \
202             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE,     FX_CALLBACKLOCK_ORDER_DEVICE),     \
203             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO, FX_CALLBACKLOCK_ORDER_PACKAGE),    \
204             FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE,      FX_CALLBACKLOCK_ORDER_QUEUE),      \
205             FX_VERIFIER_LOCK_ENTRY(0,                  0)
206 
207 //
208 // Mapping table structure between Fx object types and lock orders
209 //
210 struct FxVerifierOrderMapping {
211     USHORT ObjectType;
212     USHORT ObjectLockOrder;
213 };
214 
215 typedef struct FxVerifierOrderMapping  *pFxVerifierOrderMapping;
216 //
217 // This must be a power of two for hash algorithm
218 //
219 // Table size is dependent on the number of active threads
220 // in the frameworks at a given time. This can not execeed
221 // the number of (virtual due to hyperthreading) CPU's in the system.
222 //
223 // Setting this number lower just increases collisions, but does
224 // not impede correct function.
225 //
226 #define VERIFIER_THREAD_HASHTABLE_SIZE 64
227 
228 
229 //
230 // This structure is used by verifier hash table implementation
231 // for linking records per thread
232 //
233 struct FxVerifierThreadTableEntry {
234     MxThread        Thread;
235     FxVerifierLock* PerThreadPassiveLockList;
236     FxVerifierLock* PerThreadDispatchLockList;
237     LIST_ENTRY      HashChain;
238 };
239 
240 typedef struct FxVerifierThreadTableEntry *pFxVerifierThreadTableEntry;
241 /*
242  * This lock performs the same actions as the base
243  * FxLock, but provides additional tracking of lock
244  * order to help detect and debug
245  * deadlock and recursive lock situations.
246  *
247  * It does not inherit from FxLock since this would
248  * cause a recursion chain.
249  *
250  * Since lock verification is already more costly than
251  * basic lock use, this verifier lock supports both the
252  * FAST_MUTEX and SpinLock modes in order to utilize common
253  * code to support verification of FxCallback locks.
254  *
255  * FxVerifierLocks are only allocated when WdfVerifierLock
256  * is turned on.
257  */
258 
259 class FxVerifierLock : public FxGlobalsStump {
260 
261 private:
262     // Standard NT pool object identification
263     USHORT m_Type;
264     USHORT m_Size;
265 
266     // Spinlock to perform our lock functionality
267     MxLock          m_Lock;
268     KIRQL           m_OldIrql;
269 
270     // Fast Mutex for thread level verifier locks
271     MxPagedLock     m_Mutex;
272 
273     //
274     // Verifier per lock working values, protected
275     // by our m_Lock
276     //
277     FxObject*       m_ParentObject;
278     MxThread        m_OwningThread;
279     USHORT          m_Order;
280 
281     // True if its a Mutex based (thread context) lock
282     BOOLEAN         m_UseMutex;
283 
284     // True if its used as a Callback lock
285     BOOLEAN         m_CallbackLock;
286 
287     //
288     // This is the link for the per thread lock chain.
289     //
290     FxVerifierLock* m_OwnedLink;
291 
292 private:
293     FxVerifierLock(
294         PFX_DRIVER_GLOBALS FxDriverGlobals
295         ) :
296         FxGlobalsStump(FxDriverGlobals)
297     {
298     }
299 
300     void
301     InitializeLockOrder(
302         VOID
303         );
304 
305     void
306     FxVerifierLockDumpDetails(
307         __in FxVerifierLock* Lock,
308         __in PVOID           curThread,
309         __in FxVerifierLock* PerThreadList
310         );
311 
312 private:
313     //
314     // This constructor is used by internal object
315     // locks, which always use a spinlock.
316     //
317     FxVerifierLock(
318         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
319         __in FxObject* ParentObject
320         ) :
321         FxGlobalsStump(FxDriverGlobals)
322     {
323         m_Type = FX_TYPE_VERIFIERLOCK;
324         m_Size = sizeof(FxVerifierLock);
325 
326         m_ParentObject = ParentObject;
327 
328         m_OwningThread = NULL;
329         m_OwnedLink    = NULL;
330         m_Order        = FX_LOCK_ORDER_UNKNOWN;
331 
332         m_ThreadTableEntry.Thread = NULL;
333         m_ThreadTableEntry.PerThreadPassiveLockList = NULL;
334         m_ThreadTableEntry.PerThreadDispatchLockList = NULL;
335 
336         m_UseMutex = FALSE;
337         m_CallbackLock = FALSE;
338 
339         InitializeLockOrder();
340     }
341 
342     _Must_inspect_result_
343     __inline
344     NTSTATUS
345     Initialize(
346         )
347     {
348         NTSTATUS status;
349 
350         if (m_UseMutex) {
351             status = m_Mutex.Initialize();
352 
353             if (!NT_SUCCESS(status)) {
354                 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
355                                     "Unable to initialize paged lock for VerifierLock 0x%p "
356                                     "status %!STATUS!",
357                                     this, status);
358                 return status;
359             }
360         }
361 
362         return STATUS_SUCCESS;
363     }
364 
365     //
366     // This constructor is used by the Callback lock
367     // functions when verifer is on.
368     //
369     // The lock utlizes the callback lock order table entries to
370     // set its level.
371     //
372     FxVerifierLock(
373         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
374         __in FxObject* ParentObject,
375         __in BOOLEAN UseMutex
376         ) :
377         FxGlobalsStump(FxDriverGlobals)
378     {
379 
380         m_Type = FX_TYPE_VERIFIERLOCK;
381         m_Size = sizeof(FxVerifierLock);
382 
383         m_ParentObject = ParentObject;
384 
385         m_OwningThread = NULL;
386         m_OwnedLink    = NULL;
387         m_Order        = FX_LOCK_ORDER_UNKNOWN;
388 
389         m_ThreadTableEntry.Thread = NULL;
390         m_ThreadTableEntry.PerThreadPassiveLockList = NULL;
391         m_ThreadTableEntry.PerThreadDispatchLockList = NULL;
392 
393         // Different verifier table
394         m_CallbackLock = TRUE;
395 
396         if (UseMutex) {
397             m_UseMutex = TRUE;
398         }
399         else {
400             m_UseMutex = FALSE;
401         }
402 
403         InitializeLockOrder();
404     }
405 
406 public:
407 
408     _Must_inspect_result_
409     __inline
410     static
411     NTSTATUS
412     CreateAndInitialize(
413         __out   FxVerifierLock ** VerifierLock,
414         __in    PFX_DRIVER_GLOBALS FxDriverGlobals,
415         __in    FxObject* ParentObject,
416         __in    BOOLEAN UseMutex
417         )
418     {
419         NTSTATUS status;
420         FxVerifierLock * verifierLock;
421 
422         verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals,
423                                                             ParentObject,
424                                                             UseMutex);
425         if (NULL == verifierLock) {
426             status = STATUS_INSUFFICIENT_RESOURCES;
427             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
428                                 "Failed to allocate verifier lock, returning %!STATUS!",
429                                 status);
430             goto exit;
431         }
432 
433         status = verifierLock->Initialize();
434         if (!NT_SUCCESS(status)) {
435             delete verifierLock;
436             goto exit;
437         }
438 
439         *VerifierLock = verifierLock;
440 
441     exit:
442         return status;
443     }
444 
445     _Must_inspect_result_
446     __inline
447     static
448     NTSTATUS
449     CreateAndInitialize(
450         __out   FxVerifierLock ** VerifierLock,
451         __in    PFX_DRIVER_GLOBALS FxDriverGlobals,
452         __in    FxObject* ParentObject
453         )
454     {
455         NTSTATUS status;
456         FxVerifierLock * verifierLock;
457 
458         verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals,
459                                                             ParentObject);
460         if (NULL == verifierLock) {
461             status = STATUS_INSUFFICIENT_RESOURCES;
462             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
463                                 "Failed to allocate verifier lock, returning %!STATUS!",
464                                 status);
465             goto exit;
466         }
467 
468         status = verifierLock->Initialize();
469         if (!NT_SUCCESS(status)) {
470             delete verifierLock;
471             goto exit;
472         }
473 
474         *VerifierLock = verifierLock;
475 
476     exit:
477         return status;
478     }
479 
480     ~FxVerifierLock(
481         VOID
482         )
483     {
484         if (m_OwningThread != NULL) {
485             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
486                                 "Lock 0x%p is being destroyed while owned by "
487                                 "thread 0x%p, Owning Object 0x%p",
488                                 this, m_OwningThread, m_ParentObject);
489             FxVerifierDbgBreakPoint(GetDriverGlobals());
490         }
491     }
492 
493     VOID
494     Lock(
495         __out PKIRQL PreviousIrql,
496         __in BOOLEAN AtDpc
497         );
498 
499     VOID
500     Unlock(
501         __in KIRQL PreviousIrql,
502         __in BOOLEAN AtDpc
503         );
504 
505     KIRQL
506     GetLockPreviousIrql(
507         VOID
508         );
509 
510     //
511     // Instance data needed for the hash table chaining
512     //
513     FxVerifierThreadTableEntry m_ThreadTableEntry;
514 
515     //
516     // Static data and methods for hash table chaining
517     //
518     static ULONG ThreadTableSize;
519 
520     static KSPIN_LOCK ThreadTableLock;
521 
522     static PLIST_ENTRY ThreadTable;
523 
524     static
525     void
526     AllocateThreadTable(
527         __in PFX_DRIVER_GLOBALS FxDriverGlobals
528         );
529 
530     static
531     void
532     FreeThreadTable(
533         __in PFX_DRIVER_GLOBALS FxDriverGlobals
534         );
535 
536     static
537     void
538     DumpDetails(
539         __in FxVerifierLock* Lock,
540         __in MxThread        curThread,
541         __in FxVerifierLock* PerThreadList
542         );
543 
544     static
545     pFxVerifierThreadTableEntry
546     GetThreadTableEntry(
547         __in MxThread        curThread,
548         __in FxVerifierLock* pLock,
549         __in BOOLEAN         LookupOnly
550         );
551 
552     static
553     void
554     ReleaseOrReplaceThreadTableEntry(
555         __in MxThread        curThread,
556         __in FxVerifierLock* pLock
557         );
558 };
559 
560 #endif // _FXVERIFIERLOCK_HPP_
561 
562 
563