- 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 union
{ {
PVOID Object; PVOID Object;
ULONG RefCnt:3; ULONG_PTR RefCnt:3;
ULONG Value; ULONG_PTR Value;
}; };
} EX_FAST_REF, *PEX_FAST_REF; } 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 ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
#define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y) #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
#else #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) #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
#endif #endif

View file

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

View file

@ -17,37 +17,183 @@
/* PRIVATE FUNCTIONS *********************************************************/ /* 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 VOID
FASTCALL FASTCALL
ObInitializeFastReference(IN PEX_FAST_REF FastRef, ObInitializeFastReference(IN PEX_FAST_REF FastRef,
PVOID Object) IN PVOID Object OPTIONAL)
{ {
/* FIXME: Fast Referencing is Unimplemented */ /* Check if we were given an object and reference it 7 times */
FastRef->Object = Object; 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 PVOID
FASTCALL FASTCALL
ObFastReferenceObject(IN PEX_FAST_REF FastRef) ObFastReferenceObject(IN PEX_FAST_REF FastRef)
{ {
/* FIXME: Fast Referencing is Unimplemented */ ULONG_PTR Value, NewValue;
ULONG_PTR Count;
PVOID Object;
/* Do a normal Reference */ /* Start reference loop */
ObReferenceObject(FastRef->Object); 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 the Object */
return FastRef->Object; return Object;
} }
VOID VOID
FASTCALL FASTCALL
ObFastDereferenceObject(IN PEX_FAST_REF FastRef, ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
PVOID Object) IN PVOID Object)
{ {
/* FIXME: Fast Referencing is Unimplemented */ ULONG_PTR Value, NewValue;
/* Do a normal Dereference */ /* Sanity checks */
ObDereferenceObject(FastRef->Object); 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 PVOID
@ -55,15 +201,38 @@ FASTCALL
ObFastReplaceObject(IN PEX_FAST_REF FastRef, ObFastReplaceObject(IN PEX_FAST_REF FastRef,
PVOID Object) PVOID Object)
{ {
PVOID OldObject = FastRef->Object; ULONG_PTR NewValue;
EX_FAST_REF OldRef;
PVOID OldObject;
/* FIXME: Fast Referencing is Unimplemented */ /* Check if we were given an object and reference it 7 times */
FastRef->Object = Object; if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Do a normal Dereference */ /* Sanity check */
ObDereferenceObject(OldObject); 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; return OldObject;
} }
@ -112,17 +281,8 @@ ObfDereferenceObject(IN PVOID Object)
} }
else else
{ {
/* Add us to the list */ /* Add us to the deferred deletion list */
do ObpDeferObjectDeletion(Object);
{
Header->NextToFree = ObpReaperList;
} while (InterlockedCompareExchangePointer(&ObpReaperList,
Header,
Header->NextToFree) !=
Header->NextToFree);
/* Queue the work item */
ExQueueWorkItem(&ObpReaperWorkItem, DelayedWorkQueue);
} }
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -321,10 +321,53 @@ SepDuplicateToken(PTOKEN Token,
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
ObDereferenceObject(AccessToken);
return(Status); 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 * @unimplemented
*/ */
@ -2472,6 +2515,7 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl); Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
KEBUGCHECK(0);
ObfDereferenceObject(PrimaryToken); ObfDereferenceObject(PrimaryToken);
ObfDereferenceObject(Thread); ObfDereferenceObject(Thread);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))