- Implement Fast Referencing and fix EX_FAST_REF definition.

- Implement ObReferenceEx and ObDereferenceEx.
- Split off ObpDeferObjectCompletion. A new win2003/vista API requires direct acess to being able to defer deletes.
- Fix some bugs in Process Token management and make it all properly use Fast Referencing.
- When duplicating a token in a new process, don't de-reference it before it's even created, and also insert it.
- Change ExpChangeRundown macro to fix warnings in msvc.

svn path=/trunk/; revision=23013
This commit is contained in:
Alex Ionescu 2006-07-11 19:45:16 +00:00
parent f8aab41375
commit d2e356eda6
9 changed files with 264 additions and 74 deletions

View file

@ -361,8 +361,8 @@ typedef struct _EX_FAST_REF
union
{
PVOID Object;
ULONG RefCnt:3;
ULONG Value;
ULONG_PTR RefCnt:3;
ULONG_PTR Value;
};
} EX_FAST_REF, *PEX_FAST_REF;

View file

@ -267,7 +267,7 @@ static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
#define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
#define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
#else
#define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, y, z)
#define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
#define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
#endif

View file

@ -120,6 +120,15 @@ VOID
NTAPI
SeDeassignPrimaryToken(struct _EPROCESS *Process);
NTSTATUS
NTAPI
SeSubProcessToken(
IN PTOKEN Parent,
OUT PTOKEN *Token,
IN BOOLEAN InUse,
IN ULONG SessionId
);
NTSTATUS
STDCALL
SepCreateImpersonationTokenDacl(

View file

@ -17,37 +17,183 @@
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
ObpDeferObjectDeletion(IN PVOID Object)
{
POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
/* Add us to the list */
do
{
Header->NextToFree = ObpReaperList;
} while (InterlockedCompareExchangePointer(&ObpReaperList,
Header,
Header->NextToFree) !=
Header->NextToFree);
/* Queue the work item */
ExQueueWorkItem(&ObpReaperWorkItem, DelayedWorkQueue);
}
LONG
FASTCALL
ObReferenceObjectEx(IN PVOID Object,
IN ULONG Count)
{
/* Increment the reference count and return the count now */
return InterlockedExchangeAdd(&OBJECT_TO_OBJECT_HEADER(Object)->
PointerCount,
Count);
}
LONG
FASTCALL
ObDereferenceObjectEx(IN PVOID Object,
IN ULONG Count)
{
POBJECT_HEADER Header;
ULONG NewCount;
/* Extract the object header */
Header = OBJECT_TO_OBJECT_HEADER(Object);
/* Check whether the object can now be deleted. */
NewCount = InterlockedExchangeAdd(&Header->PointerCount, -Count);
if (!Count)
{
/* Add us to the deferred deletion list */
ObpDeferObjectDeletion(Object);
}
/* Return the current count */
return NewCount;
}
VOID
FASTCALL
ObInitializeFastReference(IN PEX_FAST_REF FastRef,
PVOID Object)
IN PVOID Object OPTIONAL)
{
/* FIXME: Fast Referencing is Unimplemented */
FastRef->Object = Object;
/* Check if we were given an object and reference it 7 times */
if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Sanity check */
ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
/* Check if the caller gave us an object */
if (Object)
{
/* He did, so write the biased pointer */
FastRef->Object = (PVOID)((ULONG_PTR)Object | MAX_FAST_REFS);
}
else
{
/* Otherwise, clear the current object */
FastRef->Object = NULL;
}
}
PVOID
FASTCALL
ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef)
{
PVOID Object;
/* Get the object and reference it slowly */
Object = (PVOID)((ULONG_PTR)FastRef->Object & MAX_FAST_REFS);
if (Object) ObReferenceObject(Object);
return Object;
}
PVOID
FASTCALL
ObFastReferenceObject(IN PEX_FAST_REF FastRef)
{
/* FIXME: Fast Referencing is Unimplemented */
ULONG_PTR Value, NewValue;
ULONG_PTR Count;
PVOID Object;
/* Do a normal Reference */
ObReferenceObject(FastRef->Object);
/* Start reference loop */
for (;;)
{
/* Get the current count */
Value = FastRef->Value;
if (!Value & MAX_FAST_REFS) break;
/* Increase the reference count */
NewValue = Value - 1;
if (ExpChangeRundown(FastRef, NewValue, Value) == Value) break;
}
/* Get the object and count */
Object = (PVOID)(Value &~ MAX_FAST_REFS);
Count = Value & MAX_FAST_REFS;
DPRINT("Ref: %p\n", Object);
/* Check if the reference count is over 1 */
if (Count > 1) return Object;
/* Check if the reference count has reached 0 */
if (!Count) return NULL;
/* Otherwise, reference the object 7 times */
ObReferenceObjectEx(Object, MAX_FAST_REFS);
ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
for (;;)
{
/* Check if the current count is too high */
Value = FastRef->Value;
if (((FastRef->RefCnt + MAX_FAST_REFS) > MAX_FAST_REFS) ||
((PVOID)((ULONG_PTR)FastRef->Object &~ MAX_FAST_REFS) != Object))
{
/* Completely dereference the object */
ObDereferenceObjectEx(Object, MAX_FAST_REFS);
break;
}
else
{
/* Increase the reference count */
NewValue = Value + MAX_FAST_REFS;
if (ExpChangeRundown(FastRef, NewValue, Value) == Value) break;
}
}
/* Return the Object */
return FastRef->Object;
return Object;
}
VOID
FASTCALL
ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
PVOID Object)
IN PVOID Object)
{
/* FIXME: Fast Referencing is Unimplemented */
ULONG_PTR Value, NewValue;
/* Do a normal Dereference */
ObDereferenceObject(FastRef->Object);
/* Sanity checks */
DPRINT("DeRef: %p\n", Object);
ASSERT(Object);
ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
/* Start dereference loop */
for (;;)
{
/* Get the current count */
Value = FastRef->Value;
if ((Value ^ (ULONG_PTR)Object) < MAX_FAST_REFS)
{
/* Decrease the reference count */
NewValue = Value + 1;
if (ExpChangeRundown(FastRef, NewValue, Value) == Value) return;
}
else
{
/* Do a normal Dereference */
ObDereferenceObject(Object);
return;
}
}
}
PVOID
@ -55,15 +201,38 @@ FASTCALL
ObFastReplaceObject(IN PEX_FAST_REF FastRef,
PVOID Object)
{
PVOID OldObject = FastRef->Object;
ULONG_PTR NewValue;
EX_FAST_REF OldRef;
PVOID OldObject;
/* FIXME: Fast Referencing is Unimplemented */
FastRef->Object = Object;
/* Check if we were given an object and reference it 7 times */
if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Do a normal Dereference */
ObDereferenceObject(OldObject);
/* Sanity check */
ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
/* Return old Object*/
/* Check if the caller gave us an object */
if (Object)
{
/* He did, so bias the pointer */
NewValue = (ULONG_PTR)Object | MAX_FAST_REFS;
}
else
{
/* No object, we're clearing */
NewValue = 0;
}
/* Switch objects */
OldRef.Value = InterlockedExchange(&FastRef->Value, NewValue);
OldObject = (PVOID)((ULONG_PTR)OldRef.Object &~ MAX_FAST_REFS);
if ((OldObject) && (OldRef.RefCnt))
{
/* Dereference the old object */
ObDereferenceObjectEx(OldObject, OldRef.RefCnt);
}
/* Return the old object */
return OldObject;
}
@ -112,17 +281,8 @@ ObfDereferenceObject(IN PVOID Object)
}
else
{
/* Add us to the list */
do
{
Header->NextToFree = ObpReaperList;
} while (InterlockedCompareExchangePointer(&ObpReaperList,
Header,
Header->NextToFree) !=
Header->NextToFree);
/* Queue the work item */
ExQueueWorkItem(&ObpReaperWorkItem, DelayedWorkQueue);
/* Add us to the deferred deletion list */
ObpDeferObjectDeletion(Object);
}
}
}

