mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
- Object Manager Improvements (3 of 3):
* Implement Per-Processor Lookaside List based allocation and de-allocation of the Object Create Information (object attributes capture) and of the object name. I counted over 4000 allocations for only 30 seconds of runtime, so this change greatly reduces pool fragmentation and increases speed. (Implementation is similar to the IRP lookaside list implementation, but inlined for speed). * Fix some cases where we weren't freeing captured information properly. This patch should also decrease memory leaks/usage. * Comment/formatting fixes. svn path=/trunk/; revision=22100
This commit is contained in:
parent
453c3d0af0
commit
a12050c789
10 changed files with 332 additions and 130 deletions
|
@ -6168,6 +6168,17 @@ RtlUlonglongByteSwap(
|
|||
((STRING)->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR) \
|
||||
)
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlInitEmptyUnicodeString(OUT PUNICODE_STRING UnicodeString,
|
||||
IN PWSTR Buffer,
|
||||
IN USHORT BufferSize)
|
||||
{
|
||||
UnicodeString->Length = 0;
|
||||
UnicodeString->MaximumLength = BufferSize;
|
||||
UnicodeString->Buffer = Buffer;
|
||||
}
|
||||
|
||||
NTOSAPI
|
||||
NTSTATUS
|
||||
DDKAPI
|
||||
|
|
|
@ -241,7 +241,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
|||
DPRINT("Capturing Create Info\n");
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
PreviousMode,
|
||||
CmiKeyType,
|
||||
FALSE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
@ -471,7 +471,7 @@ Cleanup:
|
|||
ReleaseCapturedUnicodeString(&CapturedClass,
|
||||
PreviousMode);
|
||||
}
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
|
||||
if (Object != NULL) ObDereferenceObject(Object);
|
||||
|
||||
|
@ -1305,7 +1305,7 @@ NtOpenKey(OUT PHANDLE KeyHandle,
|
|||
DPRINT("Capturing Create Info\n");
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
PreviousMode,
|
||||
CmiKeyType,
|
||||
FALSE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
@ -1320,7 +1320,7 @@ NtOpenKey(OUT PHANDLE KeyHandle,
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -1372,7 +1372,7 @@ openkey_cleanup:
|
|||
PostOpenKeyInfo.Object = NT_SUCCESS(Status) ? (PVOID)Object : NULL;
|
||||
PostOpenKeyInfo.Status = Status;
|
||||
CmiCallRegisteredCallbacks (RegNtPostOpenKey, &PostOpenKeyInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
|
||||
if (Object)
|
||||
{
|
||||
|
|
|
@ -712,7 +712,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
|||
DPRINT("Capturing Create Info\n");
|
||||
Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
|
||||
KernelMode,
|
||||
CmiKeyType,
|
||||
FALSE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
@ -729,7 +729,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
|||
NULL,
|
||||
NULL);
|
||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
|
|
|
@ -514,6 +514,9 @@ ExpInitializeExecutive(VOID)
|
|||
/* Check if the structures match the ASM offset constants */
|
||||
ExecuteRuntimeAsserts();
|
||||
|
||||
/* Set 1 CPU for now, we'll increment this later */
|
||||
KeNumberProcessors = 1;
|
||||
|
||||
/* Sets up the Text Sections of the Kernel and HAL for debugging */
|
||||
LdrInit1();
|
||||
|
||||
|
@ -554,21 +557,18 @@ ExpInitializeExecutive(VOID)
|
|||
/* Load basic Security for other Managers */
|
||||
if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
|
||||
|
||||
/* Create the Basic Object Manager Types to allow new Object Types */
|
||||
ObInit();
|
||||
|
||||
/* Initialize Lookaside Lists */
|
||||
ExpInitLookasideLists();
|
||||
|
||||
/* Create the Basic Object Manager Types to allow new Object Types */
|
||||
ObInit();
|
||||
|
||||
/* Set up Region Maps, Sections and the Paging File */
|
||||
MmInit2();
|
||||
|
||||
/* Initialize Tokens now that the Object Manager is ready */
|
||||
if (!SeInit2()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
|
||||
|
||||
/* Set 1 CPU for now, we'll increment this later */
|
||||
KeNumberProcessors = 1;
|
||||
|
||||
/* Initalize the Process Manager */
|
||||
PiInitProcessManager();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ extern POBJECT_DIRECTORY ObpTypeDirectoryObject;
|
|||
extern PHANDLE_TABLE ObpKernelHandleTable;
|
||||
extern WORK_QUEUE_ITEM ObpReaperWorkItem;
|
||||
extern volatile PVOID ObpReaperList;
|
||||
extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
|
@ -221,14 +222,15 @@ ObFastDereferenceObject(
|
|||
PVOID Object
|
||||
);
|
||||
|
||||
/* Secure object information functions */
|
||||
/* Object Create and Object Name Capture Functions */
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
ObpCaptureObjectName(
|
||||
IN PUNICODE_STRING CapturedName,
|
||||
IN PUNICODE_STRING ObjectName,
|
||||
IN KPROCESSOR_MODE AccessMode
|
||||
IN KPROCESSOR_MODE AccessMode,
|
||||
IN BOOLEAN AllocateFromLookaside
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
|
@ -236,17 +238,124 @@ STDCALL
|
|||
ObpCaptureObjectAttributes(
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN KPROCESSOR_MODE AccessMode,
|
||||
IN POBJECT_TYPE ObjectType,
|
||||
IN BOOLEAN AllocateFromLookaside,
|
||||
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
||||
OUT PUNICODE_STRING ObjectName
|
||||
);
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo);
|
||||
static __inline
|
||||
ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
|
||||
{
|
||||
/* Check if we have a security descriptor */
|
||||
if (ObjectCreateInfo->SecurityDescriptor)
|
||||
{
|
||||
/* Release it */
|
||||
SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
|
||||
ObjectCreateInfo->ProbeMode,
|
||||
TRUE);
|
||||
ObjectCreateInfo->SecurityDescriptor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* object information classes */
|
||||
PVOID
|
||||
static __inline
|
||||
ObpAllocateCapturedAttributes(IN PP_NPAGED_LOOKASIDE_NUMBER Type)
|
||||
{
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
PVOID Buffer;
|
||||
PNPAGED_LOOKASIDE_LIST List;
|
||||
|
||||
/* Get the P list first */
|
||||
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
|
||||
|
||||
/* Attempt allocation */
|
||||
List->L.TotalAllocates++;
|
||||
Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
|
||||
if (!Buffer)
|
||||
{
|
||||
/* Let the balancer know that the P list failed */
|
||||
List->L.AllocateMisses++;
|
||||
|
||||
/* Try the L List */
|
||||
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
|
||||
List->L.TotalAllocates++;
|
||||
Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
|
||||
if (!Buffer)
|
||||
{
|
||||
/* Let the balancer know the L list failed too */
|
||||
List->L.AllocateMisses++;
|
||||
|
||||
/* Allocate it */
|
||||
Buffer = List->L.Allocate(List->L.Type, List->L.Size, List->L.Tag);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return buffer */
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
VOID
|
||||
static __inline
|
||||
ObpFreeCapturedAttributes(IN PVOID Buffer,
|
||||
IN PP_NPAGED_LOOKASIDE_NUMBER Type)
|
||||
{
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
PNPAGED_LOOKASIDE_LIST List;
|
||||
|
||||
/* Use the P List */
|
||||
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
|
||||
List->L.TotalFrees++;
|
||||
|
||||
/* Check if the Free was within the Depth or not */
|
||||
if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
|
||||
{
|
||||
/* Let the balancer know */
|
||||
List->L.FreeMisses++;
|
||||
|
||||
/* Use the L List */
|
||||
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
|
||||
List->L.TotalFrees++;
|
||||
|
||||
/* Check if the Free was within the Depth or not */
|
||||
if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
|
||||
{
|
||||
/* All lists failed, use the pool */
|
||||
List->L.FreeMisses++;
|
||||
List->L.Free(Buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The free was within the Depth */
|
||||
InterlockedPushEntrySList(&List->L.ListHead,
|
||||
(PSINGLE_LIST_ENTRY)Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
static __inline
|
||||
ObpReleaseCapturedName(IN PUNICODE_STRING Name)
|
||||
{
|
||||
/* We know this is a pool-allocation if the size doesn't match */
|
||||
if (Name->MaximumLength != 248)
|
||||
{
|
||||
ExFreePool(Name->Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, free from the lookaside */
|
||||
ObpFreeCapturedAttributes(Name, LookasideNameBufferList);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
static __inline
|
||||
ObpFreeAndReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
|
||||
{
|
||||
/* First release the attributes, then free them from the lookaside list */
|
||||
ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
|
||||
}
|
||||
|
||||
#endif /* __INCLUDE_INTERNAL_OBJMGR_H */
|
||||
|
|
|
@ -962,7 +962,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
|
|||
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
AccessMode,
|
||||
NULL,
|
||||
FALSE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
@ -977,7 +977,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
|
|||
0,
|
||||
NULL);
|
||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
|
||||
|
||||
/* FIXME: wt... */
|
||||
|
@ -2415,7 +2415,7 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
{
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
AccessMode,
|
||||
NULL,
|
||||
FALSE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
}
|
||||
|
@ -2440,7 +2440,7 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
if (AccessMode != KernelMode)
|
||||
{
|
||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||
ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
}
|
||||
if (!NT_SUCCESS (Status))
|
||||
{
|
||||
|
|
|
@ -767,7 +767,7 @@ ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
/* Capture all the info */
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
AccessMode,
|
||||
ObjectType,
|
||||
TRUE,
|
||||
&ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
@ -828,7 +828,7 @@ Cleanup:
|
|||
/* Release the object attributes and return status */
|
||||
Quickie:
|
||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -1054,8 +1054,7 @@ ObInsertObject(IN PVOID Object,
|
|||
|
||||
/* We can delete the Create Info now */
|
||||
Header->ObjectCreateInfo = NULL;
|
||||
ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
ExFreePool(ObjectCreateInfo);
|
||||
ObpFreeAndReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
|
||||
DPRINT("Status %x\n", Status);
|
||||
return Status;
|
||||
|
|
|
@ -41,6 +41,90 @@ PDEVICE_MAP ObSystemDeviceMap = NULL;
|
|||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
INIT_FUNCTION
|
||||
ObInit2(VOID)
|
||||
{
|
||||
ULONG i;
|
||||
PKPRCB Prcb;
|
||||
PNPAGED_LOOKASIDE_LIST CurrentList = NULL;
|
||||
|
||||
/* Initialize the OBJECT_CREATE_INFORMATION List */
|
||||
ExInitializeNPagedLookasideList(&ObpCiLookasideList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
sizeof(OBJECT_CREATE_INFORMATION),
|
||||
TAG('O', 'b', 'C', 'I'),
|
||||
32);
|
||||
|
||||
/* Set the captured UNICODE_STRING Object Name List */
|
||||
ExInitializeNPagedLookasideList(&ObpNmLookasideList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
248,
|
||||
TAG('O', 'b', 'N', 'M'),
|
||||
16);
|
||||
|
||||
/* Now allocate the per-processor lists */
|
||||
for (i = 0; i < KeNumberProcessors; i++)
|
||||
{
|
||||
/* Get the PRCB for this CPU */
|
||||
Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
|
||||
|
||||
/* Set the OBJECT_CREATE_INFORMATION List */
|
||||
Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCiLookasideList.L;
|
||||
CurrentList = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(NPAGED_LOOKASIDE_LIST),
|
||||
TAG('O', 'b', 'C', 'I'));
|
||||
if (CurrentList)
|
||||
{
|
||||
/* Initialize it */
|
||||
ExInitializeNPagedLookasideList(CurrentList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
sizeof(OBJECT_CREATE_INFORMATION),
|
||||
TAG('O', 'b', 'C', 'I'),
|
||||
32);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No list, use the static buffer */
|
||||
CurrentList = &ObpCiLookasideList;
|
||||
}
|
||||
|
||||
/* Link it */
|
||||
Prcb->PPLookasideList[LookasideCreateInfoList].P = &CurrentList->L;
|
||||
|
||||
/* Set the captured UNICODE_STRING Object Name List */
|
||||
Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNmLookasideList.L;
|
||||
CurrentList = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(NPAGED_LOOKASIDE_LIST),
|
||||
TAG('O', 'b', 'N', 'M'));
|
||||
if (CurrentList)
|
||||
{
|
||||
/* Initialize it */
|
||||
ExInitializeNPagedLookasideList(CurrentList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
248,
|
||||
TAG('O', 'b', 'N', 'M'),
|
||||
16);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No list, use the static buffer */
|
||||
CurrentList = &ObpNmLookasideList;
|
||||
}
|
||||
|
||||
/* Link it */
|
||||
Prcb->PPLookasideList[LookasideNameBufferList].P = &CurrentList->L;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
INIT_FUNCTION
|
||||
ObInit(VOID)
|
||||
|
@ -60,6 +144,9 @@ ObInit(VOID)
|
|||
/* Setup the Object Reaper */
|
||||
ExInitializeWorkItem(&ObpReaperWorkItem, ObpReapObject, NULL);
|
||||
|
||||
/* Initialize lookaside lists */
|
||||
ObInit2();
|
||||
|
||||
/* Create the Type Type */
|
||||
DPRINT("Creating Type Type\n");
|
||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||
|
@ -72,7 +159,7 @@ ObInit(VOID)
|
|||
ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
|
||||
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
|
||||
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType);
|
||||
|
||||
|
||||
/* Create the Directory Type */
|
||||
DPRINT("Creating Directory Type\n");
|
||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||
|
|
|
@ -21,6 +21,9 @@ extern ULONG NtGlobalFlag;
|
|||
|
||||
POBJECT_TYPE ObTypeObjectType = NULL;
|
||||
KEVENT ObpDefaultObject;
|
||||
|
||||
NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
|
||||
|
||||
WORK_QUEUE_ITEM ObpReaperWorkItem;
|
||||
volatile PVOID ObpReaperList;
|
||||
|
||||
|
@ -64,7 +67,7 @@ ObpDeallocateObject(IN PVOID Object)
|
|||
if (Header->ObjectCreateInfo)
|
||||
{
|
||||
/* Free it */
|
||||
ObpReleaseCapturedAttributes(Header->ObjectCreateInfo);
|
||||
ObpFreeAndReleaseCapturedAttributes(Header->ObjectCreateInfo);
|
||||
Header->ObjectCreateInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -178,31 +181,30 @@ ObpReapObject(IN PVOID Parameter)
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
|
||||
IN PUNICODE_STRING ObjectName,
|
||||
IN KPROCESSOR_MODE AccessMode)
|
||||
IN KPROCESSOR_MODE AccessMode,
|
||||
IN BOOLEAN AllocateFromLookaside)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG StringLength;
|
||||
ULONG StringLength, MaximumLength;
|
||||
PWCHAR StringBuffer = NULL;
|
||||
UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Initialize the Input String */
|
||||
RtlInitUnicodeString(CapturedName, NULL);
|
||||
RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
|
||||
|
||||
/* Protect everything */
|
||||
_SEH_TRY
|
||||
{
|
||||
/* First Probe the String */
|
||||
DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName);
|
||||
/* Check if we came from user mode */
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
ProbeForRead(ObjectName,
|
||||
sizeof(UNICODE_STRING),
|
||||
sizeof(USHORT));
|
||||
/* First Probe the String */
|
||||
ProbeForReadUnicodeString(ObjectName);
|
||||
LocalName = *ObjectName;
|
||||
|
||||
ProbeForRead(LocalName.Buffer,
|
||||
LocalName.Length,
|
||||
sizeof(WCHAR));
|
||||
|
@ -214,13 +216,12 @@ ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
|
|||
}
|
||||
|
||||
/* Make sure there really is a string */
|
||||
DPRINT("Probing OK\n");
|
||||
if ((StringLength = LocalName.Length))
|
||||
{
|
||||
/* Check that the size is a valid WCHAR multiple */
|
||||
if ((StringLength & (sizeof(WCHAR) - 1)) ||
|
||||
/* Check that the NULL-termination below will work */
|
||||
(StringLength == (MAXUSHORT - sizeof(WCHAR) + 1)))
|
||||
(StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
|
||||
{
|
||||
/* PS: Please keep the checks above expanded for clarity */
|
||||
DPRINT1("Invalid String Length\n");
|
||||
|
@ -228,19 +229,36 @@ ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Allocate a non-paged buffer for this string */
|
||||
DPRINT("Capturing String\n");
|
||||
/* Set the maximum length to the length plus the terminator */
|
||||
MaximumLength = StringLength + sizeof(UNICODE_NULL);
|
||||
|
||||
/* Check if we should use the lookaside buffer */
|
||||
//if (!(AllocateFromLookaside) || (MaximumLength > 248))
|
||||
{
|
||||
/* Nope, allocate directly from pool */
|
||||
StringBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
||||
MaximumLength,
|
||||
OB_NAME_TAG);
|
||||
}
|
||||
//else
|
||||
{
|
||||
/* Allocate from the lookaside */
|
||||
// MaximumLength = 248;
|
||||
// StringBuffer =
|
||||
// ObpAllocateCapturedAttributes(LookasideNameBufferList);
|
||||
}
|
||||
|
||||
/* Setup the string */
|
||||
CapturedName->Length = StringLength;
|
||||
CapturedName->MaximumLength = StringLength + sizeof(WCHAR);
|
||||
if ((StringBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
||||
StringLength + sizeof(WCHAR),
|
||||
OB_NAME_TAG)))
|
||||
{
|
||||
CapturedName->MaximumLength = MaximumLength;
|
||||
CapturedName->Buffer = StringBuffer;
|
||||
|
||||
/* Make sure we have a buffer */
|
||||
if (StringBuffer)
|
||||
{
|
||||
/* Copy the string and null-terminate it */
|
||||
RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength);
|
||||
StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
|
||||
CapturedName->Buffer = StringBuffer;
|
||||
DPRINT("String Captured: %wZ\n", CapturedName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -254,23 +272,19 @@ ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
|
|||
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
|
||||
/* Remember to free the buffer in case of failure */
|
||||
DPRINT1("Failed\n");
|
||||
if (StringBuffer) ExFreePool(StringBuffer);
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
|
||||
/* Return */
|
||||
DPRINT("Returning: %lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN KPROCESSOR_MODE AccessMode,
|
||||
IN POBJECT_TYPE ObjectType,
|
||||
IN BOOLEAN AllocateFromLookaside,
|
||||
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
||||
OUT PUNICODE_STRING ObjectName)
|
||||
{
|
||||
|
@ -278,90 +292,92 @@ ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||||
PSECURITY_QUALITY_OF_SERVICE SecurityQos;
|
||||
PUNICODE_STRING LocalObjectName = NULL;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Zero out the Capture Data */
|
||||
DPRINT("ObpCaptureObjectAttributes\n");
|
||||
RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
|
||||
|
||||
|
||||
/* SEH everything here for protection */
|
||||
_SEH_TRY
|
||||
{
|
||||
/* Check if we got Oba */
|
||||
/* Check if we got attributes */
|
||||
if (ObjectAttributes)
|
||||
{
|
||||
/* Check if we're in user mode */
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
DPRINT("Probing OBA\n");
|
||||
/* Probe the attributes */
|
||||
ProbeForRead(ObjectAttributes,
|
||||
sizeof(OBJECT_ATTRIBUTES),
|
||||
sizeof(ULONG));
|
||||
}
|
||||
|
||||
|
||||
/* Validate the Size and Attributes */
|
||||
DPRINT("Validating OBA\n");
|
||||
if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
|
||||
(ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES))
|
||||
{
|
||||
/* Invalid combination, fail */
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
DPRINT1("Invalid Size: %lx or Attributes: %lx\n",
|
||||
ObjectAttributes->Length, ObjectAttributes->Attributes);
|
||||
_SEH_LEAVE;
|
||||
}
|
||||
|
||||
|
||||
/* Set some Create Info */
|
||||
DPRINT("Creating OBCI\n");
|
||||
ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
|
||||
ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
|
||||
LocalObjectName = ObjectAttributes->ObjectName;
|
||||
SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
|
||||
SecurityQos = ObjectAttributes->SecurityQualityOfService;
|
||||
|
||||
/* Validate the SD */
|
||||
|
||||
/* Check if we have a security descriptor */
|
||||
if (SecurityDescriptor)
|
||||
{
|
||||
DPRINT("Probing SD: %x\n", SecurityDescriptor);
|
||||
/* Capture it */
|
||||
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
|
||||
AccessMode,
|
||||
NonPagedPool,
|
||||
TRUE,
|
||||
&ObjectCreateInfo->SecurityDescriptor);
|
||||
&ObjectCreateInfo->
|
||||
SecurityDescriptor);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Unable to capture the security descriptor!!!\n");
|
||||
/* Capture failed, quit */
|
||||
ObjectCreateInfo->SecurityDescriptor = NULL;
|
||||
_SEH_LEAVE;
|
||||
}
|
||||
|
||||
DPRINT("Probe done\n");
|
||||
|
||||
/* Save the probe mode and security descriptor size */
|
||||
ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
|
||||
ObjectCreateInfo->ProbeMode = AccessMode;
|
||||
}
|
||||
|
||||
/* Validate the QoS */
|
||||
|
||||
/* Check if we have QoS */
|
||||
if (SecurityQos)
|
||||
{
|
||||
/* Check if we came from user mode */
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
DPRINT("Probing QoS\n");
|
||||
/* Validate the QoS */
|
||||
ProbeForRead(SecurityQos,
|
||||
sizeof(SECURITY_QUALITY_OF_SERVICE),
|
||||
sizeof(ULONG));
|
||||
}
|
||||
|
||||
|
||||
/* Save Info */
|
||||
ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
|
||||
ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService;
|
||||
ObjectCreateInfo->SecurityQos =
|
||||
&ObjectCreateInfo->SecurityQualityOfService;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't have a name */
|
||||
LocalObjectName = NULL;
|
||||
}
|
||||
}
|
||||
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
||||
{
|
||||
/* Get the exception */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
DPRINT1("Failed\n");
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
|
@ -370,46 +386,29 @@ ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
/* Now check if the Object Attributes had an Object Name */
|
||||
if (LocalObjectName)
|
||||
{
|
||||
DPRINT("Name Buffer: %wZ\n", LocalObjectName);
|
||||
Status = ObpCaptureObjectName(ObjectName,
|
||||
LocalObjectName,
|
||||
AccessMode);
|
||||
AccessMode,
|
||||
AllocateFromLookaside);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the string */
|
||||
RtlInitUnicodeString(ObjectName, NULL);
|
||||
RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
|
||||
|
||||
/* He can't have specified a Root Directory */
|
||||
if (ObjectCreateInfo->RootDirectory)
|
||||
{
|
||||
DPRINT1("Invalid name\n");
|
||||
Status = STATUS_OBJECT_NAME_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("Failed to capture, cleaning up\n");
|
||||
ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
}
|
||||
|
||||
DPRINT("Return to caller %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
|
||||
{
|
||||
/* Release the SD, it's the only thing we allocated */
|
||||
if (ObjectCreateInfo->SecurityDescriptor)
|
||||
{
|
||||
SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
|
||||
ObjectCreateInfo->ProbeMode,
|
||||
TRUE);
|
||||
ObjectCreateInfo->SecurityDescriptor = NULL;
|
||||
}
|
||||
/* Cleanup if we failed */
|
||||
if (!NT_SUCCESS(Status)) ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
|
||||
/* Return status to caller */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
|
@ -688,20 +687,17 @@ ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
|
|||
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||||
UNICODE_STRING ObjectName;
|
||||
POBJECT_HEADER Header;
|
||||
|
||||
DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
|
||||
Type, ObjectAttributes, Object);
|
||||
|
||||
/* Allocate a Buffer for the Object Create Info */
|
||||
ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(*ObjectCreateInfo),
|
||||
TAG('O','b','C', 'I'));
|
||||
/* Allocate a capture buffer */
|
||||
ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList);
|
||||
if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* Capture all the info */
|
||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||
ObjectAttributesAccessMode,
|
||||
Type,
|
||||
FALSE,
|
||||
ObjectCreateInfo,
|
||||
&ObjectName);
|
||||
if (NT_SUCCESS(Status))
|
||||
|
@ -730,32 +726,32 @@ ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
|
|||
{
|
||||
/* Return the Object */
|
||||
*Object = &Header->Body;
|
||||
|
||||
/* Check if this is a permanent object */
|
||||
if (Header->Flags & OB_FLAG_PERMANENT)
|
||||
{
|
||||
/* Do the privilege check */
|
||||
if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
|
||||
ObjectAttributesAccessMode))
|
||||
{
|
||||
/* Fail */
|
||||
ObpDeallocateObject(*Object);
|
||||
Status = STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
/* Check if this is a permanent object */
|
||||
if (Header->Flags & OB_FLAG_PERMANENT)
|
||||
{
|
||||
/* Do the privilege check */
|
||||
if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
|
||||
ObjectAttributesAccessMode))
|
||||
{
|
||||
/* Fail */
|
||||
ObpDeallocateObject(*Object);
|
||||
Status = STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the Capture Info, we don't need it */
|
||||
ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
}
|
||||
|
||||
/* We failed, so release the Buffer */
|
||||
ExFreePool(ObjectCreateInfo);
|
||||
ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
|
|||
ACCESS_STATE AccessState;
|
||||
|
||||
/* Capture the name */
|
||||
Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode);
|
||||
Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode, TRUE);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Check if we didn't get an access state */
|
||||
|
@ -264,7 +264,7 @@ ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
|
|||
|
||||
Quickie:
|
||||
/* Free the captured name if we had one, and return status */
|
||||
if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
|
||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue