Object Manager fixes based on bug reports from Aleksey Bragin:

- ObpReferenceProcessObjectByHandle:
  - Remove PAGED_CODE
  - Use InterlockedIncrement instead of InterlockedExchangeAdd.
- ObpInsertHandleCount: Fix calculation of the handle database size, fixing potential pool corruption/overwrite situations.
- ObpChargeQuotaForObject: Write proper code for charging the quota.
- ObpDecrementHandleCount:
  - Get ObjectType from caller instead of doing the extra operation.
  - If there's no handle database, then don't setup a handle entry.
- ObpIncrementHandleCount is PAGED_CODE.
- ObpCloseHandle: Do proper logic for determining if we should raise an exception, fail, or bugcheck the system when an invalid handle is being closed.
- ObpSetHandleAttributes:
  - Not PAGED_CODE.
  - Allow operations on kernel objects.
  - Use the Access Protect Close Bit in the GrantedAccess instead of an OBJ_PROTECT flag in the ObAttributes.
- ObpCloseHandleCallback: Sweep/Enumerate Routines are BOOLEAN, not VOID.
- ObDuplicateObject:
  - Clear the audit mask if auditing isn't set.
  - Always duplicate OBJ_AUDIT_OBJECT_CLOSE if it's set.
  - Clear the handle entry before writing it.
  - Always propagate ACCESS_SYSTEM_SECURITY as a desired access.
- ObFindHandleForObject: Use ObReferenceProcessHandleTable instead of directly accessing the pointer.
- ObInsertObject: Dereference symbolic links when they collide during an insert, since a reference was already added.
- NtDuplicateObject: Clear out the TargetHandle to assume failure.
- ObpCaptureObjectName: Use RtlCopyMemory which is faster.
- ObpAllocateObject: Fix check for quota usage.
- ObCreateObjectType:
  - Make sure that the object type name is wchar-aligned.
  - Add support for LPC Waitable Ports.
  - Initialize Object Locks.

svn path=/trunk/; revision=25799
This commit is contained in:
Alex Ionescu 2007-02-14 17:51:48 +00:00
parent 1102b7a6e9
commit e542b2c634
3 changed files with 133 additions and 61 deletions

View file

