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(¶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 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