From d2e356eda6fc0dc32f1449272f6d6c379aeb89c3 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 11 Jul 2006 19:45:16 +0000 Subject: [PATCH] - 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 --- reactos/include/ndk/extypes.h | 4 +- reactos/ntoskrnl/include/internal/ex.h | 2 +- reactos/ntoskrnl/include/internal/se.h | 9 ++ reactos/ntoskrnl/ob/obref.c | 216 +++++++++++++++++++++---- reactos/ntoskrnl/ps/psmgr.c | 4 +- reactos/ntoskrnl/ps/security.c | 50 ++---- reactos/ntoskrnl/ps/thread.c | 5 +- reactos/ntoskrnl/se/semgr.c | 2 +- reactos/ntoskrnl/se/token.c | 46 +++++- 9 files changed, 264 insertions(+), 74 deletions(-) diff --git a/reactos/include/ndk/extypes.h b/reactos/include/ndk/extypes.h index 6689200892c..20603aa5932 100644 --- a/reactos/include/ndk/extypes.h +++ b/reactos/include/ndk/extypes.h @@ -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; diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index 82ba748fe47..056543af025 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -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 diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index b6808d3c208..a39f0f6f1a3 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -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( diff --git a/reactos/ntoskrnl/ob/obref.c b/reactos/ntoskrnl/ob/obref.c index b09affdd24f..99083b4859e 100644 --- a/reactos/ntoskrnl/ob/obref.c +++ b/reactos/ntoskrnl/ob/obref.c @@ -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); } } } diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index c2aea28e6f1..4d7fde8064d 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -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 } diff --git a/reactos/ntoskrnl/ps/security.c b/reactos/ntoskrnl/ps/security.c index f61028d86a0..275a4e9767c 100644 --- a/reactos/ntoskrnl/ps/security.c +++ b/reactos/ntoskrnl/ps/security.c @@ -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); diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index cf4be8de349..4c927482825 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -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. diff --git a/reactos/ntoskrnl/se/semgr.c b/reactos/ntoskrnl/se/semgr.c index 6446d5c8748..e574518f3c5 100644 --- a/reactos/ntoskrnl/se/semgr.c +++ b/reactos/ntoskrnl/se/semgr.c @@ -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) diff --git a/reactos/ntoskrnl/se/token.c b/reactos/ntoskrnl/se/token.c index dc042b93e5d..3882aa75f43 100644 --- a/reactos/ntoskrnl/se/token.c +++ b/reactos/ntoskrnl/se/token.c @@ -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))