@ -336,7 +336,7 @@ ExfWaitForRundownProtectionRelease(
/* HANDLE TABLE FUNCTIONS ***************************************************/
typedef VOID
typedef BOOLEAN
(NTAPI *PEX_SWEEP_HANDLE_CALLBACK)(
PHANDLE_TABLE_ENTRY HandleTableEntry,
HANDLE Handle,

View file

@ -15,9 +15,10 @@
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#include <debug.h>
PHANDLE_TABLE ObpKernelHandleTable = NULL;
ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
#define TAG_OB_HANDLE TAG('O', 'b', 'H', 'd')
@ -69,7 +70,6 @@ ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
ULONG Attributes;
PETHREAD Thread = PsGetCurrentThread();
NTSTATUS Status;
PAGED_CODE();
/* Assume failure */
*Object = NULL;
@ -86,7 +86,7 @@ ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
/* Reference ourselves */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process);
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
InterlockedIncrement(&ObjectHeader->PointerCount);
/* Return the pointer */
*Object = Process;
@ -249,7 +249,7 @@ ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
/* Now we'll have two entries, and an entire DB */
i = 2;
Size = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
sizeof(OBJECT_HANDLE_COUNT_ENTRY);
((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
}
else
{
@ -261,7 +261,7 @@ ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
/* Add 4 more entries */
i += 4;
Size = OldSize += (4 * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
Size = OldSize += ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
}
/* Allocate the DB */
@ -395,7 +395,6 @@ ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
{
POBJECT_HEADER_QUOTA_INFO ObjectQuota;
ULONG PagedPoolCharge, NonPagedPoolCharge;
PEPROCESS Process;
/* Get quota information */
ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
@ -404,9 +403,6 @@ ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
/* Check if this is a new object */
if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
{
/* Set the flag */
*NewObject = TRUE;
/* Remove the flag */
ObjectHeader->Flags &= ~ OB_FLAG_CREATE_INFO;
if (ObjectQuota)
@ -422,14 +418,19 @@ ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
}
/*
* Charge the quota
* FIXME: This is a *COMPLETE* guess and probably defintely not the way to do this.
*/
Process = PsGetCurrentProcess();
Process->QuotaBlock->QuotaEntry[PagedPool].Usage += PagedPoolCharge;
Process->QuotaBlock->QuotaEntry[NonPagedPool].Usage += NonPagedPoolCharge;
ObjectHeader->QuotaBlockCharged = Process->QuotaBlock;
/* Charge the quota */
ObjectHeader->QuotaBlockCharged = (PVOID)1;
#if 0
PsChargeSharedPoolQuota(PsGetCurrentProcess(),
PagedPoolCharge,
NonPagedPoolCharge);
#endif
/* Check if we don't have a quota block */
if (!ObjectHeader->QuotaBlockCharged) return STATUS_QUOTA_EXCEEDED;
/* Now set the flag */
*NewObject = TRUE;
}
/* Return success */
@ -459,10 +460,10 @@ VOID
NTAPI
ObpDecrementHandleCount(IN PVOID ObjectBody,
IN PEPROCESS Process,
IN ACCESS_MASK GrantedAccess)
IN ACCESS_MASK GrantedAccess,
IN POBJECT_TYPE ObjectType)
{
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
LONG SystemHandleCount, ProcessHandleCount;
LONG NewCount;
KIRQL CalloutIrql;
@ -474,7 +475,6 @@ ObpDecrementHandleCount(IN PVOID ObjectBody,
/* Get the object type and header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
ObjectType = ObjectHeader->Type;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Decrementing count for: %p. HC LC %lx %lx\n",
__FUNCTION__,
@ -540,6 +540,11 @@ ObpDecrementHandleCount(IN PVOID ObjectBody,
i--;
}
}
else
{
/* No database, so no entry */
HandleEntry = NULL;
}
}
/* Check if this is the last handle */
@ -686,7 +691,10 @@ ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
ExDestroyHandle(HandleTable, Handle, HandleEntry);
/* Now decrement the handle count */
ObpDecrementHandleCount(Body, PsGetCurrentProcess(), GrantedAccess);
ObpDecrementHandleCount(Body,
PsGetCurrentProcess(),
GrantedAccess,
ObjectType);
/* Dereference the object as well */
ObDereferenceObject(Body);
@ -749,6 +757,7 @@ ObpIncrementHandleCount(IN PVOID Object,
KIRQL CalloutIrql;
KPROCESSOR_MODE ProbeMode;
ULONG Total;
PAGED_CODE();
/* Get the object header and type */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
@ -1359,7 +1368,8 @@ ObpCreateUnnamedHandle(IN PVOID Object,
/* Decrement the handle count and detach */
ObpDecrementHandleCount(&ObjectHeader->Body,
PsGetCurrentProcess(),
GrantedAccess);
GrantedAccess,
ObjectType);
/* Detach and fail */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
@ -1596,7 +1606,8 @@ ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
/* Decrement the handle count and detach */
ObpDecrementHandleCount(&ObjectHeader->Body,
PsGetCurrentProcess(),
GrantedAccess);
GrantedAccess,
ObjectType);
/* Handle extra references */
if (AdditionalReferences)
@ -1644,6 +1655,7 @@ ObpCloseHandle(IN HANDLE Handle,
KAPC_STATE ApcState;
PHANDLE_TABLE_ENTRY HandleTableEntry;
NTSTATUS Status;
PEPROCESS Process = PsGetCurrentProcess();
PAGED_CODE();
OBTRACE(OB_HANDLE_DEBUG,
"%s - Closing handle: %lx\n", __FUNCTION__, Handle);
@ -1656,7 +1668,7 @@ ObpCloseHandle(IN HANDLE Handle,
Handle = ObKernelHandleToHandle(Handle);
/* Check if we're not in the system process */
if (PsGetCurrentProcess() != PsInitialSystemProcess)
if (Process != PsInitialSystemProcess)
{
/* Attach to the system process */
KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
@ -1666,7 +1678,7 @@ ObpCloseHandle(IN HANDLE Handle,
else
{
/* Use the process's handle table */
HandleTable = PsGetCurrentProcess()->ObjectTable;
HandleTable = Process->ObjectTable;
}
/* Enter a critical region to protect handle access */
@ -1698,18 +1710,43 @@ ObpCloseHandle(IN HANDLE Handle,
/* Detach */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
/* Check if this was a user-mode caller with a valid debug port */
if ((AccessMode != KernelMode) &&
(PsGetCurrentProcess()->DebugPort))
/* Check if we have a valid handle that's not the process or thread */
if ((Handle) &&
(Handle != NtCurrentProcess()) &&
(Handle != NtCurrentThread()))
{
/* Raise an exception */
Status = KeRaiseUserException(STATUS_INVALID_HANDLE);
}
else
{
/* Just return the status */
Status = STATUS_INVALID_HANDLE;
/* Check if we came from user mode */
if (AccessMode != KernelMode)
{
/* Check if we have no debug port */
if (Process->DebugPort)
{
/* Make sure we're not attached */
if (!KeIsAttachedProcess())
{
/* Raise an exception */
return KeRaiseUserException(STATUS_INVALID_HANDLE);
}
}
}
else
{
/* This is kernel mode. Check if we're exiting */
if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
(Process->Peb))
{
/* Check if the debugger is enabled */
if (KdDebuggerEnabled)
{
/* Bugcheck */
KeBugCheckEx(0, (ULONG_PTR)Handle, 1, 0, 0);
}
}
}
}
/* Set invalid status */
Status = STATUS_INVALID_HANDLE;
}
/* Return status */
@ -1742,15 +1779,6 @@ ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
{
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
PAGED_CODE();
/* Don't allow operations on kernel objects */
if ((ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) &&
(SetHandleInfo->PreviousMode != KernelMode))
{
/* Fail */
return FALSE;
}
/* Check if making the handle inheritable */
if (SetHandleInfo->Information.Inherit)
@ -1775,12 +1803,12 @@ ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
if (SetHandleInfo->Information.ProtectFromClose)
{
/* Set the flag */
HandleTableEntry->ObAttributes |= OBJ_PROTECT_CLOSE;
HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
}
else
{
/* Otherwise, remove it */
HandleTableEntry->ObAttributes &= ~OBJ_PROTECT_CLOSE;
HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
}
/* Return success */
@ -1809,7 +1837,7 @@ ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
* @remarks None.
*
*--*/
VOID
BOOLEAN
NTAPI
ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
@ -1823,6 +1851,7 @@ ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
Handle,
CloseContext->AccessMode,
TRUE);
return TRUE;
}
/*++
@ -2078,6 +2107,15 @@ ObDuplicateObject(IN PEPROCESS SourceProcess,
ObDereferenceProcessHandleTable(SourceProcess);
return Status;
}
else
{
/* Check if we have to don't have to audit object close */
if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
{
/* Then there is no audit mask */
AuditMask = 0;
}
}
/* Check if there's no target process */
if (!TargetProcess)
@ -2142,6 +2180,12 @@ ObDuplicateObject(IN PEPROCESS SourceProcess,
/* Duplicate them */
HandleAttributes = HandleInformation.HandleAttributes;
}
else
{
/* Don't allow caller to bypass auditing */
HandleAttributes |= HandleInformation.HandleAttributes &
OBJ_AUDIT_OBJECT_CLOSE;
}
/* Check if we're duplicating the access */
if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
@ -2151,6 +2195,7 @@ ObDuplicateObject(IN PEPROCESS SourceProcess,
ObjectType = ObjectHeader->Type;
/* Fill out the entry */
RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
NewHandleEntry.Object = ObjectHeader;
NewHandleEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
@ -2162,8 +2207,9 @@ ObDuplicateObject(IN PEPROCESS SourceProcess,
&ObjectType->TypeInfo.GenericMapping);
}
/* Set the target access */
TargetAccess = DesiredAccess;
/* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY);
NewHandleEntry.GrantedAccess = TargetAccess;
/* Check if we're asking for new access */
@ -2242,7 +2288,8 @@ ObDuplicateObject(IN PEPROCESS SourceProcess,
/* Undo the increment */
ObpDecrementHandleCount(SourceObject,
TargetProcess,
TargetAccess);
TargetAccess,
ObjectType);
/* Deference the object and set failure status */
ObDereferenceObject(SourceObject);
@ -2623,9 +2670,11 @@ ObFindHandleForObject(IN PEPROCESS Process,
{
OBP_FIND_HANDLE_DATA FindData;
BOOLEAN Result = FALSE;
PVOID ObjectTable;
/* Make sure we have an object table */
if (Process->ObjectTable)
ObjectTable = ObReferenceProcessHandleTable(Process);
if (ObjectTable)
{
/* Check if we have an object */
if (Object)
@ -2652,6 +2701,9 @@ ObFindHandleForObject(IN PEPROCESS Process,
/* Set success */
Result = TRUE;
}
/* Let go of the table */
ObDereferenceProcessHandleTable(Process);
}
/* Return the result */
@ -2859,6 +2911,14 @@ ObInsertObject(IN PVOID Object,
}
else
{
/* Check if this was a symbolic link */
if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
ObSymbolicLinkType)
{
/* Dereference it */
ObDereferenceObject(InsertObject);
}
/* Caller wanted to create a new object, fail */
Status = STATUS_OBJECT_NAME_COLLISION;
}
@ -3094,7 +3154,6 @@ NtDuplicateObject(IN HANDLE SourceProcessHandle,
HANDLE hTarget;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
OBTRACE(OB_HANDLE_DEBUG,
"%s - Duplicating handle: %lx for %lx into %lx.\n",
__FUNCTION__,
@ -3108,8 +3167,9 @@ NtDuplicateObject(IN HANDLE SourceProcessHandle,
/* Enter SEH */
_SEH_TRY
{
/* Probe the handle */
/* Probe the handle and assume failure */
ProbeForWriteHandle(TargetHandle);
*TargetHandle = NULL;
}
_SEH_HANDLE
{

View file

@ -398,7 +398,7 @@ ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
else
{
/* Copy the name */
RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength);
RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
}
}
@ -603,11 +603,12 @@ ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
else
{
/* Check if we have quota */
if ((ObjectCreateInfo->PagedPoolCharge !=
ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
(ObjectCreateInfo->NonPagedPoolCharge !=
ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
(ObjectCreateInfo->SecurityDescriptorCharge > 2048) ||
if ((((ObjectCreateInfo->PagedPoolCharge !=
ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
(ObjectCreateInfo->NonPagedPoolCharge !=
ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
(ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
(PsGetCurrentProcess() != PsInitialSystemProcess)) ||
(ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
{
/* Set quota size */
@ -1010,6 +1011,7 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
/* Verify parameters */
if (!(TypeName) ||
!(TypeName->Length) ||
(TypeName->Length % sizeof(WCHAR)) ||
!(ObjectTypeInitializer) ||
(ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
(ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_ATTRIBUTES) ||
@ -1167,7 +1169,12 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT,
Event);
}
/* FIXME: When LPC stops sucking, add a hack for Waitable Ports */
else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
{
/* Wait on the LPC Port's object directly */
LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(LPCP_PORT_OBJECT,
WaitEvent);
}
else
{
/* No default Object */
@ -1176,6 +1183,11 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
/* Initialize Object Type components */
ExInitializeResourceLite(&LocalObjectType->Mutex);
for (i = 0; i < 4; i++)
{
/* Initialize the object locks */
ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
}
InitializeListHead(&LocalObjectType->TypeList);
/* Lock the object type */