1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ob/oblife.c 5 * PURPOSE: Manages the lifetime of an Object, including its creation, 6 * and deletion, as well as setting or querying any of its 7 * information while it is active. Since Object Types are also 8 * Objects, those are also managed here. 9 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 10 * Eric Kohl 11 * Thomas Weidenmueller (w3seek@reactos.org) 12 */ 13 14 /* INCLUDES ******************************************************************/ 15 16 #include <ntoskrnl.h> 17 #define NDEBUG 18 #include <debug.h> 19 20 extern ULONG NtGlobalFlag; 21 22 POBJECT_TYPE ObpTypeObjectType = NULL; 23 KEVENT ObpDefaultObject; 24 KGUARDED_MUTEX ObpDeviceMapLock; 25 26 GENERAL_LOOKASIDE ObpNameBufferLookasideList, ObpCreateInfoLookasideList; 27 28 WORK_QUEUE_ITEM ObpReaperWorkItem; 29 volatile PVOID ObpReaperList; 30 31 ULONG ObpObjectsCreated, ObpObjectsWithName, ObpObjectsWithPoolQuota; 32 ULONG ObpObjectsWithHandleDB, ObpObjectsWithCreatorInfo; 33 POBJECT_TYPE ObpObjectTypes[32]; 34 35 /* PRIVATE FUNCTIONS *********************************************************/ 36 37 VOID 38 FASTCALL 39 ObpDeallocateObject(IN PVOID Object) 40 { 41 PVOID HeaderLocation; 42 POBJECT_HEADER Header; 43 POBJECT_TYPE ObjectType; 44 POBJECT_HEADER_HANDLE_INFO HandleInfo; 45 POBJECT_HEADER_NAME_INFO NameInfo; 46 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 47 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 48 ULONG PagedPoolCharge, NonPagedPoolCharge; 49 PAGED_CODE(); 50 51 /* Get the header and assume this is what we'll free */ 52 Header = OBJECT_TO_OBJECT_HEADER(Object); 53 ObjectType = Header->Type; 54 HeaderLocation = Header; 55 56 /* To find the header, walk backwards from how we allocated */ 57 if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header))) 58 { 59 HeaderLocation = CreatorInfo; 60 } 61 if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header))) 62 { 63 HeaderLocation = NameInfo; 64 } 65 if ((HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(Header))) 66 { 67 HeaderLocation = HandleInfo; 68 } 69 if ((QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO(Header))) 70 { 71 HeaderLocation = QuotaInfo; 72 } 73 74 /* Decrease the total */ 75 InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects); 76 77 /* Check if we have create info */ 78 if (Header->Flags & OB_FLAG_CREATE_INFO) 79 { 80 /* Double-check that it exists */ 81 if (Header->ObjectCreateInfo) 82 { 83 /* Free it */ 84 ObpFreeObjectCreateInformation(Header->ObjectCreateInfo); 85 Header->ObjectCreateInfo = NULL; 86 } 87 } 88 else 89 { 90 /* Check if it has a quota block */ 91 if (Header->QuotaBlockCharged) 92 { 93 /* Check if we have quota information */ 94 if (QuotaInfo) 95 { 96 /* Get charges from quota information */ 97 PagedPoolCharge = QuotaInfo->PagedPoolCharge + 98 QuotaInfo->SecurityDescriptorCharge; 99 NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge; 100 } 101 else 102 { 103 /* Get charges from object type */ 104 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; 105 NonPagedPoolCharge = ObjectType-> 106 TypeInfo.DefaultNonPagedPoolCharge; 107 108 /* Add the SD charge too */ 109 if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048; 110 } 111 112 /* Return the quota */ 113 DPRINT("FIXME: Should return quotas: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge); 114 #if 0 115 PsReturnSharedPoolQuota(ObjectHeader->QuotaBlockCharged, 116 PagedPoolCharge, 117 NonPagedPoolCharge); 118 #endif 119 120 } 121 } 122 123 /* Check if a handle database was active */ 124 if ((HandleInfo) && !(Header->Flags & OB_FLAG_SINGLE_PROCESS)) 125 { 126 /* Free it */ 127 ExFreePool(HandleInfo->HandleCountDatabase); 128 HandleInfo->HandleCountDatabase = NULL; 129 } 130 131 /* Check if we have a name */ 132 if ((NameInfo) && (NameInfo->Name.Buffer)) 133 { 134 /* Free it */ 135 ExFreePool(NameInfo->Name.Buffer); 136 NameInfo->Name.Buffer = NULL; 137 } 138 139 /* Catch invalid access */ 140 Header->Type = (POBJECT_TYPE)(ULONG_PTR)0xBAADB0B0BAADB0B0ULL; 141 142 /* Free the object using the same allocation tag */ 143 ExFreePoolWithTag(HeaderLocation, ObjectType->Key); 144 } 145 146 VOID 147 NTAPI 148 ObpDeleteObject(IN PVOID Object, 149 IN BOOLEAN CalledFromWorkerThread) 150 { 151 POBJECT_HEADER Header; 152 POBJECT_TYPE ObjectType; 153 POBJECT_HEADER_NAME_INFO NameInfo; 154 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 155 KIRQL CalloutIrql; 156 PAGED_CODE(); 157 158 /* Get the header and type */ 159 Header = OBJECT_TO_OBJECT_HEADER(Object); 160 ObjectType = Header->Type; 161 162 /* Get creator and name information */ 163 NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header); 164 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); 165 166 /* Check if the object is on a type list */ 167 if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList))) 168 { 169 /* Lock the object type */ 170 ObpEnterObjectTypeMutex(ObjectType); 171 172 /* Remove the object from the type list */ 173 RemoveEntryList(&CreatorInfo->TypeList); 174 175 /* Release the lock */ 176 ObpLeaveObjectTypeMutex(ObjectType); 177 } 178 179 /* Check if we have a name */ 180 if ((NameInfo) && (NameInfo->Name.Buffer)) 181 { 182 /* Free it */ 183 ExFreePool(NameInfo->Name.Buffer); 184 RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0); 185 } 186 187 /* Check if we have a security descriptor */ 188 if (Header->SecurityDescriptor) 189 { 190 /* Call the security procedure to delete it */ 191 ObpCalloutStart(&CalloutIrql); 192 ObjectType->TypeInfo.SecurityProcedure(Object, 193 DeleteSecurityDescriptor, 194 0, 195 NULL, 196 NULL, 197 &Header->SecurityDescriptor, 198 0, 199 NULL); 200 ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object); 201 } 202 203 /* Check if we have a delete procedure */ 204 if (ObjectType->TypeInfo.DeleteProcedure) 205 { 206 /* Save whether we were deleted from worker thread or not */ 207 if (!CalledFromWorkerThread) Header->Flags |= OB_FLAG_DEFER_DELETE; 208 209 /* Call it */ 210 ObpCalloutStart(&CalloutIrql); 211 ObjectType->TypeInfo.DeleteProcedure(Object); 212 ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object); 213 } 214 215 /* Now de-allocate all object members */ 216 ObpDeallocateObject(Object); 217 } 218 219 VOID 220 NTAPI 221 ObpReapObject(IN PVOID Parameter) 222 { 223 POBJECT_HEADER ReapObject, NextObject; 224 225 /* Start reaping */ 226 do 227 { 228 /* Get the reap object */ 229 ReapObject = InterlockedExchangePointer(&ObpReaperList, (PVOID)1); 230 231 /* Start deletion loop */ 232 do 233 { 234 /* Get the next object */ 235 NextObject = ReapObject->NextToFree; 236 237 /* Delete the object */ 238 ObpDeleteObject(&ReapObject->Body, TRUE); 239 240 /* Move to the next one */ 241 ReapObject = NextObject; 242 } while ((ReapObject) && (ReapObject != (PVOID)1)); 243 } while ((ObpReaperList != (PVOID)1) || 244 (InterlockedCompareExchange((PLONG)&ObpReaperList, 0, 1) != 1)); 245 } 246 247 /*++ 248 * @name ObpSetPermanentObject 249 * 250 * The ObpSetPermanentObject routine makes an sets or clears the permanent 251 * flag of an object, thus making it either permanent or temporary. 252 * 253 * @param ObjectBody 254 * Pointer to the object to make permanent or temporary. 255 * 256 * @param Permanent 257 * Flag specifying which operation to perform. 258 * 259 * @return None. 260 * 261 * @remarks If the object is being made temporary, then it will be checked 262 * as a candidate for immediate removal from the namespace. 263 * 264 *--*/ 265 VOID 266 FASTCALL 267 ObpSetPermanentObject(IN PVOID ObjectBody, 268 IN BOOLEAN Permanent) 269 { 270 POBJECT_HEADER ObjectHeader; 271 272 /* Get the header */ 273 ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody); 274 275 /* Acquire object lock */ 276 ObpAcquireObjectLock(ObjectHeader); 277 278 /* Check what we're doing to it */ 279 if (Permanent) 280 { 281 /* Set it to permanent */ 282 ObjectHeader->Flags |= OB_FLAG_PERMANENT; 283 284 /* Release the lock */ 285 ObpReleaseObjectLock(ObjectHeader); 286 } 287 else 288 { 289 /* Remove the flag */ 290 ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; 291 292 /* Release the lock */ 293 ObpReleaseObjectLock(ObjectHeader); 294 295 /* Check if we should delete the object now */ 296 ObpDeleteNameCheck(ObjectBody); 297 } 298 } 299 300 PWCHAR 301 NTAPI 302 ObpAllocateObjectNameBuffer(IN ULONG Length, 303 IN BOOLEAN UseLookaside, 304 IN OUT PUNICODE_STRING ObjectName) 305 { 306 ULONG MaximumLength; 307 PVOID Buffer; 308 309 /* Set the maximum length to the length plus the terminator */ 310 MaximumLength = Length + sizeof(UNICODE_NULL); 311 312 /* Check if we should use the lookaside buffer */ 313 if (!(UseLookaside) || (MaximumLength > OBP_NAME_LOOKASIDE_MAX_SIZE)) 314 { 315 /* Nope, allocate directly from pool */ 316 /* Since we later use MaximumLength to detect that we're not allocating 317 * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL) 318 * here. 319 * 320 * People do call this with UseLookasideList FALSE so the distinction 321 * is critical. 322 */ 323 if (MaximumLength <= OBP_NAME_LOOKASIDE_MAX_SIZE) 324 { 325 MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE + sizeof(UNICODE_NULL); 326 } 327 Buffer = ExAllocatePoolWithTag(PagedPool, 328 MaximumLength, 329 OB_NAME_TAG); 330 } 331 else 332 { 333 /* Allocate from the lookaside */ 334 MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE; 335 Buffer = ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList); 336 } 337 338 /* Setup the string */ 339 ObjectName->MaximumLength = (USHORT)MaximumLength; 340 ObjectName->Length = (USHORT)Length; 341 ObjectName->Buffer = Buffer; 342 return Buffer; 343 } 344 345 VOID 346 NTAPI 347 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name) 348 { 349 PVOID Buffer = Name->Buffer; 350 351 /* We know this is a pool-allocation if the size doesn't match */ 352 if (Name->MaximumLength != OBP_NAME_LOOKASIDE_MAX_SIZE) 353 { 354 /* 355 * Free it from the pool. 356 * 357 * We cannot use here ExFreePoolWithTag(..., OB_NAME_TAG); , because 358 * the object name may have been massaged during operation by different 359 * object parse routines. If the latter ones have to resolve a symbolic 360 * link (e.g. as is done by CmpParseKey() and CmpGetSymbolicLink()), 361 * the original object name is freed and re-allocated from the pool, 362 * possibly with a different pool tag. At the end of the day, the new 363 * object name can be reallocated and completely different, but we 364 * should still be able to free it! 365 */ 366 ExFreePool(Buffer); 367 } 368 else 369 { 370 /* Otherwise, free from the lookaside */ 371 ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList); 372 } 373 } 374 375 NTSTATUS 376 NTAPI 377 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName, 378 IN PUNICODE_STRING ObjectName, 379 IN KPROCESSOR_MODE AccessMode, 380 IN BOOLEAN UseLookaside) 381 { 382 NTSTATUS Status = STATUS_SUCCESS; 383 ULONG StringLength; 384 PWCHAR _SEH2_VOLATILE StringBuffer = NULL; 385 UNICODE_STRING LocalName; 386 PAGED_CODE(); 387 388 /* Initialize the Input String */ 389 RtlInitEmptyUnicodeString(CapturedName, NULL, 0); 390 391 /* Protect everything */ 392 _SEH2_TRY 393 { 394 /* Check if we came from user mode */ 395 if (AccessMode != KernelMode) 396 { 397 /* First Probe the String */ 398 LocalName = ProbeForReadUnicodeString(ObjectName); 399 ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR)); 400 } 401 else 402 { 403 /* No probing needed */ 404 LocalName = *ObjectName; 405 } 406 407 /* Make sure there really is a string */ 408 StringLength = LocalName.Length; 409 if (StringLength) 410 { 411 /* Check that the size is a valid WCHAR multiple */ 412 if ((StringLength & (sizeof(WCHAR) - 1)) || 413 /* Check that the NULL-termination below will work */ 414 (StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1))) 415 { 416 /* PS: Please keep the checks above expanded for clarity */ 417 Status = STATUS_OBJECT_NAME_INVALID; 418 } 419 else 420 { 421 /* Allocate the string buffer */ 422 StringBuffer = ObpAllocateObjectNameBuffer(StringLength, 423 UseLookaside, 424 CapturedName); 425 if (!StringBuffer) 426 { 427 /* Set failure code */ 428 Status = STATUS_INSUFFICIENT_RESOURCES; 429 } 430 else 431 { 432 /* Copy the name */ 433 RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength); 434 StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL; 435 } 436 } 437 } 438 } 439 _SEH2_EXCEPT(ExSystemExceptionFilter()) 440 { 441 /* Handle exception and free the string buffer */ 442 Status = _SEH2_GetExceptionCode(); 443 if (StringBuffer) 444 { 445 ObpFreeObjectNameBuffer(CapturedName); 446 } 447 } 448 _SEH2_END; 449 450 /* Return */ 451 return Status; 452 } 453 454 NTSTATUS 455 NTAPI 456 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes, 457 IN KPROCESSOR_MODE AccessMode, 458 IN KPROCESSOR_MODE CreatorMode, 459 IN BOOLEAN AllocateFromLookaside, 460 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, 461 OUT PUNICODE_STRING ObjectName) 462 { 463 NTSTATUS Status = STATUS_SUCCESS; 464 PSECURITY_DESCRIPTOR SecurityDescriptor; 465 PSECURITY_QUALITY_OF_SERVICE SecurityQos; 466 PUNICODE_STRING LocalObjectName = NULL; 467 PAGED_CODE(); 468 469 /* Zero out the Capture Data */ 470 RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); 471 472 /* SEH everything here for protection */ 473 _SEH2_TRY 474 { 475 /* Check if we got attributes */ 476 if (ObjectAttributes) 477 { 478 /* Check if we're in user mode */ 479 if (AccessMode != KernelMode) 480 { 481 /* Probe the attributes */ 482 ProbeForRead(ObjectAttributes, 483 sizeof(OBJECT_ATTRIBUTES), 484 sizeof(ULONG)); 485 } 486 487 /* Validate the Size and Attributes */ 488 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || 489 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) 490 { 491 /* Invalid combination, fail */ 492 _SEH2_YIELD(return STATUS_INVALID_PARAMETER); 493 } 494 495 /* Set some Create Info and do not allow user-mode kernel handles */ 496 ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; 497 ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_KERNEL_ATTRIBUTES; 498 if (CreatorMode != KernelMode) ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE; 499 LocalObjectName = ObjectAttributes->ObjectName; 500 SecurityDescriptor = ObjectAttributes->SecurityDescriptor; 501 SecurityQos = ObjectAttributes->SecurityQualityOfService; 502 503 /* Check if we have a security descriptor */ 504 if (SecurityDescriptor) 505 { 506 /* Capture it. Note: This has an implicit memory barrier due 507 to the function call, so cleanup is safe here.) */ 508 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 509 AccessMode, 510 NonPagedPool, 511 TRUE, 512 &ObjectCreateInfo-> 513 SecurityDescriptor); 514 if (!NT_SUCCESS(Status)) 515 { 516 /* Capture failed, quit */ 517 ObjectCreateInfo->SecurityDescriptor = NULL; 518 _SEH2_YIELD(return Status); 519 } 520 521 /* Save the probe mode and security descriptor size */ 522 ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */ 523 ObjectCreateInfo->ProbeMode = AccessMode; 524 } 525 526 /* Check if we have QoS */ 527 if (SecurityQos) 528 { 529 /* Check if we came from user mode */ 530 if (AccessMode != KernelMode) 531 { 532 /* Validate the QoS */ 533 ProbeForRead(SecurityQos, 534 sizeof(SECURITY_QUALITY_OF_SERVICE), 535 sizeof(ULONG)); 536 } 537 538 /* Save Info */ 539 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; 540 ObjectCreateInfo->SecurityQos = 541 &ObjectCreateInfo->SecurityQualityOfService; 542 } 543 } 544 else 545 { 546 /* We don't have a name */ 547 LocalObjectName = NULL; 548 } 549 } 550 _SEH2_EXCEPT(ExSystemExceptionFilter()) 551 { 552 /* Cleanup and return the exception code */ 553 ObpReleaseObjectCreateInformation(ObjectCreateInfo); 554 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 555 } 556 _SEH2_END; 557 558 /* Now check if the Object Attributes had an Object Name */ 559 if (LocalObjectName) 560 { 561 Status = ObpCaptureObjectName(ObjectName, 562 LocalObjectName, 563 AccessMode, 564 AllocateFromLookaside); 565 } 566 else 567 { 568 /* Clear the string */ 569 RtlInitEmptyUnicodeString(ObjectName, NULL, 0); 570 571 /* It cannot have specified a Root Directory */ 572 if (ObjectCreateInfo->RootDirectory) 573 { 574 Status = STATUS_OBJECT_NAME_INVALID; 575 } 576 } 577 578 /* Cleanup if we failed */ 579 if (!NT_SUCCESS(Status)) 580 { 581 ObpReleaseObjectCreateInformation(ObjectCreateInfo); 582 } 583 584 /* Return status to caller */ 585 return Status; 586 } 587 588 VOID 589 NTAPI 590 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) 591 { 592 /* Call the macro. We use this function to isolate Ob internals from Io */ 593 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); 594 } 595 596 NTSTATUS 597 NTAPI 598 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, 599 IN PUNICODE_STRING ObjectName, 600 IN POBJECT_TYPE ObjectType, 601 IN ULONG ObjectSize, 602 IN KPROCESSOR_MODE PreviousMode, 603 IN POBJECT_HEADER *ObjectHeader) 604 { 605 POBJECT_HEADER Header; 606 ULONG QuotaSize, HandleSize, NameSize, CreatorSize; 607 POBJECT_HEADER_HANDLE_INFO HandleInfo; 608 POBJECT_HEADER_NAME_INFO NameInfo; 609 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 610 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 611 POOL_TYPE PoolType; 612 ULONG FinalSize; 613 ULONG Tag; 614 PAGED_CODE(); 615 616 /* Accounting */ 617 ObpObjectsCreated++; 618 619 /* Check if we don't have an Object Type yet */ 620 if (!ObjectType) 621 { 622 /* Use default tag and non-paged pool */ 623 PoolType = NonPagedPool; 624 Tag = 'TjbO'; 625 } 626 else 627 { 628 /* Use the pool and tag given */ 629 PoolType = ObjectType->TypeInfo.PoolType; 630 Tag = ObjectType->Key; 631 } 632 633 /* Check if we have no create information (ie: we're an object type) */ 634 if (!ObjectCreateInfo) 635 { 636 /* Use defaults */ 637 QuotaSize = HandleSize = 0; 638 NameSize = sizeof(OBJECT_HEADER_NAME_INFO); 639 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO); 640 } 641 else 642 { 643 /* Check if we have quota */ 644 if ((((ObjectCreateInfo->PagedPoolCharge != 645 ObjectType->TypeInfo.DefaultPagedPoolCharge) || 646 (ObjectCreateInfo->NonPagedPoolCharge != 647 ObjectType->TypeInfo.DefaultNonPagedPoolCharge) || 648 (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) && 649 (PsGetCurrentProcess() != PsInitialSystemProcess)) || 650 (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) 651 { 652 /* Set quota size */ 653 QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO); 654 ObpObjectsWithPoolQuota++; 655 } 656 else 657 { 658 /* No Quota */ 659 QuotaSize = 0; 660 } 661 662 /* Check if we have a handle database */ 663 if (ObjectType->TypeInfo.MaintainHandleCount) 664 { 665 /* Set handle database size */ 666 HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO); 667 ObpObjectsWithHandleDB++; 668 } 669 else 670 { 671 /* None */ 672 HandleSize = 0; 673 } 674 675 /* Check if the Object has a name */ 676 if (ObjectName->Buffer) 677 { 678 /* Set name size */ 679 NameSize = sizeof(OBJECT_HEADER_NAME_INFO); 680 ObpObjectsWithName++; 681 } 682 else 683 { 684 /* No name */ 685 NameSize = 0; 686 } 687 688 /* Check if the Object maintains type lists */ 689 if (ObjectType->TypeInfo.MaintainTypeList) 690 { 691 /* Set owner/creator size */ 692 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO); 693 ObpObjectsWithCreatorInfo++; 694 } 695 else 696 { 697 /* No info */ 698 CreatorSize = 0; 699 } 700 } 701 702 /* Set final header size */ 703 FinalSize = QuotaSize + 704 HandleSize + 705 NameSize + 706 CreatorSize + 707 FIELD_OFFSET(OBJECT_HEADER, Body); 708 709 /* Allocate memory for the Object and Header */ 710 Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag); 711 if (!Header) return STATUS_INSUFFICIENT_RESOURCES; 712 713 /* Check if we have a quota header */ 714 if (QuotaSize) 715 { 716 /* Initialize quota info */ 717 QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header; 718 QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge; 719 QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge; 720 QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge; 721 QuotaInfo->ExclusiveProcess = NULL; 722 Header = (POBJECT_HEADER)(QuotaInfo + 1); 723 } 724 725 /* Check if we have a handle database header */ 726 if (HandleSize) 727 { 728 /* Initialize Handle Info */ 729 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; 730 HandleInfo->SingleEntry.HandleCount = 0; 731 Header = (POBJECT_HEADER)(HandleInfo + 1); 732 } 733 734 /* Check if we have a name header */ 735 if (NameSize) 736 { 737 /* Initialize the Object Name Info */ 738 NameInfo = (POBJECT_HEADER_NAME_INFO)Header; 739 NameInfo->Name = *ObjectName; 740 NameInfo->Directory = NULL; 741 NameInfo->QueryReferences = 1; 742 743 /* Check if this is a call with the special protection flag */ 744 if ((PreviousMode == KernelMode) && 745 (ObjectCreateInfo) && 746 (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE)) 747 { 748 /* Set flag which will make the object protected from user-mode */ 749 NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE; 750 } 751 752 /* Set the header pointer */ 753 Header = (POBJECT_HEADER)(NameInfo + 1); 754 } 755 756 /* Check if we have a creator header */ 757 if (CreatorSize) 758 { 759 /* Initialize Creator Info */ 760 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; 761 CreatorInfo->CreatorBackTraceIndex = 0; 762 CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); 763 InitializeListHead(&CreatorInfo->TypeList); 764 Header = (POBJECT_HEADER)(CreatorInfo + 1); 765 } 766 767 /* Check for quota information */ 768 if (QuotaSize) 769 { 770 /* Set the offset */ 771 Header->QuotaInfoOffset = (UCHAR)(QuotaSize + 772 HandleSize + 773 NameSize + 774 CreatorSize); 775 } 776 else 777 { 778 /* No offset */ 779 Header->QuotaInfoOffset = 0; 780 } 781 782 /* Check for handle information */ 783 if (HandleSize) 784 { 785 /* Set the offset */ 786 Header->HandleInfoOffset = (UCHAR)(HandleSize + 787 NameSize + 788 CreatorSize); 789 } 790 else 791 { 792 /* No offset */ 793 Header->HandleInfoOffset = 0; 794 } 795 796 /* Check for name information */ 797 if (NameSize) 798 { 799 /* Set the offset */ 800 Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize); 801 } 802 else 803 { 804 /* No Name */ 805 Header->NameInfoOffset = 0; 806 } 807 808 /* Set the new object flag */ 809 Header->Flags = OB_FLAG_CREATE_INFO; 810 811 /* Remember if we have creator info */ 812 if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO; 813 814 /* Remember if we have handle info */ 815 if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS; 816 817 /* Initialize the object header */ 818 Header->PointerCount = 1; 819 Header->HandleCount = 0; 820 Header->Type = ObjectType; 821 Header->ObjectCreateInfo = ObjectCreateInfo; 822 Header->SecurityDescriptor = NULL; 823 824 /* Check if this is a permanent object */ 825 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT)) 826 { 827 /* Set the needed flag so we can check */ 828 Header->Flags |= OB_FLAG_PERMANENT; 829 } 830 831 /* Check if this is an exclusive object */ 832 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) 833 { 834 /* Set the needed flag so we can check */ 835 Header->Flags |= OB_FLAG_EXCLUSIVE; 836 } 837 838 /* Set kernel-mode flag */ 839 if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE; 840 841 /* Check if we have a type */ 842 if (ObjectType) 843 { 844 /* Increase the number of objects of this type */ 845 InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects); 846 847 /* Update the high water */ 848 ObjectType->HighWaterNumberOfObjects = max(ObjectType-> 849 TotalNumberOfObjects, 850 ObjectType-> 851 HighWaterNumberOfObjects); 852 } 853 854 /* Return Header */ 855 *ObjectHeader = Header; 856 return STATUS_SUCCESS; 857 } 858 859 NTSTATUS 860 NTAPI 861 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType, 862 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo, 863 IN ULONG Length, 864 OUT PULONG ReturnLength) 865 { 866 NTSTATUS Status = STATUS_SUCCESS; 867 PWSTR InfoBuffer; 868 869 /* Enter SEH */ 870 _SEH2_TRY 871 { 872 /* Set return length aligned to 4-byte boundary */ 873 *ReturnLength += sizeof(*ObjectTypeInfo) + 874 ALIGN_UP(ObjectType->Name.MaximumLength, ULONG); 875 876 /* Check if thats too much though. */ 877 if (Length < *ReturnLength) 878 { 879 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 880 } 881 882 /* Build the data */ 883 ObjectTypeInfo->TotalNumberOfHandles = 884 ObjectType->TotalNumberOfHandles; 885 ObjectTypeInfo->TotalNumberOfObjects = 886 ObjectType->TotalNumberOfObjects; 887 ObjectTypeInfo->HighWaterNumberOfHandles = 888 ObjectType->HighWaterNumberOfHandles; 889 ObjectTypeInfo->HighWaterNumberOfObjects = 890 ObjectType->HighWaterNumberOfObjects; 891 ObjectTypeInfo->PoolType = 892 ObjectType->TypeInfo.PoolType; 893 ObjectTypeInfo->DefaultNonPagedPoolCharge = 894 ObjectType->TypeInfo.DefaultNonPagedPoolCharge; 895 ObjectTypeInfo->DefaultPagedPoolCharge = 896 ObjectType->TypeInfo.DefaultPagedPoolCharge; 897 ObjectTypeInfo->ValidAccessMask = 898 ObjectType->TypeInfo.ValidAccessMask; 899 ObjectTypeInfo->SecurityRequired = 900 ObjectType->TypeInfo.SecurityRequired; 901 ObjectTypeInfo->InvalidAttributes = 902 ObjectType->TypeInfo.InvalidAttributes; 903 ObjectTypeInfo->GenericMapping = 904 ObjectType->TypeInfo.GenericMapping; 905 ObjectTypeInfo->MaintainHandleCount = 906 ObjectType->TypeInfo.MaintainHandleCount; 907 908 /* Setup the name buffer */ 909 InfoBuffer = (PWSTR)(ObjectTypeInfo + 1); 910 ObjectTypeInfo->TypeName.Buffer = InfoBuffer; 911 ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength; 912 ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length; 913 914 /* Copy it */ 915 RtlCopyMemory(InfoBuffer, 916 ObjectType->Name.Buffer, 917 ObjectType->Name.Length); 918 919 /* Null-terminate it */ 920 (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; 921 } 922 _SEH2_EXCEPT(ExSystemExceptionFilter()) 923 { 924 /* Otherwise, get the exception code */ 925 Status = _SEH2_GetExceptionCode(); 926 } 927 _SEH2_END; 928 929 /* Return status to caller */ 930 return Status; 931 } 932 933 934 /* PUBLIC FUNCTIONS **********************************************************/ 935 936 NTSTATUS 937 NTAPI 938 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, 939 IN POBJECT_TYPE Type, 940 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 941 IN KPROCESSOR_MODE AccessMode, 942 IN OUT PVOID ParseContext OPTIONAL, 943 IN ULONG ObjectSize, 944 IN ULONG PagedPoolCharge OPTIONAL, 945 IN ULONG NonPagedPoolCharge OPTIONAL, 946 OUT PVOID *Object) 947 { 948 NTSTATUS Status; 949 POBJECT_CREATE_INFORMATION ObjectCreateInfo; 950 UNICODE_STRING ObjectName; 951 POBJECT_HEADER Header; 952 953 /* Allocate a capture buffer */ 954 ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList); 955 if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES; 956 957 /* Capture all the info */ 958 Status = ObpCaptureObjectCreateInformation(ObjectAttributes, 959 ProbeMode, 960 AccessMode, 961 FALSE, 962 ObjectCreateInfo, 963 &ObjectName); 964 if (NT_SUCCESS(Status)) 965 { 966 /* Validate attributes */ 967 if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) 968 { 969 /* Fail */ 970 Status = STATUS_INVALID_PARAMETER; 971 } 972 else 973 { 974 /* Check if we have a paged charge */ 975 if (!PagedPoolCharge) 976 { 977 /* Save it */ 978 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge; 979 } 980 981 /* Check for nonpaged charge */ 982 if (!NonPagedPoolCharge) 983 { 984 /* Save it */ 985 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge; 986 } 987 988 /* Write the pool charges */ 989 ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge; 990 ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge; 991 992 /* Allocate the Object */ 993 Status = ObpAllocateObject(ObjectCreateInfo, 994 &ObjectName, 995 Type, 996 ObjectSize, 997 AccessMode, 998 &Header); 999 if (NT_SUCCESS(Status)) 1000 { 1001 /* Return the Object */ 1002 *Object = &Header->Body; 1003 1004 /* Check if this is a permanent object */ 1005 if (Header->Flags & OB_FLAG_PERMANENT) 1006 { 1007 /* Do the privilege check */ 1008 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, 1009 ProbeMode)) 1010 { 1011 /* Fail */ 1012 ObpDeallocateObject(*Object); 1013 Status = STATUS_PRIVILEGE_NOT_HELD; 1014 } 1015 } 1016 1017 /* Return status */ 1018 return Status; 1019 } 1020 } 1021 1022 /* Release the Capture Info, we don't need it */ 1023 ObpFreeObjectCreateInformation(ObjectCreateInfo); 1024 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName); 1025 } 1026 1027 /* We failed, so release the Buffer */ 1028 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); 1029 return Status; 1030 } 1031 1032 NTSTATUS 1033 NTAPI 1034 ObCreateObjectType(IN PUNICODE_STRING TypeName, 1035 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, 1036 IN PVOID Reserved, 1037 OUT POBJECT_TYPE *ObjectType) 1038 { 1039 POBJECT_HEADER Header; 1040 POBJECT_TYPE LocalObjectType; 1041 ULONG HeaderSize; 1042 NTSTATUS Status; 1043 OBP_LOOKUP_CONTEXT Context; 1044 PWCHAR p; 1045 ULONG i; 1046 UNICODE_STRING ObjectName; 1047 ANSI_STRING AnsiName; 1048 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 1049 1050 /* Verify parameters */ 1051 if (!(TypeName) || 1052 !(TypeName->Length) || 1053 (TypeName->Length % sizeof(WCHAR)) || 1054 !(ObjectTypeInitializer) || 1055 (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) || 1056 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) || 1057 (ObjectTypeInitializer->MaintainHandleCount && 1058 (!(ObjectTypeInitializer->OpenProcedure) && 1059 !ObjectTypeInitializer->CloseProcedure)) || 1060 ((!ObjectTypeInitializer->UseDefaultObject) && 1061 (ObjectTypeInitializer->PoolType != NonPagedPool))) 1062 { 1063 /* Fail */ 1064 return STATUS_INVALID_PARAMETER; 1065 } 1066 1067 /* Make sure the name doesn't have a separator */ 1068 p = TypeName->Buffer; 1069 i = TypeName->Length / sizeof(WCHAR); 1070 while (i--) 1071 { 1072 /* Check for one and fail */ 1073 if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID; 1074 } 1075 1076 /* Setup a lookup context */ 1077 ObpInitializeLookupContext(&Context); 1078 1079 /* Check if we've already created the directory of types */ 1080 if (ObpTypeDirectoryObject) 1081 { 1082 /* Acquire the directory lock */ 1083 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context); 1084 1085 /* Do the lookup */ 1086 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject, 1087 TypeName, 1088 OBJ_CASE_INSENSITIVE, 1089 FALSE, 1090 &Context)) 1091 { 1092 /* We have already created it, so fail */ 1093 ObpReleaseLookupContext(&Context); 1094 return STATUS_OBJECT_NAME_COLLISION; 1095 } 1096 } 1097 1098 /* Now make a copy of the object name */ 1099 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1100 TypeName->MaximumLength, 1101 OB_NAME_TAG); 1102 if (!ObjectName.Buffer) 1103 { 1104 /* Out of memory, fail */ 1105 ObpReleaseLookupContext(&Context); 1106 return STATUS_INSUFFICIENT_RESOURCES; 1107 } 1108 1109 /* Set the length and copy the name */ 1110 ObjectName.MaximumLength = TypeName->MaximumLength; 1111 RtlCopyUnicodeString(&ObjectName, TypeName); 1112 1113 /* Allocate the Object */ 1114 Status = ObpAllocateObject(NULL, 1115 &ObjectName, 1116 ObpTypeObjectType, 1117 sizeof(OBJECT_TYPE), 1118 KernelMode, 1119 &Header); 1120 if (!NT_SUCCESS(Status)) 1121 { 1122 /* Free the name and fail */ 1123 ObpReleaseLookupContext(&Context); 1124 ExFreePool(ObjectName.Buffer); 1125 return Status; 1126 } 1127 1128 /* Setup the flags and name */ 1129 LocalObjectType = (POBJECT_TYPE)&Header->Body; 1130 LocalObjectType->Name = ObjectName; 1131 Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT; 1132 1133 /* Clear accounting data */ 1134 LocalObjectType->TotalNumberOfObjects = 1135 LocalObjectType->TotalNumberOfHandles = 1136 LocalObjectType->HighWaterNumberOfObjects = 1137 LocalObjectType->HighWaterNumberOfHandles = 0; 1138 1139 /* Check if this is the first Object Type */ 1140 if (!ObpTypeObjectType) 1141 { 1142 /* It is, so set this as the type object */ 1143 ObpTypeObjectType = LocalObjectType; 1144 Header->Type = ObpTypeObjectType; 1145 1146 /* Set the hard-coded key and object count */ 1147 LocalObjectType->TotalNumberOfObjects = 1; 1148 LocalObjectType->Key = 'TjbO'; 1149 } 1150 else 1151 { 1152 /* Convert the tag to ASCII */ 1153 Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE); 1154 if (NT_SUCCESS(Status)) 1155 { 1156 /* For every missing character, use a space */ 1157 for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' '; 1158 1159 /* Set the key and free the converted name */ 1160 LocalObjectType->Key = *(PULONG)AnsiName.Buffer; 1161 RtlFreeAnsiString(&AnsiName); 1162 } 1163 else 1164 { 1165 /* Just copy the characters */ 1166 LocalObjectType->Key = *(PULONG)TypeName->Buffer; 1167 } 1168 } 1169 1170 /* Set up the type information */ 1171 LocalObjectType->TypeInfo = *ObjectTypeInitializer; 1172 LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType; 1173 1174 /* Check if we have to maintain a type list */ 1175 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) 1176 { 1177 /* Enable support */ 1178 LocalObjectType->TypeInfo.MaintainTypeList = TRUE; 1179 } 1180 1181 /* Calculate how much space our header'll take up */ 1182 HeaderSize = sizeof(OBJECT_HEADER) + 1183 sizeof(OBJECT_HEADER_NAME_INFO) + 1184 (ObjectTypeInitializer->MaintainHandleCount ? 1185 sizeof(OBJECT_HEADER_HANDLE_INFO) : 0); 1186 1187 /* Check the pool type */ 1188 if (ObjectTypeInitializer->PoolType == NonPagedPool) 1189 { 1190 /* Update the NonPaged Pool charge */ 1191 LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize; 1192 } 1193 else 1194 { 1195 /* Update the Paged Pool charge */ 1196 LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize; 1197 } 1198 1199 /* All objects types need a security procedure */ 1200 if (!ObjectTypeInitializer->SecurityProcedure) 1201 { 1202 LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; 1203 } 1204 1205 /* Select the Wait Object */ 1206 if (LocalObjectType->TypeInfo.UseDefaultObject) 1207 { 1208 /* Add the SYNCHRONIZE access mask since it's waitable */ 1209 LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; 1210 1211 /* Use the "Default Object", a simple event */ 1212 LocalObjectType->DefaultObject = &ObpDefaultObject; 1213 } 1214 /* The File Object gets an optimized hack so it can be waited on */ 1215 else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File"))) 1216 { 1217 /* Wait on the File Object's event directly */ 1218 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT, 1219 Event)); 1220 } 1221 else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort"))) 1222 { 1223 /* Wait on the LPC Port's object directly */ 1224 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT, 1225 WaitEvent)); 1226 } 1227 else 1228 { 1229 /* No default Object */ 1230 LocalObjectType->DefaultObject = NULL; 1231 } 1232 1233 /* Initialize Object Type components */ 1234 ExInitializeResourceLite(&LocalObjectType->Mutex); 1235 for (i = 0; i < 4; i++) 1236 { 1237 /* Initialize the object locks */ 1238 ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]); 1239 } 1240 InitializeListHead(&LocalObjectType->TypeList); 1241 1242 /* Lock the object type */ 1243 ObpEnterObjectTypeMutex(ObpTypeObjectType); 1244 1245 /* Get creator info and insert it into the type list */ 1246 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); 1247 if (CreatorInfo) 1248 { 1249 InsertTailList(&ObpTypeObjectType->TypeList, 1250 &CreatorInfo->TypeList); 1251 1252 /* CORE-8423: Avoid inserting this a second time if someone creates a 1253 * handle to the object type (bug in Windows 2003) */ 1254 Header->Flags &= ~OB_FLAG_CREATE_INFO; 1255 } 1256 1257 /* Set the index and the entry into the object type array */ 1258 LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects; 1259 1260 ASSERT(LocalObjectType->Index != 0); 1261 1262 if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes)) 1263 { 1264 /* It fits, insert it */ 1265 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType; 1266 } 1267 1268 /* Release the object type */ 1269 ObpLeaveObjectTypeMutex(ObpTypeObjectType); 1270 1271 /* Check if we're actually creating the directory object itself */ 1272 if (!(ObpTypeDirectoryObject) || 1273 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header))) 1274 { 1275 /* Check if the type directory exists */ 1276 if (ObpTypeDirectoryObject) 1277 { 1278 /* Reference it */ 1279 ObReferenceObject(ObpTypeDirectoryObject); 1280 } 1281 1282 /* Cleanup the lookup context */ 1283 ObpReleaseLookupContext(&Context); 1284 1285 /* Return the object type and success */ 1286 *ObjectType = LocalObjectType; 1287 return STATUS_SUCCESS; 1288 } 1289 1290 /* If we got here, then we failed */ 1291 ObpReleaseLookupContext(&Context); 1292 return STATUS_INSUFFICIENT_RESOURCES; 1293 } 1294 1295 VOID 1296 NTAPI 1297 ObDeleteCapturedInsertInfo(IN PVOID Object) 1298 { 1299 POBJECT_HEADER ObjectHeader; 1300 PAGED_CODE(); 1301 1302 /* Check if there is anything to free */ 1303 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1304 if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) && 1305 (ObjectHeader->ObjectCreateInfo != NULL)) 1306 { 1307 /* Free the create info */ 1308 ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo); 1309 ObjectHeader->ObjectCreateInfo = NULL; 1310 } 1311 } 1312 1313 VOID 1314 NTAPI 1315 ObpDeleteObjectType(IN PVOID Object) 1316 { 1317 ULONG i; 1318 POBJECT_TYPE ObjectType = (PVOID)Object; 1319 1320 /* Loop our locks */ 1321 for (i = 0; i < 4; i++) 1322 { 1323 /* Delete each one */ 1324 ExDeleteResourceLite(&ObjectType->ObjectLocks[i]); 1325 } 1326 1327 /* Delete our main mutex */ 1328 ExDeleteResourceLite(&ObjectType->Mutex); 1329 } 1330 1331 /*++ 1332 * @name ObMakeTemporaryObject 1333 * @implemented NT4 1334 * 1335 * The ObMakeTemporaryObject routine <FILLMEIN> 1336 * 1337 * @param ObjectBody 1338 * <FILLMEIN> 1339 * 1340 * @return None. 1341 * 1342 * @remarks None. 1343 * 1344 *--*/ 1345 VOID 1346 NTAPI 1347 ObMakeTemporaryObject(IN PVOID ObjectBody) 1348 { 1349 PAGED_CODE(); 1350 1351 /* Call the internal API */ 1352 ObpSetPermanentObject(ObjectBody, FALSE); 1353 } 1354 1355 /*++ 1356 * @name NtMakeTemporaryObject 1357 * @implemented NT4 1358 * 1359 * The NtMakeTemporaryObject routine <FILLMEIN> 1360 * 1361 * @param ObjectHandle 1362 * <FILLMEIN> 1363 * 1364 * @return STATUS_SUCCESS or appropriate error value. 1365 * 1366 * @remarks None. 1367 * 1368 *--*/ 1369 NTSTATUS 1370 NTAPI 1371 NtMakeTemporaryObject(IN HANDLE ObjectHandle) 1372 { 1373 PVOID ObjectBody; 1374 NTSTATUS Status; 1375 PAGED_CODE(); 1376 1377 /* Reference the object for DELETE access */ 1378 Status = ObReferenceObjectByHandle(ObjectHandle, 1379 DELETE, 1380 NULL, 1381 KeGetPreviousMode(), 1382 &ObjectBody, 1383 NULL); 1384 if (Status != STATUS_SUCCESS) return Status; 1385 1386 /* Set it as temporary and dereference it */ 1387 ObpSetPermanentObject(ObjectBody, FALSE); 1388 ObDereferenceObject(ObjectBody); 1389 return STATUS_SUCCESS; 1390 } 1391 1392 /*++ 1393 * @name NtMakePermanentObject 1394 * @implemented NT4 1395 * 1396 * The NtMakePermanentObject routine <FILLMEIN> 1397 * 1398 * @param ObjectHandle 1399 * <FILLMEIN> 1400 * 1401 * @return STATUS_SUCCESS or appropriate error value. 1402 * 1403 * @remarks None. 1404 * 1405 *--*/ 1406 NTSTATUS 1407 NTAPI 1408 NtMakePermanentObject(IN HANDLE ObjectHandle) 1409 { 1410 PVOID ObjectBody; 1411 NTSTATUS Status; 1412 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1413 PAGED_CODE(); 1414 1415 /* Make sure that the caller has SeCreatePermanentPrivilege */ 1416 Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, 1417 PreviousMode); 1418 if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD; 1419 1420 /* Reference the object */ 1421 Status = ObReferenceObjectByHandle(ObjectHandle, 1422 0, 1423 NULL, 1424 PreviousMode, 1425 &ObjectBody, 1426 NULL); 1427 if (Status != STATUS_SUCCESS) return Status; 1428 1429 /* Set it as permanent and dereference it */ 1430 ObpSetPermanentObject(ObjectBody, TRUE); 1431 ObDereferenceObject(ObjectBody); 1432 return STATUS_SUCCESS; 1433 } 1434 1435 /*++ 1436 * @name NtQueryObject 1437 * @implemented NT4 1438 * 1439 * The NtQueryObject routine <FILLMEIN> 1440 * 1441 * @param ObjectHandle 1442 * <FILLMEIN> 1443 * 1444 * @param ObjectInformationClass 1445 * <FILLMEIN> 1446 * 1447 * @param ObjectInformation 1448 * <FILLMEIN> 1449 * 1450 * @param Length 1451 * <FILLMEIN> 1452 * 1453 * @param ResultLength 1454 * <FILLMEIN> 1455 * 1456 * @return STATUS_SUCCESS or appropriate error value. 1457 * 1458 * @remarks None. 1459 * 1460 *--*/ 1461 NTSTATUS 1462 NTAPI 1463 NtQueryObject(IN HANDLE ObjectHandle, 1464 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1465 OUT PVOID ObjectInformation, 1466 IN ULONG Length, 1467 OUT PULONG ResultLength OPTIONAL) 1468 { 1469 OBJECT_HANDLE_INFORMATION HandleInfo; 1470 POBJECT_HEADER ObjectHeader = NULL; 1471 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags; 1472 POBJECT_BASIC_INFORMATION BasicInfo; 1473 ULONG InfoLength = 0; 1474 PVOID Object = NULL; 1475 NTSTATUS Status; 1476 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1477 PAGED_CODE(); 1478 1479 /* Check if the caller is from user mode */ 1480 if (PreviousMode != KernelMode) 1481 { 1482 /* Protect validation with SEH */ 1483 _SEH2_TRY 1484 { 1485 /* Probe the input structure */ 1486 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR)); 1487 1488 /* If we have a result length, probe it too */ 1489 if (ResultLength) ProbeForWriteUlong(ResultLength); 1490 } 1491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1492 { 1493 /* Return the exception code */ 1494 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1495 } 1496 _SEH2_END; 1497 } 1498 1499 /* 1500 * Make sure this isn't a generic type query, since the caller doesn't 1501 * have to give a handle for it 1502 */ 1503 if (ObjectInformationClass != ObjectTypesInformation) 1504 { 1505 /* Reference the object */ 1506 Status = ObReferenceObjectByHandle(ObjectHandle, 1507 0, 1508 NULL, 1509 KeGetPreviousMode(), 1510 &Object, 1511 &HandleInfo); 1512 if (!NT_SUCCESS (Status)) return Status; 1513 1514 /* Get the object header */ 1515 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1516 } 1517 1518 _SEH2_TRY 1519 { 1520 /* Check the information class */ 1521 switch (ObjectInformationClass) 1522 { 1523 /* Basic info */ 1524 case ObjectBasicInformation: 1525 1526 /* Validate length */ 1527 InfoLength = sizeof(OBJECT_BASIC_INFORMATION); 1528 if (Length != sizeof(OBJECT_BASIC_INFORMATION)) 1529 { 1530 /* Fail */ 1531 Status = STATUS_INFO_LENGTH_MISMATCH; 1532 break; 1533 } 1534 1535 /* Fill out the basic information */ 1536 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation; 1537 BasicInfo->Attributes = HandleInfo.HandleAttributes; 1538 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; 1539 BasicInfo->HandleCount = ObjectHeader->HandleCount; 1540 BasicInfo->PointerCount = ObjectHeader->PointerCount; 1541 1542 /* Permanent/Exclusive Flags are NOT in Handle attributes! */ 1543 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) 1544 { 1545 /* Set the flag */ 1546 BasicInfo->Attributes |= OBJ_EXCLUSIVE; 1547 } 1548 if (ObjectHeader->Flags & OB_FLAG_PERMANENT) 1549 { 1550 /* Set the flag */ 1551 BasicInfo->Attributes |= OBJ_PERMANENT; 1552 } 1553 1554 /* Copy quota information */ 1555 BasicInfo->PagedPoolCharge = 0; /* FIXME*/ 1556 BasicInfo->NonPagedPoolCharge = 0; /* FIXME*/ 1557 1558 /* Copy name information */ 1559 BasicInfo->NameInfoSize = 0; /* FIXME*/ 1560 BasicInfo->TypeInfoSize = 0; /* FIXME*/ 1561 1562 /* Copy security information */ 1563 BasicInfo->SecurityDescriptorSize = 0; /* FIXME*/ 1564 1565 /* Check if this is a symlink */ 1566 if (ObjectHeader->Type == ObSymbolicLinkType) 1567 { 1568 /* Return the creation time */ 1569 BasicInfo->CreationTime.QuadPart = 1570 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; 1571 } 1572 else 1573 { 1574 /* Otherwise return 0 */ 1575 BasicInfo->CreationTime.QuadPart = (ULONGLONG)0; 1576 } 1577 1578 /* Break out with success */ 1579 Status = STATUS_SUCCESS; 1580 break; 1581 1582 /* Name information */ 1583 case ObjectNameInformation: 1584 1585 /* Call the helper and break out */ 1586 Status = ObQueryNameString(Object, 1587 (POBJECT_NAME_INFORMATION) 1588 ObjectInformation, 1589 Length, 1590 &InfoLength); 1591 break; 1592 1593 /* Information about this type */ 1594 case ObjectTypeInformation: 1595 1596 /* Call the helper and break out */ 1597 Status = ObQueryTypeInfo(ObjectHeader->Type, 1598 (POBJECT_TYPE_INFORMATION) 1599 ObjectInformation, 1600 Length, 1601 &InfoLength); 1602 break; 1603 1604 /* Information about all types */ 1605 case ObjectTypesInformation: 1606 DPRINT1("NOT IMPLEMENTED!\n"); 1607 InfoLength = Length; 1608 Status = STATUS_NOT_IMPLEMENTED; 1609 break; 1610 1611 /* Information about the handle flags */ 1612 case ObjectHandleFlagInformation: 1613 1614 /* Validate length */ 1615 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION); 1616 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1617 { 1618 Status = STATUS_INFO_LENGTH_MISMATCH; 1619 break; 1620 } 1621 1622 /* Get the structure */ 1623 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1624 ObjectInformation; 1625 1626 /* Set the flags */ 1627 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT; 1628 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes & 1629 OBJ_PROTECT_CLOSE) != 0; 1630 1631 /* Break out with success */ 1632 Status = STATUS_SUCCESS; 1633 break; 1634 1635 /* Anything else */ 1636 default: 1637 1638 /* Fail it */ 1639 InfoLength = Length; 1640 Status = STATUS_INVALID_INFO_CLASS; 1641 break; 1642 } 1643 1644 /* Check if the caller wanted the return length */ 1645 if (ResultLength) 1646 { 1647 /* Write the length */ 1648 *ResultLength = InfoLength; 1649 } 1650 } 1651 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1652 { 1653 /* Otherwise, get the exception code */ 1654 Status = _SEH2_GetExceptionCode(); 1655 } 1656 _SEH2_END; 1657 1658 /* Dereference the object if we had referenced it */ 1659 if (Object) ObDereferenceObject(Object); 1660 1661 /* Return status */ 1662 return Status; 1663 } 1664 1665 /*++ 1666 * @name NtSetInformationObject 1667 * @implemented NT4 1668 * 1669 * The NtSetInformationObject routine <FILLMEIN> 1670 * 1671 * @param ObjectHandle 1672 * <FILLMEIN> 1673 * 1674 * @param ObjectInformationClass 1675 * <FILLMEIN> 1676 * 1677 * @param ObjectInformation 1678 * <FILLMEIN> 1679 * 1680 * @param Length 1681 * <FILLMEIN> 1682 * 1683 * @return STATUS_SUCCESS or appropriate error value. 1684 * 1685 * @remarks None. 1686 * 1687 *--*/ 1688 NTSTATUS 1689 NTAPI 1690 NtSetInformationObject(IN HANDLE ObjectHandle, 1691 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1692 IN PVOID ObjectInformation, 1693 IN ULONG Length) 1694 { 1695 NTSTATUS Status; 1696 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context; 1697 PVOID ObjectTable; 1698 KAPC_STATE ApcState; 1699 POBJECT_DIRECTORY Directory; 1700 KPROCESSOR_MODE PreviousMode; 1701 BOOLEAN AttachedToProcess = FALSE; 1702 PAGED_CODE(); 1703 1704 /* Validate the information class */ 1705 switch (ObjectInformationClass) 1706 { 1707 case ObjectHandleFlagInformation: 1708 1709 /* Validate the length */ 1710 if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1711 { 1712 /* Invalid length */ 1713 return STATUS_INFO_LENGTH_MISMATCH; 1714 } 1715 1716 /* Save the previous mode */ 1717 Context.PreviousMode = ExGetPreviousMode(); 1718 1719 /* Check if we were called from user mode */ 1720 if (Context.PreviousMode != KernelMode) 1721 { 1722 /* Enter SEH */ 1723 _SEH2_TRY 1724 { 1725 /* Probe and capture the attribute buffer */ 1726 ProbeForRead(ObjectInformation, 1727 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION), 1728 sizeof(BOOLEAN)); 1729 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1730 ObjectInformation; 1731 } 1732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1733 { 1734 /* Return the exception code */ 1735 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1736 } 1737 _SEH2_END; 1738 } 1739 else 1740 { 1741 /* Just copy the buffer directly */ 1742 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1743 ObjectInformation; 1744 } 1745 1746 /* Check if this is a kernel handle */ 1747 if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode)) 1748 { 1749 /* Get the actual handle */ 1750 ObjectHandle = ObKernelHandleToHandle(ObjectHandle); 1751 ObjectTable = ObpKernelHandleTable; 1752 1753 /* Check if we're not in the system process */ 1754 if (PsGetCurrentProcess() != PsInitialSystemProcess) 1755 { 1756 /* Attach to it */ 1757 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 1758 AttachedToProcess = TRUE; 1759 } 1760 } 1761 else 1762 { 1763 /* Use the current table */ 1764 ObjectTable = PsGetCurrentProcess()->ObjectTable; 1765 } 1766 1767 /* Change the handle attributes */ 1768 if (!ExChangeHandle(ObjectTable, 1769 ObjectHandle, 1770 ObpSetHandleAttributes, 1771 (ULONG_PTR)&Context)) 1772 { 1773 /* Some failure */ 1774 Status = STATUS_ACCESS_DENIED; 1775 } 1776 else 1777 { 1778 /* We are done */ 1779 Status = STATUS_SUCCESS; 1780 } 1781 1782 /* De-attach if we were attached, and return status */ 1783 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState); 1784 break; 1785 1786 case ObjectSessionInformation: 1787 1788 /* Only a system process can do this */ 1789 PreviousMode = ExGetPreviousMode(); 1790 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1791 { 1792 /* Fail */ 1793 DPRINT1("Privilege not held\n"); 1794 Status = STATUS_PRIVILEGE_NOT_HELD; 1795 } 1796 else 1797 { 1798 /* Get the object directory */ 1799 Status = ObReferenceObjectByHandle(ObjectHandle, 1800 0, 1801 ObDirectoryType, 1802 PreviousMode, 1803 (PVOID*)&Directory, 1804 NULL); 1805 if (NT_SUCCESS(Status)) 1806 { 1807 /* FIXME: Missng locks */ 1808 /* Set its session ID */ 1809 Directory->SessionId = PsGetCurrentProcessSessionId(); 1810 ObDereferenceObject(Directory); 1811 } 1812 } 1813 break; 1814 1815 default: 1816 /* Unsupported class */ 1817 Status = STATUS_INVALID_INFO_CLASS; 1818 break; 1819 } 1820 1821 return Status; 1822 } 1823 1824 /* EOF */ 1825