View file

@ -196,6 +196,7 @@ PsInitProcessManagment(VOID)
InitializeListHead(&PsIdleProcess->Pcb.ThreadListHead);
InitializeListHead(&PsIdleProcess->ThreadListHead);
InitializeListHead(&PsIdleProcess->ActiveProcessLinks);
ObInitializeFastReference(&PsIdleProcess->Token, NULL);
KeInitializeDispatcherHeader(&PsIdleProcess->Pcb.Header,
ProcessObject,
sizeof(EPROCESS) / sizeof(LONG),
@ -278,8 +279,7 @@ PsInitProcessManagment(VOID)
/* No parent, this is the Initial System Process. Assign Boot Token */
BootToken = SepCreateSystemProcessToken();
BootToken->TokenInUse = TRUE;
PsInitialSystemProcess->Token.Object = BootToken; /* FIXME */
ObReferenceObject(BootToken);
ObInitializeFastReference(&PsInitialSystemProcess->Token, BootToken);
}
#endif
}

View file

@ -176,7 +176,7 @@ PsReferencePrimaryToken(PEPROCESS Process)
PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */
//Token = ObFastReferenceObjectLocked(&Process->Token);
Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
@ -222,47 +222,25 @@ PspInitializeProcessSecurity(PEPROCESS Process,
PEPROCESS Parent OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PTOKEN NewToken, ParentToken;
/* If we have a parent, then duplicate the Token */
if (Parent) {
PTOKEN pNewToken;
PTOKEN pParentToken;
OBJECT_ATTRIBUTES ObjectAttributes;
if (Parent)
{
/* Get the Parent Token */
pParentToken = PsReferencePrimaryToken(Parent);
ParentToken = PsReferencePrimaryToken(Parent);
/* Initialize the Object Attributes */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL);
/* Duplicate it */
Status = SeSubProcessToken(ParentToken, &NewToken, TRUE, 0);
/* Duplicate the Token */
Status = SepDuplicateToken(pParentToken,
&ObjectAttributes,
FALSE,
TokenPrimary,
pParentToken->ImpersonationLevel,
KernelMode,
&pNewToken);
if(!NT_SUCCESS(Status)) {
DPRINT1("Failed to Duplicate Token\n");
return Status;
}
/* Dereference the Token */
ObFastDereferenceObject(&Parent->Token, pParentToken);
/* Dereference the Parent */
ObFastDereferenceObject(&Parent->Token, ParentToken);
/* Set the new Token */
ObInitializeFastReference(&Process->Token, pNewToken);
} else {
ObInitializeFastReference(&Process->Token, NewToken);
}
else
{
#ifdef SCHED_REWRITE
PTOKEN BootToken;
@ -449,7 +427,7 @@ PsReferenceEffectiveToken(PETHREAD Thread,
PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */
//Token = ObFastReferenceObjectLocked(&Process->Token);
Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);

View file

@ -10,10 +10,9 @@
/*
* Alex FIXMEs:
* - CRITICAL: NtCurrentTeb returns KPCR.
* - CRITICAL: Verify rundown APIs (ex/rundown.c) and use them where necessary.
* - MAJOR: Implement Pushlocks and use them as process lock.
* - MAJOR: Use Process Rundown
* - MAJOR: Use Process Pushlock Locks
* - MAJOR: Implement Safe Referencing (See PsGetNextProcess/Thread).
* - MAJOR: Implement Fast Referencing (mostly for tokens).
* - MAJOR: Use Guarded Mutex instead of Fast Mutex for Active Process Locks.
* - Generate process cookie for user-more thread.
* - Add security calls where necessary.

View file

@ -485,7 +485,7 @@ SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
if (SubjectContext->PrimaryToken != NULL)
{
ObDereferenceObject(SubjectContext->PrimaryToken);
ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken);
}
if (SubjectContext->ClientToken != NULL)

View file

@ -321,10 +321,53 @@ SepDuplicateToken(PTOKEN Token,
return(STATUS_SUCCESS);
}
ObDereferenceObject(AccessToken);
return(Status);
}
NTSTATUS
NTAPI
SeSubProcessToken(IN PTOKEN ParentToken,
OUT PTOKEN *Token,
IN BOOLEAN InUse,
IN ULONG SessionId)
{
PTOKEN NewToken;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
/* Initialize the attributes and duplicate it */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = SepDuplicateToken(ParentToken,
&ObjectAttributes,
FALSE,
TokenPrimary,
ParentToken->ImpersonationLevel,
KernelMode,
&NewToken);
if (NT_SUCCESS(Status))
{
/* Insert it */
Status = ObInsertObject(NewToken,
NULL,
0,
1,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the session ID */
NewToken->SessionId = SessionId;
NewToken->TokenInUse = InUse;
/* Return the token */
*Token = NewToken;
}
}
/* Return status */
return Status;
}
/*
* @unimplemented
*/
@ -2472,6 +2515,7 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
KEBUGCHECK(0);
ObfDereferenceObject(PrimaryToken);
ObfDereferenceObject(Thread);
if (!NT_SUCCESS(Status))