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 ULONG SdCharge, QuotaInfoSize; 464 NTSTATUS Status = STATUS_SUCCESS; 465 PSECURITY_DESCRIPTOR SecurityDescriptor; 466 PSECURITY_QUALITY_OF_SERVICE SecurityQos; 467 PUNICODE_STRING LocalObjectName = NULL; 468 PAGED_CODE(); 469 470 /* Zero out the Capture Data */ 471 RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); 472 473 /* SEH everything here for protection */ 474 _SEH2_TRY 475 { 476 /* Check if we got attributes */ 477 if (ObjectAttributes) 478 { 479 /* Check if we're in user mode */ 480 if (AccessMode != KernelMode) 481 { 482 /* Probe the attributes */ 483 ProbeForRead(ObjectAttributes, 484 sizeof(OBJECT_ATTRIBUTES), 485 sizeof(ULONG)); 486 } 487 488 /* Validate the Size and Attributes */ 489 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || 490 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) 491 { 492 /* Invalid combination, fail */ 493 _SEH2_YIELD(return STATUS_INVALID_PARAMETER); 494 } 495 496 /* Set some Create Info and do not allow user-mode kernel handles */ 497 ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; 498 ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_KERNEL_ATTRIBUTES; 499 if (CreatorMode != KernelMode) ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE; 500 LocalObjectName = ObjectAttributes->ObjectName; 501 SecurityDescriptor = ObjectAttributes->SecurityDescriptor; 502 SecurityQos = ObjectAttributes->SecurityQualityOfService; 503 504 /* Check if we have a security descriptor */ 505 if (SecurityDescriptor) 506 { 507 /* Capture it. Note: This has an implicit memory barrier due 508 to the function call, so cleanup is safe here.) */ 509 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 510 AccessMode, 511 NonPagedPool, 512 TRUE, 513 &ObjectCreateInfo-> 514 SecurityDescriptor); 515 if (!NT_SUCCESS(Status)) 516 { 517 /* Capture failed, quit */ 518 ObjectCreateInfo->SecurityDescriptor = NULL; 519 _SEH2_YIELD(return Status); 520 } 521 522 /* 523 * By default, assume a SD size of 1024 and allow twice its 524 * size. 525 * If SD size happen to be bigger than that, then allow it 526 */ 527 SdCharge = 2048; 528 SeComputeQuotaInformationSize(ObjectCreateInfo->SecurityDescriptor, 529 &QuotaInfoSize); 530 if ((2 * QuotaInfoSize) > 2048) 531 { 532 SdCharge = 2 * QuotaInfoSize; 533 } 534 535 /* Save the probe mode and security descriptor size */ 536 ObjectCreateInfo->SecurityDescriptorCharge = SdCharge; 537 ObjectCreateInfo->ProbeMode = AccessMode; 538 } 539 540 /* Check if we have QoS */ 541 if (SecurityQos) 542 { 543 /* Check if we came from user mode */ 544 if (AccessMode != KernelMode) 545 { 546 /* Validate the QoS */ 547 ProbeForRead(SecurityQos, 548 sizeof(SECURITY_QUALITY_OF_SERVICE), 549 sizeof(ULONG)); 550 } 551 552 /* Save Info */ 553 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; 554 ObjectCreateInfo->SecurityQos = 555 &ObjectCreateInfo->SecurityQualityOfService; 556 } 557 } 558 else 559 { 560 /* We don't have a name */ 561 LocalObjectName = NULL; 562 } 563 } 564 _SEH2_EXCEPT(ExSystemExceptionFilter()) 565 { 566 /* Cleanup and return the exception code */ 567 ObpReleaseObjectCreateInformation(ObjectCreateInfo); 568 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 569 } 570 _SEH2_END; 571 572 /* Now check if the Object Attributes had an Object Name */ 573 if (LocalObjectName) 574 { 575 Status = ObpCaptureObjectName(ObjectName, 576 LocalObjectName, 577 AccessMode, 578 AllocateFromLookaside); 579 } 580 else 581 { 582 /* Clear the string */ 583 RtlInitEmptyUnicodeString(ObjectName, NULL, 0); 584 585 /* It cannot have specified a Root Directory */ 586 if (ObjectCreateInfo->RootDirectory) 587 { 588 Status = STATUS_OBJECT_NAME_INVALID; 589 } 590 } 591 592 /* Cleanup if we failed */ 593 if (!NT_SUCCESS(Status)) 594 { 595 ObpReleaseObjectCreateInformation(ObjectCreateInfo); 596 } 597 598 /* Return status to caller */ 599 return Status; 600 } 601 602 VOID 603 NTAPI 604 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) 605 { 606 /* Call the macro. We use this function to isolate Ob internals from Io */ 607 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); 608 } 609 610 NTSTATUS 611 NTAPI 612 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, 613 IN PUNICODE_STRING ObjectName, 614 IN POBJECT_TYPE ObjectType, 615 IN ULONG ObjectSize, 616 IN KPROCESSOR_MODE PreviousMode, 617 IN POBJECT_HEADER *ObjectHeader) 618 { 619 POBJECT_HEADER Header; 620 ULONG QuotaSize, HandleSize, NameSize, CreatorSize; 621 POBJECT_HEADER_HANDLE_INFO HandleInfo; 622 POBJECT_HEADER_NAME_INFO NameInfo; 623 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 624 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 625 POOL_TYPE PoolType; 626 ULONG FinalSize; 627 ULONG Tag; 628 PAGED_CODE(); 629 630 /* Accounting */ 631 ObpObjectsCreated++; 632 633 /* Check if we don't have an Object Type yet */ 634 if (!ObjectType) 635 { 636 /* Use default tag and non-paged pool */ 637 PoolType = NonPagedPool; 638 Tag = 'TjbO'; 639 } 640 else 641 { 642 /* Use the pool and tag given */ 643 PoolType = ObjectType->TypeInfo.PoolType; 644 Tag = ObjectType->Key; 645 } 646 647 /* Check if we have no create information (ie: we're an object type) */ 648 if (!ObjectCreateInfo) 649 { 650 /* Use defaults */ 651 QuotaSize = HandleSize = 0; 652 NameSize = sizeof(OBJECT_HEADER_NAME_INFO); 653 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO); 654 } 655 else 656 { 657 /* Check if we have quota */ 658 if ((((ObjectCreateInfo->PagedPoolCharge != 659 ObjectType->TypeInfo.DefaultPagedPoolCharge) || 660 (ObjectCreateInfo->NonPagedPoolCharge != 661 ObjectType->TypeInfo.DefaultNonPagedPoolCharge) || 662 (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) && 663 (PsGetCurrentProcess() != PsInitialSystemProcess)) || 664 (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) 665 { 666 /* Set quota size */ 667 QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO); 668 ObpObjectsWithPoolQuota++; 669 } 670 else 671 { 672 /* No Quota */ 673 QuotaSize = 0; 674 } 675 676 /* Check if we have a handle database */ 677 if (ObjectType->TypeInfo.MaintainHandleCount) 678 { 679 /* Set handle database size */ 680 HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO); 681 ObpObjectsWithHandleDB++; 682 } 683 else 684 { 685 /* None */ 686 HandleSize = 0; 687 } 688 689 /* Check if the Object has a name */ 690 if (ObjectName->Buffer) 691 { 692 /* Set name size */ 693 NameSize = sizeof(OBJECT_HEADER_NAME_INFO); 694 ObpObjectsWithName++; 695 } 696 else 697 { 698 /* No name */ 699 NameSize = 0; 700 } 701 702 /* Check if the Object maintains type lists */ 703 if (ObjectType->TypeInfo.MaintainTypeList) 704 { 705 /* Set owner/creator size */ 706 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO); 707 ObpObjectsWithCreatorInfo++; 708 } 709 else 710 { 711 /* No info */ 712 CreatorSize = 0; 713 } 714 } 715 716 /* Set final header size */ 717 FinalSize = QuotaSize + 718 HandleSize + 719 NameSize + 720 CreatorSize + 721 FIELD_OFFSET(OBJECT_HEADER, Body); 722 723 /* Allocate memory for the Object and Header */ 724 Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag); 725 if (!Header) return STATUS_INSUFFICIENT_RESOURCES; 726 727 /* Check if we have a quota header */ 728 if (QuotaSize) 729 { 730 /* Initialize quota info */ 731 QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header; 732 QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge; 733 QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge; 734 QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge; 735 QuotaInfo->ExclusiveProcess = NULL; 736 Header = (POBJECT_HEADER)(QuotaInfo + 1); 737 } 738 739 /* Check if we have a handle database header */ 740 if (HandleSize) 741 { 742 /* Initialize Handle Info */ 743 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; 744 HandleInfo->SingleEntry.HandleCount = 0; 745 Header = (POBJECT_HEADER)(HandleInfo + 1); 746 } 747 748 /* Check if we have a name header */ 749 if (NameSize) 750 { 751 /* Initialize the Object Name Info */ 752 NameInfo = (POBJECT_HEADER_NAME_INFO)Header; 753 NameInfo->Name = *ObjectName; 754 NameInfo->Directory = NULL; 755 NameInfo->QueryReferences = 1; 756 757 /* Check if this is a call with the special protection flag */ 758 if ((PreviousMode == KernelMode) && 759 (ObjectCreateInfo) && 760 (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE)) 761 { 762 /* Set flag which will make the object protected from user-mode */ 763 NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE; 764 } 765 766 /* Set the header pointer */ 767 Header = (POBJECT_HEADER)(NameInfo + 1); 768 } 769 770 /* Check if we have a creator header */ 771 if (CreatorSize) 772 { 773 /* Initialize Creator Info */ 774 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; 775 CreatorInfo->CreatorBackTraceIndex = 0; 776 CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); 777 InitializeListHead(&CreatorInfo->TypeList); 778 Header = (POBJECT_HEADER)(CreatorInfo + 1); 779 } 780 781 /* Check for quota information */ 782 if (QuotaSize) 783 { 784 /* Set the offset */ 785 Header->QuotaInfoOffset = (UCHAR)(QuotaSize + 786 HandleSize + 787 NameSize + 788 CreatorSize); 789 } 790 else 791 { 792 /* No offset */ 793 Header->QuotaInfoOffset = 0; 794 } 795 796 /* Check for handle information */ 797 if (HandleSize) 798 { 799 /* Set the offset */ 800 Header->HandleInfoOffset = (UCHAR)(HandleSize + 801 NameSize + 802 CreatorSize); 803 } 804 else 805 { 806 /* No offset */ 807 Header->HandleInfoOffset = 0; 808 } 809 810 /* Check for name information */ 811 if (NameSize) 812 { 813 /* Set the offset */ 814 Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize); 815 } 816 else 817 { 818 /* No Name */ 819 Header->NameInfoOffset = 0; 820 } 821 822 /* Set the new object flag */ 823 Header->Flags = OB_FLAG_CREATE_INFO; 824 825 /* Remember if we have creator info */ 826 if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO; 827 828 /* Remember if we have handle info */ 829 if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS; 830 831 /* Initialize the object header */ 832 Header->PointerCount = 1; 833 Header->HandleCount = 0; 834 Header->Type = ObjectType; 835 Header->ObjectCreateInfo = ObjectCreateInfo; 836 Header->SecurityDescriptor = NULL; 837 838 /* Check if this is a permanent object */ 839 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT)) 840 { 841 /* Set the needed flag so we can check */ 842 Header->Flags |= OB_FLAG_PERMANENT; 843 } 844 845 /* Check if this is an exclusive object */ 846 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) 847 { 848 /* Set the needed flag so we can check */ 849 Header->Flags |= OB_FLAG_EXCLUSIVE; 850 } 851 852 /* Set kernel-mode flag */ 853 if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE; 854 855 /* Check if we have a type */ 856 if (ObjectType) 857 { 858 /* Increase the number of objects of this type */ 859 InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects); 860 861 /* Update the high water */ 862 ObjectType->HighWaterNumberOfObjects = max(ObjectType-> 863 TotalNumberOfObjects, 864 ObjectType-> 865 HighWaterNumberOfObjects); 866 } 867 868 /* Return Header */ 869 *ObjectHeader = Header; 870 return STATUS_SUCCESS; 871 } 872 873 NTSTATUS 874 NTAPI 875 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType, 876 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo, 877 IN ULONG Length, 878 OUT PULONG ReturnLength) 879 { 880 NTSTATUS Status = STATUS_SUCCESS; 881 PWSTR InfoBuffer; 882 883 /* Enter SEH */ 884 _SEH2_TRY 885 { 886 /* Set return length aligned to 4-byte boundary */ 887 *ReturnLength += sizeof(*ObjectTypeInfo) + 888 ALIGN_UP(ObjectType->Name.MaximumLength, ULONG); 889 890 /* Check if thats too much though. */ 891 if (Length < *ReturnLength) 892 { 893 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 894 } 895 896 /* Build the data */ 897 ObjectTypeInfo->TotalNumberOfHandles = 898 ObjectType->TotalNumberOfHandles; 899 ObjectTypeInfo->TotalNumberOfObjects = 900 ObjectType->TotalNumberOfObjects; 901 ObjectTypeInfo->HighWaterNumberOfHandles = 902 ObjectType->HighWaterNumberOfHandles; 903 ObjectTypeInfo->HighWaterNumberOfObjects = 904 ObjectType->HighWaterNumberOfObjects; 905 ObjectTypeInfo->PoolType = 906 ObjectType->TypeInfo.PoolType; 907 ObjectTypeInfo->DefaultNonPagedPoolCharge = 908 ObjectType->TypeInfo.DefaultNonPagedPoolCharge; 909 ObjectTypeInfo->DefaultPagedPoolCharge = 910 ObjectType->TypeInfo.DefaultPagedPoolCharge; 911 ObjectTypeInfo->ValidAccessMask = 912 ObjectType->TypeInfo.ValidAccessMask; 913 ObjectTypeInfo->SecurityRequired = 914 ObjectType->TypeInfo.SecurityRequired; 915 ObjectTypeInfo->InvalidAttributes = 916 ObjectType->TypeInfo.InvalidAttributes; 917 ObjectTypeInfo->GenericMapping = 918 ObjectType->TypeInfo.GenericMapping; 919 ObjectTypeInfo->MaintainHandleCount = 920 ObjectType->TypeInfo.MaintainHandleCount; 921 922 /* Setup the name buffer */ 923 InfoBuffer = (PWSTR)(ObjectTypeInfo + 1); 924 ObjectTypeInfo->TypeName.Buffer = InfoBuffer; 925 ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength; 926 ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length; 927 928 /* Copy it */ 929 RtlCopyMemory(InfoBuffer, 930 ObjectType->Name.Buffer, 931 ObjectType->Name.Length); 932 933 /* Null-terminate it */ 934 (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; 935 } 936 _SEH2_EXCEPT(ExSystemExceptionFilter()) 937 { 938 /* Otherwise, get the exception code */ 939 Status = _SEH2_GetExceptionCode(); 940 } 941 _SEH2_END; 942 943 /* Return status to caller */ 944 return Status; 945 } 946 947 948 /* PUBLIC FUNCTIONS **********************************************************/ 949 950 NTSTATUS 951 NTAPI 952 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, 953 IN POBJECT_TYPE Type, 954 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 955 IN KPROCESSOR_MODE AccessMode, 956 IN OUT PVOID ParseContext OPTIONAL, 957 IN ULONG ObjectSize, 958 IN ULONG PagedPoolCharge OPTIONAL, 959 IN ULONG NonPagedPoolCharge OPTIONAL, 960 OUT PVOID *Object) 961 { 962 NTSTATUS Status; 963 POBJECT_CREATE_INFORMATION ObjectCreateInfo; 964 UNICODE_STRING ObjectName; 965 POBJECT_HEADER Header; 966 967 /* Allocate a capture buffer */ 968 ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList); 969 if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES; 970 971 /* Capture all the info */ 972 Status = ObpCaptureObjectCreateInformation(ObjectAttributes, 973 ProbeMode, 974 AccessMode, 975 FALSE, 976 ObjectCreateInfo, 977 &ObjectName); 978 if (NT_SUCCESS(Status)) 979 { 980 /* Validate attributes */ 981 if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) 982 { 983 /* Fail */ 984 Status = STATUS_INVALID_PARAMETER; 985 } 986 else 987 { 988 /* Check if we have a paged charge */ 989 if (!PagedPoolCharge) 990 { 991 /* Save it */ 992 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge; 993 } 994 995 /* Check for nonpaged charge */ 996 if (!NonPagedPoolCharge) 997 { 998 /* Save it */ 999 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge; 1000 } 1001 1002 /* Write the pool charges */ 1003 ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge; 1004 ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge; 1005 1006 /* Allocate the Object */ 1007 Status = ObpAllocateObject(ObjectCreateInfo, 1008 &ObjectName, 1009 Type, 1010 ObjectSize, 1011 AccessMode, 1012 &Header); 1013 if (NT_SUCCESS(Status)) 1014 { 1015 /* Return the Object */ 1016 *Object = &Header->Body; 1017 1018 /* Check if this is a permanent object */ 1019 if (Header->Flags & OB_FLAG_PERMANENT) 1020 { 1021 /* Do the privilege check */ 1022 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, 1023 ProbeMode)) 1024 { 1025 /* Fail */ 1026 ObpDeallocateObject(*Object); 1027 Status = STATUS_PRIVILEGE_NOT_HELD; 1028 } 1029 } 1030 1031 /* Return status */ 1032 return Status; 1033 } 1034 } 1035 1036 /* Release the Capture Info, we don't need it */ 1037 ObpFreeObjectCreateInformation(ObjectCreateInfo); 1038 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName); 1039 } 1040 1041 /* We failed, so release the Buffer */ 1042 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); 1043 return Status; 1044 } 1045 1046 NTSTATUS 1047 NTAPI 1048 ObCreateObjectType(IN PUNICODE_STRING TypeName, 1049 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, 1050 IN PVOID Reserved, 1051 OUT POBJECT_TYPE *ObjectType) 1052 { 1053 POBJECT_HEADER Header; 1054 POBJECT_TYPE LocalObjectType; 1055 ULONG HeaderSize; 1056 NTSTATUS Status; 1057 OBP_LOOKUP_CONTEXT Context; 1058 PWCHAR p; 1059 ULONG i; 1060 UNICODE_STRING ObjectName; 1061 ANSI_STRING AnsiName; 1062 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 1063 1064 /* Verify parameters */ 1065 if (!(TypeName) || 1066 !(TypeName->Length) || 1067 (TypeName->Length % sizeof(WCHAR)) || 1068 !(ObjectTypeInitializer) || 1069 (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) || 1070 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) || 1071 (ObjectTypeInitializer->MaintainHandleCount && 1072 (!(ObjectTypeInitializer->OpenProcedure) && 1073 !ObjectTypeInitializer->CloseProcedure)) || 1074 ((!ObjectTypeInitializer->UseDefaultObject) && 1075 (ObjectTypeInitializer->PoolType != NonPagedPool))) 1076 { 1077 /* Fail */ 1078 return STATUS_INVALID_PARAMETER; 1079 } 1080 1081 /* Make sure the name doesn't have a separator */ 1082 p = TypeName->Buffer; 1083 i = TypeName->Length / sizeof(WCHAR); 1084 while (i--) 1085 { 1086 /* Check for one and fail */ 1087 if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID; 1088 } 1089 1090 /* Setup a lookup context */ 1091 ObpInitializeLookupContext(&Context); 1092 1093 /* Check if we've already created the directory of types */ 1094 if (ObpTypeDirectoryObject) 1095 { 1096 /* Acquire the directory lock */ 1097 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context); 1098 1099 /* Do the lookup */ 1100 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject, 1101 TypeName, 1102 OBJ_CASE_INSENSITIVE, 1103 FALSE, 1104 &Context)) 1105 { 1106 /* We have already created it, so fail */ 1107 ObpReleaseLookupContext(&Context); 1108 return STATUS_OBJECT_NAME_COLLISION; 1109 } 1110 } 1111 1112 /* Now make a copy of the object name */ 1113 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1114 TypeName->MaximumLength, 1115 OB_NAME_TAG); 1116 if (!ObjectName.Buffer) 1117 { 1118 /* Out of memory, fail */ 1119 ObpReleaseLookupContext(&Context); 1120 return STATUS_INSUFFICIENT_RESOURCES; 1121 } 1122 1123 /* Set the length and copy the name */ 1124 ObjectName.MaximumLength = TypeName->MaximumLength; 1125 RtlCopyUnicodeString(&ObjectName, TypeName); 1126 1127 /* Allocate the Object */ 1128 Status = ObpAllocateObject(NULL, 1129 &ObjectName, 1130 ObpTypeObjectType, 1131 sizeof(OBJECT_TYPE), 1132 KernelMode, 1133 &Header); 1134 if (!NT_SUCCESS(Status)) 1135 { 1136 /* Free the name and fail */ 1137 ObpReleaseLookupContext(&Context); 1138 ExFreePool(ObjectName.Buffer); 1139 return Status; 1140 } 1141 1142 /* Setup the flags and name */ 1143 LocalObjectType = (POBJECT_TYPE)&Header->Body; 1144 LocalObjectType->Name = ObjectName; 1145 Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT; 1146 1147 /* Clear accounting data */ 1148 LocalObjectType->TotalNumberOfObjects = 1149 LocalObjectType->TotalNumberOfHandles = 1150 LocalObjectType->HighWaterNumberOfObjects = 1151 LocalObjectType->HighWaterNumberOfHandles = 0; 1152 1153 /* Check if this is the first Object Type */ 1154 if (!ObpTypeObjectType) 1155 { 1156 /* It is, so set this as the type object */ 1157 ObpTypeObjectType = LocalObjectType; 1158 Header->Type = ObpTypeObjectType; 1159 1160 /* Set the hard-coded key and object count */ 1161 LocalObjectType->TotalNumberOfObjects = 1; 1162 LocalObjectType->Key = 'TjbO'; 1163 } 1164 else 1165 { 1166 /* Convert the tag to ASCII */ 1167 Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE); 1168 if (NT_SUCCESS(Status)) 1169 { 1170 /* For every missing character, use a space */ 1171 for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' '; 1172 1173 /* Set the key and free the converted name */ 1174 LocalObjectType->Key = *(PULONG)AnsiName.Buffer; 1175 RtlFreeAnsiString(&AnsiName); 1176 } 1177 else 1178 { 1179 /* Just copy the characters */ 1180 LocalObjectType->Key = *(PULONG)TypeName->Buffer; 1181 } 1182 } 1183 1184 /* Set up the type information */ 1185 LocalObjectType->TypeInfo = *ObjectTypeInitializer; 1186 LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType; 1187 1188 /* Check if we have to maintain a type list */ 1189 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) 1190 { 1191 /* Enable support */ 1192 LocalObjectType->TypeInfo.MaintainTypeList = TRUE; 1193 } 1194 1195 /* Calculate how much space our header'll take up */ 1196 HeaderSize = sizeof(OBJECT_HEADER) + 1197 sizeof(OBJECT_HEADER_NAME_INFO) + 1198 (ObjectTypeInitializer->MaintainHandleCount ? 1199 sizeof(OBJECT_HEADER_HANDLE_INFO) : 0); 1200 1201 /* Check the pool type */ 1202 if (ObjectTypeInitializer->PoolType == NonPagedPool) 1203 { 1204 /* Update the NonPaged Pool charge */ 1205 LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize; 1206 } 1207 else 1208 { 1209 /* Update the Paged Pool charge */ 1210 LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize; 1211 } 1212 1213 /* All objects types need a security procedure */ 1214 if (!ObjectTypeInitializer->SecurityProcedure) 1215 { 1216 LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; 1217 } 1218 1219 /* Select the Wait Object */ 1220 if (LocalObjectType->TypeInfo.UseDefaultObject) 1221 { 1222 /* Add the SYNCHRONIZE access mask since it's waitable */ 1223 LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; 1224 1225 /* Use the "Default Object", a simple event */ 1226 LocalObjectType->DefaultObject = &ObpDefaultObject; 1227 } 1228 /* The File Object gets an optimized hack so it can be waited on */ 1229 else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File"))) 1230 { 1231 /* Wait on the File Object's event directly */ 1232 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT, 1233 Event)); 1234 } 1235 else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort"))) 1236 { 1237 /* Wait on the LPC Port's object directly */ 1238 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT, 1239 WaitEvent)); 1240 } 1241 else 1242 { 1243 /* No default Object */ 1244 LocalObjectType->DefaultObject = NULL; 1245 } 1246 1247 /* Initialize Object Type components */ 1248 ExInitializeResourceLite(&LocalObjectType->Mutex); 1249 for (i = 0; i < 4; i++) 1250 { 1251 /* Initialize the object locks */ 1252 ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]); 1253 } 1254 InitializeListHead(&LocalObjectType->TypeList); 1255 1256 /* Lock the object type */ 1257 ObpEnterObjectTypeMutex(ObpTypeObjectType); 1258 1259 /* Get creator info and insert it into the type list */ 1260 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); 1261 if (CreatorInfo) 1262 { 1263 InsertTailList(&ObpTypeObjectType->TypeList, 1264 &CreatorInfo->TypeList); 1265 1266 /* CORE-8423: Avoid inserting this a second time if someone creates a 1267 * handle to the object type (bug in Windows 2003) */ 1268 Header->Flags &= ~OB_FLAG_CREATE_INFO; 1269 } 1270 1271 /* Set the index and the entry into the object type array */ 1272 LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects; 1273 1274 ASSERT(LocalObjectType->Index != 0); 1275 1276 if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes)) 1277 { 1278 /* It fits, insert it */ 1279 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType; 1280 } 1281 1282 /* Release the object type */ 1283 ObpLeaveObjectTypeMutex(ObpTypeObjectType); 1284 1285 /* Check if we're actually creating the directory object itself */ 1286 if (!(ObpTypeDirectoryObject) || 1287 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header))) 1288 { 1289 /* Check if the type directory exists */ 1290 if (ObpTypeDirectoryObject) 1291 { 1292 /* Reference it */ 1293 ObReferenceObject(ObpTypeDirectoryObject); 1294 } 1295 1296 /* Cleanup the lookup context */ 1297 ObpReleaseLookupContext(&Context); 1298 1299 /* Return the object type and success */ 1300 *ObjectType = LocalObjectType; 1301 return STATUS_SUCCESS; 1302 } 1303 1304 /* If we got here, then we failed */ 1305 ObpReleaseLookupContext(&Context); 1306 return STATUS_INSUFFICIENT_RESOURCES; 1307 } 1308 1309 VOID 1310 NTAPI 1311 ObDeleteCapturedInsertInfo(IN PVOID Object) 1312 { 1313 POBJECT_HEADER ObjectHeader; 1314 PAGED_CODE(); 1315 1316 /* Check if there is anything to free */ 1317 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1318 if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) && 1319 (ObjectHeader->ObjectCreateInfo != NULL)) 1320 { 1321 /* Free the create info */ 1322 ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo); 1323 ObjectHeader->ObjectCreateInfo = NULL; 1324 } 1325 } 1326 1327 VOID 1328 NTAPI 1329 ObpDeleteObjectType(IN PVOID Object) 1330 { 1331 ULONG i; 1332 POBJECT_TYPE ObjectType = (PVOID)Object; 1333 1334 /* Loop our locks */ 1335 for (i = 0; i < 4; i++) 1336 { 1337 /* Delete each one */ 1338 ExDeleteResourceLite(&ObjectType->ObjectLocks[i]); 1339 } 1340 1341 /* Delete our main mutex */ 1342 ExDeleteResourceLite(&ObjectType->Mutex); 1343 } 1344 1345 /*++ 1346 * @name ObMakeTemporaryObject 1347 * @implemented NT4 1348 * 1349 * The ObMakeTemporaryObject routine <FILLMEIN> 1350 * 1351 * @param ObjectBody 1352 * <FILLMEIN> 1353 * 1354 * @return None. 1355 * 1356 * @remarks None. 1357 * 1358 *--*/ 1359 VOID 1360 NTAPI 1361 ObMakeTemporaryObject(IN PVOID ObjectBody) 1362 { 1363 PAGED_CODE(); 1364 1365 /* Call the internal API */ 1366 ObpSetPermanentObject(ObjectBody, FALSE); 1367 } 1368 1369 /*++ 1370 * @name NtMakeTemporaryObject 1371 * @implemented NT4 1372 * 1373 * The NtMakeTemporaryObject routine <FILLMEIN> 1374 * 1375 * @param ObjectHandle 1376 * <FILLMEIN> 1377 * 1378 * @return STATUS_SUCCESS or appropriate error value. 1379 * 1380 * @remarks None. 1381 * 1382 *--*/ 1383 NTSTATUS 1384 NTAPI 1385 NtMakeTemporaryObject(IN HANDLE ObjectHandle) 1386 { 1387 PVOID ObjectBody; 1388 NTSTATUS Status; 1389 PAGED_CODE(); 1390 1391 /* Reference the object for DELETE access */ 1392 Status = ObReferenceObjectByHandle(ObjectHandle, 1393 DELETE, 1394 NULL, 1395 KeGetPreviousMode(), 1396 &ObjectBody, 1397 NULL); 1398 if (Status != STATUS_SUCCESS) return Status; 1399 1400 /* Set it as temporary and dereference it */ 1401 ObpSetPermanentObject(ObjectBody, FALSE); 1402 ObDereferenceObject(ObjectBody); 1403 return STATUS_SUCCESS; 1404 } 1405 1406 /*++ 1407 * @name NtMakePermanentObject 1408 * @implemented NT4 1409 * 1410 * The NtMakePermanentObject routine <FILLMEIN> 1411 * 1412 * @param ObjectHandle 1413 * <FILLMEIN> 1414 * 1415 * @return STATUS_SUCCESS or appropriate error value. 1416 * 1417 * @remarks None. 1418 * 1419 *--*/ 1420 NTSTATUS 1421 NTAPI 1422 NtMakePermanentObject(IN HANDLE ObjectHandle) 1423 { 1424 PVOID ObjectBody; 1425 NTSTATUS Status; 1426 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1427 PAGED_CODE(); 1428 1429 /* Make sure that the caller has SeCreatePermanentPrivilege */ 1430 Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, 1431 PreviousMode); 1432 if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD; 1433 1434 /* Reference the object */ 1435 Status = ObReferenceObjectByHandle(ObjectHandle, 1436 0, 1437 NULL, 1438 PreviousMode, 1439 &ObjectBody, 1440 NULL); 1441 if (Status != STATUS_SUCCESS) return Status; 1442 1443 /* Set it as permanent and dereference it */ 1444 ObpSetPermanentObject(ObjectBody, TRUE); 1445 ObDereferenceObject(ObjectBody); 1446 return STATUS_SUCCESS; 1447 } 1448 1449 /*++ 1450 * @name NtQueryObject 1451 * @implemented NT4 1452 * 1453 * The NtQueryObject routine <FILLMEIN> 1454 * 1455 * @param ObjectHandle 1456 * <FILLMEIN> 1457 * 1458 * @param ObjectInformationClass 1459 * <FILLMEIN> 1460 * 1461 * @param ObjectInformation 1462 * <FILLMEIN> 1463 * 1464 * @param Length 1465 * <FILLMEIN> 1466 * 1467 * @param ResultLength 1468 * <FILLMEIN> 1469 * 1470 * @return STATUS_SUCCESS or appropriate error value. 1471 * 1472 * @remarks None. 1473 * 1474 *--*/ 1475 NTSTATUS 1476 NTAPI 1477 NtQueryObject(IN HANDLE ObjectHandle, 1478 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1479 OUT PVOID ObjectInformation, 1480 IN ULONG Length, 1481 OUT PULONG ResultLength OPTIONAL) 1482 { 1483 OBJECT_HANDLE_INFORMATION HandleInfo; 1484 POBJECT_HEADER ObjectHeader = NULL; 1485 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags; 1486 POBJECT_BASIC_INFORMATION BasicInfo; 1487 ULONG InfoLength = 0; 1488 PVOID Object = NULL; 1489 NTSTATUS Status; 1490 POBJECT_HEADER_QUOTA_INFO ObjectQuota; 1491 SECURITY_INFORMATION SecurityInformation; 1492 POBJECT_TYPE ObjectType; 1493 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1494 PAGED_CODE(); 1495 1496 /* Check if the caller is from user mode */ 1497 if (PreviousMode != KernelMode) 1498 { 1499 /* Protect validation with SEH */ 1500 _SEH2_TRY 1501 { 1502 /* Probe the input structure */ 1503 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR)); 1504 1505 /* If we have a result length, probe it too */ 1506 if (ResultLength) ProbeForWriteUlong(ResultLength); 1507 } 1508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1509 { 1510 /* Return the exception code */ 1511 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1512 } 1513 _SEH2_END; 1514 } 1515 1516 /* 1517 * Make sure this isn't a generic type query, since the caller doesn't 1518 * have to give a handle for it 1519 */ 1520 if (ObjectInformationClass != ObjectTypesInformation) 1521 { 1522 /* Reference the object */ 1523 Status = ObReferenceObjectByHandle(ObjectHandle, 1524 0, 1525 NULL, 1526 KeGetPreviousMode(), 1527 &Object, 1528 &HandleInfo); 1529 if (!NT_SUCCESS (Status)) return Status; 1530 1531 /* Get the object header */ 1532 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1533 ObjectType = ObjectHeader->Type; 1534 } 1535 1536 _SEH2_TRY 1537 { 1538 /* Check the information class */ 1539 switch (ObjectInformationClass) 1540 { 1541 /* Basic info */ 1542 case ObjectBasicInformation: 1543 1544 /* Validate length */ 1545 InfoLength = sizeof(OBJECT_BASIC_INFORMATION); 1546 if (Length != sizeof(OBJECT_BASIC_INFORMATION)) 1547 { 1548 /* Fail */ 1549 Status = STATUS_INFO_LENGTH_MISMATCH; 1550 break; 1551 } 1552 1553 /* Fill out the basic information */ 1554 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation; 1555 BasicInfo->Attributes = HandleInfo.HandleAttributes; 1556 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; 1557 BasicInfo->HandleCount = ObjectHeader->HandleCount; 1558 BasicInfo->PointerCount = ObjectHeader->PointerCount; 1559 1560 /* Permanent/Exclusive Flags are NOT in Handle attributes! */ 1561 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) 1562 { 1563 /* Set the flag */ 1564 BasicInfo->Attributes |= OBJ_EXCLUSIVE; 1565 } 1566 if (ObjectHeader->Flags & OB_FLAG_PERMANENT) 1567 { 1568 /* Set the flag */ 1569 BasicInfo->Attributes |= OBJ_PERMANENT; 1570 } 1571 1572 /* Copy quota information */ 1573 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader); 1574 if (ObjectQuota != NULL) 1575 { 1576 BasicInfo->PagedPoolCharge = ObjectQuota->PagedPoolCharge; 1577 BasicInfo->NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge; 1578 } 1579 else 1580 { 1581 BasicInfo->PagedPoolCharge = 0; 1582 BasicInfo->NonPagedPoolCharge = 0; 1583 } 1584 1585 /* Copy name information */ 1586 BasicInfo->NameInfoSize = 0; /* FIXME*/ 1587 BasicInfo->TypeInfoSize = 0; /* FIXME*/ 1588 1589 /* Check if this is a symlink */ 1590 if (ObjectHeader->Type == ObpSymbolicLinkObjectType) 1591 { 1592 /* Return the creation time */ 1593 BasicInfo->CreationTime.QuadPart = 1594 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; 1595 } 1596 else 1597 { 1598 /* Otherwise return 0 */ 1599 BasicInfo->CreationTime.QuadPart = (ULONGLONG)0; 1600 } 1601 1602 /* Copy security information */ 1603 BasicInfo->SecurityDescriptorSize = 0; 1604 if (BooleanFlagOn(HandleInfo.GrantedAccess, READ_CONTROL) && 1605 ObjectHeader->SecurityDescriptor != NULL) 1606 { 1607 SecurityInformation = OWNER_SECURITY_INFORMATION | 1608 GROUP_SECURITY_INFORMATION | 1609 DACL_SECURITY_INFORMATION | 1610 SACL_SECURITY_INFORMATION; 1611 1612 ObjectType->TypeInfo.SecurityProcedure(Object, 1613 QuerySecurityDescriptor, 1614 &SecurityInformation, 1615 NULL, 1616 &BasicInfo->SecurityDescriptorSize, 1617 &ObjectHeader->SecurityDescriptor, 1618 ObjectType->TypeInfo.PoolType, 1619 &ObjectType->TypeInfo.GenericMapping); 1620 } 1621 1622 /* Break out with success */ 1623 Status = STATUS_SUCCESS; 1624 break; 1625 1626 /* Name information */ 1627 case ObjectNameInformation: 1628 1629 /* Call the helper and break out */ 1630 Status = ObQueryNameString(Object, 1631 (POBJECT_NAME_INFORMATION) 1632 ObjectInformation, 1633 Length, 1634 &InfoLength); 1635 break; 1636 1637 /* Information about this type */ 1638 case ObjectTypeInformation: 1639 1640 /* Call the helper and break out */ 1641 Status = ObQueryTypeInfo(ObjectHeader->Type, 1642 (POBJECT_TYPE_INFORMATION) 1643 ObjectInformation, 1644 Length, 1645 &InfoLength); 1646 break; 1647 1648 /* Information about all types */ 1649 case ObjectTypesInformation: 1650 DPRINT1("NOT IMPLEMENTED!\n"); 1651 InfoLength = Length; 1652 Status = STATUS_NOT_IMPLEMENTED; 1653 break; 1654 1655 /* Information about the handle flags */ 1656 case ObjectHandleFlagInformation: 1657 1658 /* Validate length */ 1659 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION); 1660 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1661 { 1662 Status = STATUS_INFO_LENGTH_MISMATCH; 1663 break; 1664 } 1665 1666 /* Get the structure */ 1667 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1668 ObjectInformation; 1669 1670 /* Set the flags */ 1671 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT; 1672 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes & 1673 OBJ_PROTECT_CLOSE) != 0; 1674 1675 /* Break out with success */ 1676 Status = STATUS_SUCCESS; 1677 break; 1678 1679 /* Anything else */ 1680 default: 1681 1682 /* Fail it */ 1683 InfoLength = Length; 1684 Status = STATUS_INVALID_INFO_CLASS; 1685 break; 1686 } 1687 1688 /* Check if the caller wanted the return length */ 1689 if (ResultLength) 1690 { 1691 /* Write the length */ 1692 *ResultLength = InfoLength; 1693 } 1694 } 1695 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1696 { 1697 /* Otherwise, get the exception code */ 1698 Status = _SEH2_GetExceptionCode(); 1699 } 1700 _SEH2_END; 1701 1702 /* Dereference the object if we had referenced it */ 1703 if (Object) ObDereferenceObject(Object); 1704 1705 /* Return status */ 1706 return Status; 1707 } 1708 1709 /*++ 1710 * @name NtSetInformationObject 1711 * @implemented NT4 1712 * 1713 * The NtSetInformationObject routine <FILLMEIN> 1714 * 1715 * @param ObjectHandle 1716 * <FILLMEIN> 1717 * 1718 * @param ObjectInformationClass 1719 * <FILLMEIN> 1720 * 1721 * @param ObjectInformation 1722 * <FILLMEIN> 1723 * 1724 * @param Length 1725 * <FILLMEIN> 1726 * 1727 * @return STATUS_SUCCESS or appropriate error value. 1728 * 1729 * @remarks None. 1730 * 1731 *--*/ 1732 NTSTATUS 1733 NTAPI 1734 NtSetInformationObject(IN HANDLE ObjectHandle, 1735 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1736 IN PVOID ObjectInformation, 1737 IN ULONG Length) 1738 { 1739 NTSTATUS Status; 1740 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context; 1741 PVOID ObjectTable; 1742 KAPC_STATE ApcState; 1743 POBJECT_DIRECTORY Directory; 1744 KPROCESSOR_MODE PreviousMode; 1745 BOOLEAN AttachedToProcess = FALSE; 1746 PAGED_CODE(); 1747 1748 /* Validate the information class */ 1749 switch (ObjectInformationClass) 1750 { 1751 case ObjectHandleFlagInformation: 1752 1753 /* Validate the length */ 1754 if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1755 { 1756 /* Invalid length */ 1757 return STATUS_INFO_LENGTH_MISMATCH; 1758 } 1759 1760 /* Save the previous mode */ 1761 Context.PreviousMode = ExGetPreviousMode(); 1762 1763 /* Check if we were called from user mode */ 1764 if (Context.PreviousMode != KernelMode) 1765 { 1766 /* Enter SEH */ 1767 _SEH2_TRY 1768 { 1769 /* Probe and capture the attribute buffer */ 1770 ProbeForRead(ObjectInformation, 1771 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION), 1772 sizeof(BOOLEAN)); 1773 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1774 ObjectInformation; 1775 } 1776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1777 { 1778 /* Return the exception code */ 1779 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1780 } 1781 _SEH2_END; 1782 } 1783 else 1784 { 1785 /* Just copy the buffer directly */ 1786 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1787 ObjectInformation; 1788 } 1789 1790 /* Check if this is a kernel handle */ 1791 if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode)) 1792 { 1793 /* Get the actual handle */ 1794 ObjectHandle = ObKernelHandleToHandle(ObjectHandle); 1795 ObjectTable = ObpKernelHandleTable; 1796 1797 /* Check if we're not in the system process */ 1798 if (PsGetCurrentProcess() != PsInitialSystemProcess) 1799 { 1800 /* Attach to it */ 1801 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 1802 AttachedToProcess = TRUE; 1803 } 1804 } 1805 else 1806 { 1807 /* Use the current table */ 1808 ObjectTable = PsGetCurrentProcess()->ObjectTable; 1809 } 1810 1811 /* Change the handle attributes */ 1812 if (!ExChangeHandle(ObjectTable, 1813 ObjectHandle, 1814 ObpSetHandleAttributes, 1815 (ULONG_PTR)&Context)) 1816 { 1817 /* Some failure */ 1818 Status = STATUS_ACCESS_DENIED; 1819 } 1820 else 1821 { 1822 /* We are done */ 1823 Status = STATUS_SUCCESS; 1824 } 1825 1826 /* De-attach if we were attached, and return status */ 1827 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState); 1828 break; 1829 1830 case ObjectSessionInformation: 1831 1832 /* Only a system process can do this */ 1833 PreviousMode = ExGetPreviousMode(); 1834 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1835 { 1836 /* Fail */ 1837 DPRINT1("Privilege not held\n"); 1838 Status = STATUS_PRIVILEGE_NOT_HELD; 1839 } 1840 else 1841 { 1842 /* Get the object directory */ 1843 Status = ObReferenceObjectByHandle(ObjectHandle, 1844 0, 1845 ObpDirectoryObjectType, 1846 PreviousMode, 1847 (PVOID*)&Directory, 1848 NULL); 1849 if (NT_SUCCESS(Status)) 1850 { 1851 /* FIXME: Missng locks */ 1852 /* Set its session ID */ 1853 Directory->SessionId = PsGetCurrentProcessSessionId(); 1854 ObDereferenceObject(Directory); 1855 } 1856 } 1857 break; 1858 1859 default: 1860 /* Unsupported class */ 1861 Status = STATUS_INVALID_INFO_CLASS; 1862 break; 1863 } 1864 1865 return Status; 1866 } 1867 1868 /* EOF */ 1869