Author: ion Date: Tue Jul 11 23:45:16 2006 New Revision: 23013
URL: http://svn.reactos.org/svn/reactos?rev=23013&view=rev Log: - 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.
Modified: trunk/reactos/include/ndk/extypes.h trunk/reactos/ntoskrnl/include/internal/ex.h trunk/reactos/ntoskrnl/include/internal/se.h trunk/reactos/ntoskrnl/ob/obref.c trunk/reactos/ntoskrnl/ps/psmgr.c trunk/reactos/ntoskrnl/ps/security.c trunk/reactos/ntoskrnl/ps/thread.c trunk/reactos/ntoskrnl/se/semgr.c trunk/reactos/ntoskrnl/se/token.c
Modified: trunk/reactos/include/ndk/extypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/extypes.h?rev=2... ============================================================================== --- trunk/reactos/include/ndk/extypes.h (original) +++ trunk/reactos/include/ndk/extypes.h Tue Jul 11 23:45:16 2006 @@ -361,8 +361,8 @@ union { PVOID Object; - ULONG RefCnt:3; - ULONG Value; + ULONG_PTR RefCnt:3; + ULONG_PTR Value; }; } EX_FAST_REF, *PEX_FAST_REF;
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/e... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ex.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ex.h Tue Jul 11 23:45:16 2006 @@ -267,7 +267,7 @@ #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
Modified: trunk/reactos/ntoskrnl/include/internal/se.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/s... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/se.h (original) +++ trunk/reactos/ntoskrnl/include/internal/se.h Tue Jul 11 23:45:16 2006 @@ -121,6 +121,15 @@ SeDeassignPrimaryToken(struct _EPROCESS *Process);
NTSTATUS +NTAPI +SeSubProcessToken( + IN PTOKEN Parent, + OUT PTOKEN *Token, + IN BOOLEAN InUse, + IN ULONG SessionId +); + +NTSTATUS STDCALL SepCreateImpersonationTokenDacl( PTOKEN Token,
Modified: trunk/reactos/ntoskrnl/ob/obref.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ob/obref.c?rev=230... ============================================================================== --- trunk/reactos/ntoskrnl/ob/obref.c (original) +++ trunk/reactos/ntoskrnl/ob/obref.c Tue Jul 11 23:45:16 2006 @@ -18,36 +18,182 @@ /* 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) -{ - /* FIXME: Fast Referencing is Unimplemented */ - FastRef->Object = Object; + IN PVOID Object OPTIONAL) +{ + /* 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 */ - - /* Do a normal Reference */ - ObReferenceObject(FastRef->Object); + ULONG_PTR Value, NewValue; + ULONG_PTR Count; + PVOID 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) -{ - /* FIXME: Fast Referencing is Unimplemented */ - - /* Do a normal Dereference */ - ObDereferenceObject(FastRef->Object); + IN PVOID Object) +{ + ULONG_PTR Value, NewValue; + + /* 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 @@ ObFastReplaceObject(IN PEX_FAST_REF FastRef, PVOID Object) { - PVOID OldObject = FastRef->Object; - - /* FIXME: Fast Referencing is Unimplemented */ - FastRef->Object = Object; - - /* Do a normal Dereference */ - ObDereferenceObject(OldObject); - - /* Return old Object*/ + ULONG_PTR NewValue; + EX_FAST_REF OldRef; + PVOID OldObject; + + /* 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 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 @@ } 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); } } }
Modified: trunk/reactos/ntoskrnl/ps/psmgr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/psmgr.c?rev=230... ============================================================================== --- trunk/reactos/ntoskrnl/ps/psmgr.c (original) +++ trunk/reactos/ntoskrnl/ps/psmgr.c Tue Jul 11 23:45:16 2006 @@ -196,6 +196,7 @@ 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 @@ /* 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 }
Modified: trunk/reactos/ntoskrnl/ps/security.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/security.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/ps/security.c (original) +++ trunk/reactos/ntoskrnl/ps/security.c Tue Jul 11 23:45:16 2006 @@ -176,7 +176,7 @@ PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */ - //Token = ObFastReferenceObjectLocked(&Process->Token); + Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */ PspUnlockProcessSecurityShared(Process); @@ -222,47 +222,25 @@ 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); - - /* Initialize the Object Attributes */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - 0, - NULL, - NULL); - - /* 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); + ParentToken = PsReferencePrimaryToken(Parent); + + /* Duplicate it */ + Status = SeSubProcessToken(ParentToken, &NewToken, TRUE, 0); + + /* 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 @@ PspLockProcessSecurityShared(Process);
/* Do a Locked Fast Reference */ - //Token = ObFastReferenceObjectLocked(&Process->Token); + Token = ObFastReferenceObjectLocked(&Process->Token);
/* Unlock the Process */ PspUnlockProcessSecurityShared(Process);
Modified: trunk/reactos/ntoskrnl/ps/thread.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/thread.c?rev=23... ============================================================================== --- trunk/reactos/ntoskrnl/ps/thread.c (original) +++ trunk/reactos/ntoskrnl/ps/thread.c Tue Jul 11 23:45:16 2006 @@ -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.
Modified: trunk/reactos/ntoskrnl/se/semgr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/se/semgr.c?rev=230... ============================================================================== --- trunk/reactos/ntoskrnl/se/semgr.c (original) +++ trunk/reactos/ntoskrnl/se/semgr.c Tue Jul 11 23:45:16 2006 @@ -485,7 +485,7 @@
if (SubjectContext->PrimaryToken != NULL) { - ObDereferenceObject(SubjectContext->PrimaryToken); + ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken); }
if (SubjectContext->ClientToken != NULL)
Modified: trunk/reactos/ntoskrnl/se/token.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/se/token.c?rev=230... ============================================================================== --- trunk/reactos/ntoskrnl/se/token.c (original) +++ trunk/reactos/ntoskrnl/se/token.c Tue Jul 11 23:45:16 2006 @@ -321,8 +321,51 @@ 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; }
/* @@ -2472,6 +2515,7 @@
PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl); + KEBUGCHECK(0); ObfDereferenceObject(PrimaryToken); ObfDereferenceObject(Thread); if (!NT_SUCCESS(Status))