mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 04:35:07 +00:00
- 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
This commit is contained in:
parent
50224a4d55
commit
afea80bbe4
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
|
||||
#define ObGetObjectPointerCount(x) OBJECT_TO_OBJECT_HEADER(x)->PointerCount
|
||||
#define ObGetObjectHandleCount(x) OBJECT_TO_OBJECT_HEADER(x)->HandleCount
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
|
|
|
@ -114,9 +114,11 @@ ObpSetHandleAttributes(
|
|||
IN PVOID Context
|
||||
);
|
||||
|
||||
ULONG
|
||||
VOID
|
||||
NTAPI
|
||||
ObGetObjectHandleCount(PVOID Object);
|
||||
ObpDeleteNameCheck(
|
||||
IN PVOID Object
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue