From afea80bbe42846005872a8ea82fb56c93464d525 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 6 Jun 2006 04:52:08 +0000 Subject: [PATCH] - Make sure callers of NtMakeTemporaryObject have DELETE privileges, otherwise they could end up illegaly killing objects (in certain situations) - Make sure callers of NtMakePermanentObject have SeCreatePermanentPrivilege. - Implement ObpDeleteNameCheck as described in Gl00my's Ob Documentation (using such documentation falls under US Reverse Engineering Law - Clean rooming). - Remove duplicated code in ObpDecrementHandleCount and ObpSetPermanentObject and have them use ObpDeleteNameCheck instead. - Fixes thanks to using this routine: * Name-check is now properly done. * The keep-alive reference is now deleted when going from permanent->temporary object. * The parent directory is now dereferenced and cleared when deleting the object. * The security procedure is now called to delete the SD, and the name buffer is freed. - Remove ObGetObjectHandleCount, it's not a public function. svn path=/trunk/; revision=22244 --- reactos/ntoskrnl/cm/registry.c | 1 + reactos/ntoskrnl/include/internal/ob.h | 6 +- reactos/ntoskrnl/ob/obhandle.c | 152 ++++++++++++++----------- 3 files changed, 91 insertions(+), 68 deletions(-) diff --git a/reactos/ntoskrnl/cm/registry.c b/reactos/ntoskrnl/cm/registry.c index e827f208b00..83ffecdb364 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -23,6 +23,7 @@ #endif #define ObGetObjectPointerCount(x) OBJECT_TO_OBJECT_HEADER(x)->PointerCount +#define ObGetObjectHandleCount(x) OBJECT_TO_OBJECT_HEADER(x)->HandleCount /* GLOBALS ******************************************************************/ diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index 9b54fb52d5b..d7a0070282a 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -114,9 +114,11 @@ ObpSetHandleAttributes( IN PVOID Context ); -ULONG +VOID NTAPI -ObGetObjectHandleCount(PVOID Object); +ObpDeleteNameCheck( + IN PVOID Object +); NTSTATUS NTAPI diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index acf5634e204..4a8b34f9ce5 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -21,6 +21,70 @@ PHANDLE_TABLE ObpKernelHandleTable = NULL; /* PRIVATE FUNCTIONS *********************************************************/ +VOID +NTAPI +ObpDeleteNameCheck(IN PVOID Object) +{ + POBJECT_HEADER ObjectHeader; + OBP_LOOKUP_CONTEXT Context; + POBJECT_HEADER_NAME_INFO ObjectNameInfo; + POBJECT_TYPE ObjectType; + + /* Get object structures */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + ObjectType = ObjectHeader->Type; + + /* + * Check if the handle count is 0, if the object is named, + * and if the object isn't a permanent object. + */ + if (!(ObjectHeader->HandleCount) && + (ObjectNameInfo) && + (ObjectNameInfo->Name.Length) && + !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) + { + /* Make sure it's still inserted */ + Context.Directory = ObjectNameInfo->Directory; + Context.DirectoryLocked = TRUE; + Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, + &ObjectNameInfo->Name, + 0, + FALSE, + &Context); + if (Object) + { + /* First delete it from the directory */ + ObpDeleteEntryDirectory(&Context); + + /* Now check if we have a security callback */ + if (ObjectType->TypeInfo.SecurityRequired) + { + /* Call it */ + ObjectType->TypeInfo.SecurityProcedure(Object, + DeleteSecurityDescriptor, + 0, + NULL, + NULL, + &ObjectHeader-> + SecurityDescriptor, + ObjectType-> + TypeInfo.PoolType, + NULL); + } + + /* Free the name */ + ExFreePool(ObjectNameInfo->Name.Buffer); + RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); + + /* Clear the current directory and de-reference it */ + ObDereferenceObject(ObjectNameInfo->Directory); + ObDereferenceObject(Object); + ObjectNameInfo->Directory = NULL; + } + } +} + /*++ * @name ObpSetPermanentObject * @@ -43,32 +107,21 @@ ObpSetPermanentObject(IN PVOID ObjectBody, IN BOOLEAN Permanent) { POBJECT_HEADER ObjectHeader; - OBP_LOOKUP_CONTEXT Context; + /* Get the header */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody); - ASSERT (ObjectHeader->PointerCount > 0); if (Permanent) { + /* Set it to permanent */ ObjectHeader->Flags |= OB_FLAG_PERMANENT; } else { + /* Remove the flag */ ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; - if (ObjectHeader->HandleCount == 0 && - OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory) - { - /* Make sure it's still inserted */ - Context.Directory = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory; - Context.DirectoryLocked = TRUE; - if (ObpLookupEntryDirectory(OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory, - &OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Name, - 0, - FALSE, - &Context)) - { - ObpDeleteEntryDirectory(&Context); - } - } + + /* Check if we should delete the object now */ + ObpDeleteNameCheck(ObjectBody); } } @@ -113,7 +166,6 @@ ObpDecrementHandleCount(PVOID ObjectBody) { POBJECT_HEADER ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody); LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount); - OBP_LOOKUP_CONTEXT Context; DPRINT("Header: %x\n", ObjectHeader); DPRINT("NewHandleCount: %x\n", NewHandleCount); DPRINT("OBJECT_HEADER_TO_NAME_INFO: %x\n", OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)); @@ -126,32 +178,8 @@ ObpDecrementHandleCount(PVOID ObjectBody) ObjectHeader->Type->TypeInfo.CloseProcedure(NULL, ObjectBody, 0, NewHandleCount + 1, NewHandleCount + 1); } - if(NewHandleCount == 0) - { - if(OBJECT_HEADER_TO_NAME_INFO(ObjectHeader) && - OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory != NULL && - !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) - { - /* delete the object from the namespace when the last handle got closed. - Only do this if it's actually been inserted into the namespace and - if it's not a permanent object. */ - - /* Make sure it's still inserted */ - Context.Directory = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory; - Context.DirectoryLocked = TRUE; - if (ObpLookupEntryDirectory(OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory, - &OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Name, - 0, - FALSE, - &Context)) - { - ObpDeleteEntryDirectory(&Context); - } - } - - /* remove the keep-alive reference */ - ObDereferenceObject(ObjectBody); - } + /* Check if we should delete the object */ + ObpDeleteNameCheck(ObjectBody); } BOOLEAN @@ -594,20 +622,6 @@ ObpCreateHandle(PVOID ObjectBody, /* PUBLIC FUNCTIONS *********************************************************/ -ULONG -NTAPI -ObGetObjectHandleCount(PVOID Object) -{ - POBJECT_HEADER Header; - - PAGED_CODE(); - - ASSERT(Object); - Header = OBJECT_TO_OBJECT_HEADER(Object); - - return Header->HandleCount; -} - NTSTATUS NTAPI ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, @@ -1162,18 +1176,18 @@ NtMakeTemporaryObject(IN HANDLE ObjectHandle) NTSTATUS Status; PAGED_CODE(); + /* Reference the object for DELETE access */ Status = ObReferenceObjectByHandle(ObjectHandle, - 0, + DELETE, NULL, KeGetPreviousMode(), &ObjectBody, NULL); if (Status != STATUS_SUCCESS) return Status; - ObpSetPermanentObject (ObjectBody, FALSE); - + /* Set it as temporary and dereference it */ + ObpSetPermanentObject(ObjectBody, FALSE); ObDereferenceObject(ObjectBody); - return STATUS_SUCCESS; } @@ -1197,20 +1211,26 @@ NtMakePermanentObject(IN HANDLE ObjectHandle) { PVOID ObjectBody; NTSTATUS Status; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PAGED_CODE(); + /* Make sure that the caller has SeCreatePermanentPrivilege */ + Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, + PreviousMode); + if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD; + + /* Reference the object */ Status = ObReferenceObjectByHandle(ObjectHandle, 0, NULL, - KeGetPreviousMode(), + PreviousMode, &ObjectBody, NULL); if (Status != STATUS_SUCCESS) return Status; - ObpSetPermanentObject (ObjectBody, TRUE); - + /* Set it as permanent and dereference it */ + ObpSetPermanentObject(ObjectBody, TRUE); ObDereferenceObject(ObjectBody); - return STATUS_SUCCESS; } /* EOF */