mirror of
https://github.com/reactos/reactos.git
synced 2024-07-28 15:19:09 +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
|
#endif
|
||||||
|
|
||||||
#define ObGetObjectPointerCount(x) OBJECT_TO_OBJECT_HEADER(x)->PointerCount
|
#define ObGetObjectPointerCount(x) OBJECT_TO_OBJECT_HEADER(x)->PointerCount
|
||||||
|
#define ObGetObjectHandleCount(x) OBJECT_TO_OBJECT_HEADER(x)->HandleCount
|
||||||
|
|
||||||
/* GLOBALS ******************************************************************/
|
/* GLOBALS ******************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -114,9 +114,11 @@ ObpSetHandleAttributes(
|
||||||
IN PVOID Context
|
IN PVOID Context
|
||||||
);
|
);
|
||||||
|
|
||||||
ULONG
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
ObGetObjectHandleCount(PVOID Object);
|
ObpDeleteNameCheck(
|
||||||
|
IN PVOID Object
|
||||||
|
);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -21,6 +21,70 @@ PHANDLE_TABLE ObpKernelHandleTable = NULL;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS *********************************************************/
|
/* 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
|
* @name ObpSetPermanentObject
|
||||||
*
|
*
|
||||||
|
@ -43,32 +107,21 @@ ObpSetPermanentObject(IN PVOID ObjectBody,
|
||||||
IN BOOLEAN Permanent)
|
IN BOOLEAN Permanent)
|
||||||
{
|
{
|
||||||
POBJECT_HEADER ObjectHeader;
|
POBJECT_HEADER ObjectHeader;
|
||||||
OBP_LOOKUP_CONTEXT Context;
|
|
||||||
|
|
||||||
|
/* Get the header */
|
||||||
ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
|
ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
|
||||||
ASSERT (ObjectHeader->PointerCount > 0);
|
|
||||||
if (Permanent)
|
if (Permanent)
|
||||||
{
|
{
|
||||||
|
/* Set it to permanent */
|
||||||
ObjectHeader->Flags |= OB_FLAG_PERMANENT;
|
ObjectHeader->Flags |= OB_FLAG_PERMANENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Remove the flag */
|
||||||
ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
|
ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
|
||||||
if (ObjectHeader->HandleCount == 0 &&
|
|
||||||
OBJECT_HEADER_TO_NAME_INFO(ObjectHeader)->Directory)
|
/* Check if we should delete the object now */
|
||||||
{
|
ObpDeleteNameCheck(ObjectBody);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +166,6 @@ ObpDecrementHandleCount(PVOID ObjectBody)
|
||||||
{
|
{
|
||||||
POBJECT_HEADER ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
|
POBJECT_HEADER ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
|
||||||
LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount);
|
LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount);
|
||||||
OBP_LOOKUP_CONTEXT Context;
|
|
||||||
DPRINT("Header: %x\n", ObjectHeader);
|
DPRINT("Header: %x\n", ObjectHeader);
|
||||||
DPRINT("NewHandleCount: %x\n", NewHandleCount);
|
DPRINT("NewHandleCount: %x\n", NewHandleCount);
|
||||||
DPRINT("OBJECT_HEADER_TO_NAME_INFO: %x\n", OBJECT_HEADER_TO_NAME_INFO(ObjectHeader));
|
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);
|
ObjectHeader->Type->TypeInfo.CloseProcedure(NULL, ObjectBody, 0, NewHandleCount + 1, NewHandleCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewHandleCount == 0)
|
/* Check if we should delete the object */
|
||||||
{
|
ObpDeleteNameCheck(ObjectBody);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -594,20 +622,6 @@ ObpCreateHandle(PVOID ObjectBody,
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS *********************************************************/
|
/* PUBLIC FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
ObGetObjectHandleCount(PVOID Object)
|
|
||||||
{
|
|
||||||
POBJECT_HEADER Header;
|
|
||||||
|
|
||||||
PAGED_CODE();
|
|
||||||
|
|
||||||
ASSERT(Object);
|
|
||||||
Header = OBJECT_TO_OBJECT_HEADER(Object);
|
|
||||||
|
|
||||||
return Header->HandleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
@ -1162,18 +1176,18 @@ NtMakeTemporaryObject(IN HANDLE ObjectHandle)
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Reference the object for DELETE access */
|
||||||
Status = ObReferenceObjectByHandle(ObjectHandle,
|
Status = ObReferenceObjectByHandle(ObjectHandle,
|
||||||
0,
|
DELETE,
|
||||||
NULL,
|
NULL,
|
||||||
KeGetPreviousMode(),
|
KeGetPreviousMode(),
|
||||||
&ObjectBody,
|
&ObjectBody,
|
||||||
NULL);
|
NULL);
|
||||||
if (Status != STATUS_SUCCESS) return Status;
|
if (Status != STATUS_SUCCESS) return Status;
|
||||||
|
|
||||||
ObpSetPermanentObject (ObjectBody, FALSE);
|
/* Set it as temporary and dereference it */
|
||||||
|
ObpSetPermanentObject(ObjectBody, FALSE);
|
||||||
ObDereferenceObject(ObjectBody);
|
ObDereferenceObject(ObjectBody);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,20 +1211,26 @@ NtMakePermanentObject(IN HANDLE ObjectHandle)
|
||||||
{
|
{
|
||||||
PVOID ObjectBody;
|
PVOID ObjectBody;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
PAGED_CODE();
|
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,
|
Status = ObReferenceObjectByHandle(ObjectHandle,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
KeGetPreviousMode(),
|
PreviousMode,
|
||||||
&ObjectBody,
|
&ObjectBody,
|
||||||
NULL);
|
NULL);
|
||||||
if (Status != STATUS_SUCCESS) return Status;
|
if (Status != STATUS_SUCCESS) return Status;
|
||||||
|
|
||||||
ObpSetPermanentObject (ObjectBody, TRUE);
|
/* Set it as permanent and dereference it */
|
||||||
|
ObpSetPermanentObject(ObjectBody, TRUE);
|
||||||
ObDereferenceObject(ObjectBody);
|
ObDereferenceObject(ObjectBody);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in a new issue