1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     HandleApi.cpp
8 
9 Abstract:
10 
11     This module implements the driver frameworks handle functions.
12 
13 Author:
14 
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 
25 --*/
26 
27 #include "fxobjectpch.hpp"
28 
29 extern "C" {
30 
31 #if defined(EVENT_TRACING)
32 #include "HandleAPI.tmh"
33 #endif
34 
35 }
36 
37 size_t
38 FxGetContextSize(
39     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes
40     )
41 /*++
42 
43 Routine Description:
44     Get a context size from an object's attributes settings.
45 
46 Arguments:
47     Attributes - attributes which will describe the size requirements for the
48         associated context.
49 
50 Return Value:
51     Size requirements for the  associated context.
52 
53   --*/
54 {
55     size_t contextSize = 0;
56 
57     if (Attributes != NULL) {
58         if (Attributes->ContextTypeInfo != NULL) {
59             if (Attributes->ContextSizeOverride != 0) {
60                 contextSize = Attributes->ContextSizeOverride;
61             }
62             else {
63                 contextSize = Attributes->ContextTypeInfo->ContextSize;
64             }
65         }
66     }
67 
68     return contextSize;
69 }
70 
71 _Must_inspect_result_
72 NTSTATUS
73 FxCalculateObjectTotalSize2(
74     __in        PFX_DRIVER_GLOBALS FxDriverGlobals,
75     __in        USHORT RawObjectSize,
76     __in        USHORT ExtraSize,
77     __in        size_t ContextSize,
78     __out       size_t* Total
79     )
80 /*++
81 
82 Routine Description:
83     Calculates the size of an allocation for an FxObject that will contain the
84     object, its initial context and any addtional headers.
85 
86 Arguments:
87     FxDriverGlobals - driver's globals
88     RawObjectSize - the size of the FxObject derived object
89     ExtraSize - additional size required by the derived object
90     ContextSize - Size requirements for the associated context (see FxGetContextSize() above).
91     Total - pointer which will receive the final size requirement
92 
93 Return Value:
94     NT_SUCCESS on success, !NT_SUCCESS on failure
95 
96   --*/
97 {
98     NTSTATUS status;
99 
100     *Total = 0;
101 
102     status = RtlSizeTAdd(
103         WDF_ALIGN_SIZE_UP(COMPUTE_OBJECT_SIZE(RawObjectSize, ExtraSize), MEMORY_ALLOCATION_ALIGNMENT),
104         FX_CONTEXT_HEADER_SIZE,
105         Total
106         );
107 
108     if (NT_SUCCESS(status)) {
109         if (ContextSize != 0) {
110             size_t alignUp;
111 
112             alignUp = ALIGN_UP(ContextSize, PVOID);
113 
114             //
115             // overflow after aligning up to a pointer boundary;
116             //
117             if (alignUp < ContextSize) {
118                 return STATUS_INTEGER_OVERFLOW;
119             }
120 
121             status = RtlSizeTAdd(*Total, alignUp, Total);
122         }
123     }
124 
125     if (NT_SUCCESS(status) && FxDriverGlobals->IsObjectDebugOn()) {
126         //
127         // Attempt to add in the debug extension
128         //
129         status = RtlSizeTAdd(*Total,
130                              FxObjectDebugExtensionSize,
131                              Total);
132     }
133 
134     if (!NT_SUCCESS(status)) {
135         DoTraceLevelMessage(
136             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT,
137             "Size overflow, object size 0x%x, extra object size 0x%x, "
138             "context size 0x%I64x, %!STATUS!",
139             RawObjectSize, ExtraSize, ContextSize, status);
140     }
141 
142     return status;
143 }
144 
145 _Must_inspect_result_
146 NTSTATUS
147 FxCalculateObjectTotalSize(
148     __in        PFX_DRIVER_GLOBALS FxDriverGlobals,
149     __in        USHORT RawObjectSize,
150     __in        USHORT ExtraSize,
151     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
152     __out       size_t* Total
153     )
154 {
155     return FxCalculateObjectTotalSize2(FxDriverGlobals,
156                                        RawObjectSize,
157                                        ExtraSize,
158                                        FxGetContextSize(Attributes),
159                                        Total);
160 }
161 
162 PVOID
163 FxObjectHandleAlloc(
164     __in        PFX_DRIVER_GLOBALS FxDriverGlobals,
165     __in        POOL_TYPE PoolType,
166     __in        size_t Size,
167     __in        ULONG Tag,
168     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
169     __in        USHORT ExtraSize,
170     __in        FxObjectType ObjectType
171     )
172 /*++
173 
174 Routine Description:
175     Allocates an FxObject derived object, it's associated context, and any
176     framework required headers and footers.
177 
178 Arguments:
179     FxDriverGlobals - caller's globals
180     PoolType - type of pool to be used in allocating the object's memory
181     Size - size of the object (as passed to operator new() by the compiler)
182     Tag - tag to use when allocating the object's memory
183     Attributes - attributes which describe the context to be associated with the
184         object
185     ExtraSize - any addtional storage required by the object itself
186     ObjectType - the type (internal or external) of object being allocated.  An
187         internal object is a worker object which will never have an associated
188         type or be Commit()'ed into an external object handle that the client
189         driver will see.
190 
191 Return Value:
192     A valid pointer on success, NULL otherwise
193 
194   --*/
195 {
196     PVOID   blob;
197     size_t  totalSize;
198     NTSTATUS status;
199 
200     if (Tag == 0) {
201         Tag = FxDriverGlobals->Tag;
202         ASSERT(Tag != 0);
203     }
204 
205     if (ObjectType == FxObjectTypeInternal) {
206         //
207         // An internal object might need the debug extension size added to it,
208         // but that's it.  No extra size, no FxContextHeader.
209         //
210         if (FxDriverGlobals->IsObjectDebugOn()) {
211             status = RtlSizeTAdd(Size,
212                                  FxObjectDebugExtensionSize,
213                                  &totalSize);
214         }
215         else {
216             totalSize = Size;
217             status = STATUS_SUCCESS;
218         }
219     }
220     else {
221         status = FxCalculateObjectTotalSize(FxDriverGlobals,
222                                             (USHORT) Size,
223                                             ExtraSize,
224                                             Attributes,
225                                             &totalSize);
226     }
227 
228     if (!NT_SUCCESS(status)) {
229         return NULL;
230     }
231 
232     blob = FxPoolAllocateWithTag(FxDriverGlobals, PoolType, totalSize, Tag);
233 
234     if (blob != NULL) {
235         blob = FxObjectAndHandleHeaderInit(
236             FxDriverGlobals,
237             blob,
238             COMPUTE_OBJECT_SIZE((USHORT) Size, ExtraSize),
239             Attributes,
240             ObjectType
241             );
242     }
243 
244     return blob;
245 }
246 
247 VOID
248 FxContextHeaderInit(
249     __in        FxContextHeader* Header,
250     __in        FxObject* Object,
251     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes
252     )
253 /*++
254 
255 Routine Description:
256     Initializes a context header which describes a typed context.
257 
258 Arguments:
259     Header - the header to initialize
260     Object - the object on which the context is being associated with
261     Attributes - description of the typed context
262 
263   --*/
264 {
265     RtlZeroMemory(Header, FX_CONTEXT_HEADER_SIZE);
266 
267     Header->Object = Object;
268 
269     if (Attributes != NULL) {
270         if (Attributes->ContextTypeInfo != NULL) {
271             size_t contextSize;
272 
273             if (Attributes->ContextSizeOverride != 0) {
274                 contextSize = Attributes->ContextSizeOverride;
275 
276             }
277             else {
278                 contextSize = Attributes->ContextTypeInfo->ContextSize;
279             }
280 
281             //
282             // Zero initialize the entire context
283             //
284             RtlZeroMemory(&Header->Context[0], ALIGN_UP(contextSize, PVOID));
285         }
286 
287         Header->ContextTypeInfo = Attributes->ContextTypeInfo;
288     }
289 }
290 
291 PVOID
292 FxObjectAndHandleHeaderInit(
293     __in        PFX_DRIVER_GLOBALS FxDriverGlobals,
294     __in        PVOID AllocationStart,
295     __in        USHORT ObjectSize,
296     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
297     __in        FxObjectType ObjectType
298     )
299 /*++
300 
301 Routine Description:
302     Initialize the object and its associated context.
303 
304 Arguments:
305     FxDriverGlobals - caller's globals
306     AllocationStart - start of the memory block allocated to represent the object.
307         This will not be the same as the pointer which represents the address of
308         the object itself in memory
309     ObjectSize - size of the object
310     Attributes - description of its context
311     ObjectType - type (internal or external) of object being initialized
312 
313 Return Value:
314     The address of the object withing AllocationStart
315 
316   --*/
317 
318 {
319     FxObject* pObject;
320 
321     if (FxDriverGlobals->IsObjectDebugOn()) {
322         FxObjectDebugExtension* pExtension;
323 
324         pExtension = (FxObjectDebugExtension*) AllocationStart;
325 
326         RtlZeroMemory(pExtension, FxObjectDebugExtensionSize);
327         pExtension->Signature = FxObjectDebugExtensionSignature;
328 
329         pObject = (FxObject*) &pExtension->AllocationStart[0];
330     }
331     else {
332         pObject = (FxObject*) AllocationStart;
333     }
334 
335     if (ObjectType == FxObjectTypeExternal) {
336         FxContextHeaderInit(
337             (FxContextHeader*) WDF_PTR_ADD_OFFSET(pObject, ObjectSize),
338             pObject,
339             Attributes
340             );
341     }
342 
343     return pObject;
344 }
345 
346 VOID
347 FxObjectHandleGetPtrQI(
348     __in    FxObject* Object,
349     __out   PVOID* PPObject,
350     __in    WDFOBJECT Handle,
351     __in    WDFTYPE Type,
352     __in    WDFOBJECT_OFFSET Offset
353     )
354 /*++
355 
356 Routine Description:
357     Worker function for FxObjectHandleGetPtrXxx which will call
358     FxObject::QueryInterface when the Type does not match the object's built in
359     Type.
360 
361 Arguments:
362     Object - object to query
363     PPObject - pointer which will recieve the queried for object
364     Handle - handle which the caller passed to the framework
365     Type - required object type
366     Offset - offset of the handle within the object.  Nearly all handles will have
367         a zero object.
368 
369   --*/
370 {
371     FxQueryInterfaceParams params = { PPObject, Type, Offset };
372     NTSTATUS status;
373 
374     *PPObject = NULL;
375 
376     status = Object->QueryInterface(&params);
377 
378     if (!NT_SUCCESS(status)) {
379         DoTraceLevelMessage(
380             Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
381             "Object Type Mismatch, Handle 0x%p, Type 0x%x, "
382             "Obj 0x%p, SB 0x%x",
383             Handle, Type, Object, Object->GetType());
384 
385         FxVerifierBugCheck(Object->GetDriverGlobals(),
386                            WDF_INVALID_HANDLE,
387                            (ULONG_PTR) Handle,
388                            Type);
389 
390         /* NOTREACHED */
391         return;
392     }
393 }
394 
395 _Must_inspect_result_
396 NTSTATUS
397 FxObjectAllocateContext(
398     __in        FxObject*               Object,
399     __in        PWDF_OBJECT_ATTRIBUTES  Attributes,
400     __in        BOOLEAN                 AllowCallbacksOnly,
401     __deref_opt_out PVOID*              Context
402     )
403 /*++
404 
405 Routine Description:
406     Allocates an additional context on the object if it is in the correct state.
407 
408 Arguments:
409     Object - object on which to add a context
410     Attributes - attributes which describe the type and size of the new context
411     AllowEmptyContext -TRUE to allow logic to allocate the context's header only.
412     Context - optional pointer which will recieve the new context
413 
414 Return Value:
415     STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
416     is already attached to the handle, and !NT_SUCCESS on failure
417 
418   --*/
419 {
420     PFX_DRIVER_GLOBALS  fxDriverGlobals;
421     NTSTATUS            status;
422     FxContextHeader *   header;
423     size_t              size;
424     BOOLEAN             relRef;
425     ULONG               flags;
426 
427     fxDriverGlobals = Object->GetDriverGlobals();
428     header = NULL;
429     relRef = FALSE;
430 
431     //
432     // Init validation flags.
433     //
434     flags = FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED;
435     if (fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
436         flags |= FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED;
437     }
438 
439     //
440     // Basic validations.
441     //
442     status = FxValidateObjectAttributes(fxDriverGlobals, Attributes, flags);
443     if (!NT_SUCCESS(status)) {
444         goto Done;
445     }
446 
447     //
448     // Check for context type!
449     //
450     if (Attributes->ContextTypeInfo == NULL && AllowCallbacksOnly == FALSE) {
451         status = STATUS_OBJECT_NAME_INVALID;
452         DoTraceLevelMessage(
453             fxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
454             "Attributes %p ContextTypeInfo is NULL, %!STATUS!",
455             Attributes, status);
456         goto Done;
457     }
458 
459     Object->ADDREF(&status);
460     relRef = TRUE;
461 
462     //
463     // By passing 0's for raw object size and extra size, we can compute the
464     // size of only the header and its contents.
465     //
466     status = FxCalculateObjectTotalSize(fxDriverGlobals, 0, 0, Attributes, &size);
467     if (!NT_SUCCESS(status)) {
468         goto Done;
469     }
470 
471     header = (FxContextHeader*)
472                 FxPoolAllocate(fxDriverGlobals, NonPagedPool, size);
473 
474     if (header == NULL) {
475         status = STATUS_INSUFFICIENT_RESOURCES;
476         goto Done;
477     }
478 
479     FxContextHeaderInit(header, Object, Attributes);
480 
481     status = Object->AddContext(header, Context, Attributes);
482 
483     //
484     // STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check
485     // explicitly for STATUS_SUCCESS.
486     //
487     if (status != STATUS_SUCCESS) {
488         FxPoolFree(header);
489     }
490 
491 Done:
492 
493     if (relRef) {
494         Object->RELEASE(&status);
495     }
496 
497     return status;
498 }
499 
500 // extern "C" all APIs
501 extern "C" {
502 
503 _Must_inspect_result_
504 __drv_maxIRQL(DISPATCH_LEVEL)
505 WDFAPI
506 NTSTATUS
507 STDCALL
508 WDFEXPORT(WdfObjectAllocateContext)(
509     __in
510     PWDF_DRIVER_GLOBALS DriverGlobals,
511     __in
512     WDFOBJECT Handle,
513     __in
514     PWDF_OBJECT_ATTRIBUTES Attributes,
515     __deref_opt_out
516     PVOID* Context
517     )
518 /*++
519 
520 Routine Description:
521     Allocates an additional context on the handle if the object is in the
522     correct state
523 
524 Arguments:
525     Handle - handle on which to add a context
526     Attributes - attributes which describe the type and size of the new context
527     Context - optional pointer which will recieve the new context
528 
529 Return Value:
530     STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
531     is already attached to the handle, and !NT_SUCCESS on failure
532 
533   --*/
534 {
535     DDI_ENTRY_IMPERSONATION_OK();
536 
537     NTSTATUS            status;
538     FxObject*           object;
539     WDFOBJECT_OFFSET    offset;
540 
541     FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
542 
543     //
544     // No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because
545     // we assume that the object handle will point back to an FxObject.  (The
546     // call to FxObjectHandleGetPtr will just make needless virtual call into
547     // FxObject anyways).
548     //
549     offset = 0;
550     object = FxObject::_GetObjectFromHandle(Handle, &offset);
551 
552     if (offset != 0) {
553 
554 
555 
556         status = STATUS_OBJECT_PATH_INVALID;
557         DoTraceLevelMessage(
558             object->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGHANDLE,
559             "WDFHANDLE %p cannot have contexts added to it, %!STATUS!",
560             Handle, status);
561         goto Done;
562     }
563 
564     //
565     // Internal helper function does the rest of the work.
566     //
567     status = FxObjectAllocateContext(object, Attributes, FALSE, Context);
568 
569 Done:
570     return status;
571 }
572 
573 __drv_maxIRQL(DISPATCH_LEVEL+1)
574 WDFAPI
575 PVOID
576 FASTCALL
577 WDFEXPORT(WdfObjectGetTypedContextWorker)(
578     __in
579     PWDF_DRIVER_GLOBALS DriverGlobals,
580     __in
581     WDFOBJECT Handle,
582     __in
583     PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo
584     )
585 /*++
586 
587 Routine Description:
588     Retrieves the requested type from a handle
589 
590 Arguments:
591     Handle - the handle to retrieve the context from
592     TypeInfo - global constant pointer which describes the type.  Since the pointer
593         value is unique in all of kernel space, we will perform a pointer compare
594         instead of a deep structure compare
595 
596 Return Value:
597     A valid context pointere or NULL.  NULL is not a failure, querying for a type
598     not associated with the handle is a legitimate operation.
599 
600   --*/
601 {
602     DDI_ENTRY_IMPERSONATION_OK();
603 
604     FxContextHeader* pHeader;
605     FxObject* pObject;
606     PFX_DRIVER_GLOBALS pFxDriverGlobals;
607     WDFOBJECT_OFFSET offset;
608 
609     FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
610 
611     //
612     // Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a
613     // hot spot / workhorse function that should be as efficient as possible.
614     //
615     // A call to FxObjectHandleGetPtr would :
616     // 1)  invoke a virtual call to QueryInterface
617     //
618     // 2)  ASSERT that the ref count of the object is > zero.  Since this is one
619     //     of the few functions that can be called in EvtObjectDestroy where the
620     //     ref count is zero, that is not a good side affect.
621     //
622     offset = 0;
623     pObject = FxObject::_GetObjectFromHandle(Handle, &offset);
624 
625     //
626     // Use the object's globals, not the caller's
627     //
628     pFxDriverGlobals = pObject->GetDriverGlobals();
629 
630     FxPointerNotNull(pFxDriverGlobals, TypeInfo);
631 
632     pHeader = pObject->GetContextHeader();
633 
634     for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) {
635         if (pHeader->ContextTypeInfo == TypeInfo) {
636             return &pHeader->Context[0];
637         }
638     }
639 
640     PCHAR pGivenName;
641 
642     if (TypeInfo->ContextName != NULL) {
643         pGivenName = TypeInfo->ContextName;
644     }
645     else {
646         pGivenName = "<no typename given>";
647     }
648 
649     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
650                         "Attempting to get context type %s from WDFOBJECT 0x%p",
651                         pGivenName, Handle);
652 
653     return NULL;
654 }
655 
656 __drv_maxIRQL(DISPATCH_LEVEL+1)
657 WDFAPI
658 WDFOBJECT
659 FASTCALL
660 WDFEXPORT(WdfObjectContextGetObject)(
661     __in
662     PWDF_DRIVER_GLOBALS,
663     __in
664     PVOID ContextPointer
665     )
666 /*++
667 
668 Routine Description:
669     Reverse of WdfObjectGetTypedContextWorker.  Function will return the handle
670     associated with the provided context pointer.
671 
672 Arguments:
673     ContextPointer - context pointer from which to retrieve the owning handle
674 
675 Return Value:
676     A valid WDF handle
677 
678   --*/
679 {
680     DDI_ENTRY_IMPERSONATION_OK();
681 
682     FxContextHeader* pHeader;
683     FxObject* pObject;
684 
685     //
686     // The context could be one of the chained contexts on the object and not
687     // the first one, so it is easiest to go back to the object and build the
688     // handle value from the FxObject*.
689     //
690     #pragma prefast(push);
691 
692 
693     #pragma prefast(disable:__WARNING_BUFFER_UNDERFLOW, "No way to express that passed in ptr is at an offset");
694 
695     pHeader = CONTAINING_RECORD(ContextPointer, FxContextHeader, Context);
696     pObject = pHeader->Object;
697 
698     #pragma prefast(pop);
699 
700     return (WDFOBJECT) pObject->GetObjectHandle();
701 }
702 
703 } // extern "C"
704