- 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:
Alex Ionescu 2006-06-06 04:52:08 +00:00
parent 50224a4d55
commit afea80bbe4
3 changed files with 91 additions and 68 deletions

View file

@ -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 ******************************************************************/

View file

@ -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

View file

@ -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 */