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
FxGetContextSize(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes)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
FxCalculateObjectTotalSize2(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in USHORT RawObjectSize,__in USHORT ExtraSize,__in size_t ContextSize,__out size_t * Total)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
FxCalculateObjectTotalSize(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in USHORT RawObjectSize,__in USHORT ExtraSize,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__out size_t * Total)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
FxObjectHandleAlloc(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in POOL_TYPE PoolType,__in size_t Size,__in ULONG Tag,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__in USHORT ExtraSize,__in FxObjectType ObjectType)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
FxContextHeaderInit(__in FxContextHeader * Header,__in FxObject * Object,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes)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
FxObjectAndHandleHeaderInit(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PVOID AllocationStart,__in USHORT ObjectSize,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__in FxObjectType ObjectType)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
FxObjectHandleGetPtrQI(__in FxObject * Object,__out PVOID * PPObject,__in WDFOBJECT Handle,__in WDFTYPE Type,__in WDFOBJECT_OFFSET Offset)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(¶ms);
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
FxObjectAllocateContext(__in FxObject * Object,__in PWDF_OBJECT_ATTRIBUTES Attributes,__in BOOLEAN AllowCallbacksOnly,__deref_opt_out PVOID * Context)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_
__drv_maxIRQL(DISPATCH_LEVEL)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
WDFEXPORT(WdfObjectGetTypedContextWorker)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
WDFEXPORT(WdfObjectContextGetObject)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