From 3774a4b2594189f81cd9adb6617b7d932f5fa748 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 23 Jul 2006 17:45:30 +0000 Subject: [PATCH] - Acquire Process lock when touching the thread list entry and incrementing the process' active threads. - Set the Thread Create Time on creation, I had forgotten this! - Handle failures for thread-safety/race conditions. If the process was deleted or the thread terminated behind our back, then go through a manual un-initalization code path. - Just like previous process patch, add code to now create an access state with SeCreateAccessStateEx. - Handle failure of ObInsertObject. svn path=/trunk/; revision=23249 --- reactos/ntoskrnl/include/internal/ke.h | 6 ++ reactos/ntoskrnl/include/internal/ob.h | 7 +++ reactos/ntoskrnl/ke/kthread.c | 9 +++ reactos/ntoskrnl/ps/thread.c | 85 +++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 7a61aff1edd..5b72b646b3c 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -291,6 +291,12 @@ KeInitializeThread( IN PVOID KernelStack ); +VOID +NTAPI +KeUninitThread( + IN PKTHREAD Thread +); + NTSTATUS NTAPI KeInitThread( diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index 44780fd85c3..2c09fd287a3 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -193,6 +193,13 @@ ObpDeleteObject( IN PVOID Object ); +LONG +FASTCALL +ObDereferenceObjectEx( + IN PVOID Object, + IN ULONG Count +); + LONG FASTCALL ObReferenceObjectEx( diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index 3ef0ebdc093..578f0e898b9 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.c @@ -728,6 +728,15 @@ KeCapturePersistentThreadState(IN PVOID CurrentThread, UNIMPLEMENTED; } +VOID +NTAPI +KeUninitThread(IN PKTHREAD Thread) +{ + /* Delete the stack */ + MmDeleteKernelStack(Thread->StackBase, FALSE); + Thread->InitialStack = NULL; +} + NTSTATUS NTAPI KeInitThread(IN OUT PKTHREAD Thread, diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index 42d3a104c4b..4e9df2b1874 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -146,6 +146,9 @@ PspCreateThread(OUT PHANDLE ThreadHandle, KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; HANDLE_TABLE_ENTRY CidEntry; + ACCESS_STATE LocalAccessState; + PACCESS_STATE AccessState = &LocalAccessState; + AUX_DATA AuxData; PAGED_CODE(); /* If we were called from PsCreateSystemThread, then we're kernel mode */ @@ -299,7 +302,21 @@ PspCreateThread(OUT PHANDLE ThreadHandle, return Status; } - /* FIXME: Acquire exclusive pushlock */ + /* Lock the process */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&Process->ProcessLock); + + /* Make sure the proces didn't just die on us */ + if (Process->ProcessDelete) goto Quickie; + + /* Check if the thread was ours, terminated and it was user mode */ + if ((Thread->Terminated) && + (ThreadContext) && + (Thread->ThreadsProcess == Process)) + { + /* Cleanup, we don't want to start it up and context switch */ + goto Quickie; + } /* * Insert the Thread into the Process's Thread List @@ -312,7 +329,9 @@ PspCreateThread(OUT PHANDLE ThreadHandle, /* Start the thread */ KeStartThread(&Thread->Tcb); - /* FIXME: Wake pushlock */ + /* Release the process lock */ + ExReleasePushLockExclusive(&Process->ProcessLock); + KeLeaveCriticalRegion(); /* Release rundown */ ExReleaseRundownProtection(&Process->RundownProtect); @@ -333,13 +352,43 @@ PspCreateThread(OUT PHANDLE ThreadHandle, /* Check if we were already terminated */ if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); + /* Create an access state */ + Status = SeCreateAccessStateEx(NULL, + ThreadContext ? + PsGetCurrentProcess() : Process, + &LocalAccessState, + &AuxData, + DesiredAccess, + &PsThreadType->TypeInfo.GenericMapping); + if (!NT_SUCCESS(Status)) + { + /* Access state failed, thread is dead */ + InterlockedOr(&Thread->CrossThreadFlags, CT_DEAD_THREAD_BIT); + + /* If we were suspended, wake it up */ + if (CreateSuspended) KeResumeThread(&Thread->Tcb); + + /* Dispatch thread */ + OldIrql = KeAcquireDispatcherDatabaseLock (); + KiReadyThread(&Thread->Tcb); + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Dereference completely to kill it */ + ObDereferenceObjectEx(Thread, 2); + } + /* Insert the Thread into the Object Manager */ Status = ObInsertObject(Thread, - NULL, + AccessState, DesiredAccess, 0, NULL, &hThread); + + /* Delete the access state if we had one */ + if (AccessState) SeDeleteAccessState(AccessState); + + /* Check for success */ if (NT_SUCCESS(Status)) { /* Wrap in SEH to protect against bad user-mode pointers */ @@ -356,6 +405,18 @@ PspCreateThread(OUT PHANDLE ThreadHandle, } _SEH_END; } + else + { + /* Thread insertion failed, thread is dead */ + InterlockedOr(&Thread->CrossThreadFlags, CT_DEAD_THREAD_BIT); + + /* If we were suspended, wake it up */ + if (CreateSuspended) KeResumeThread(&Thread->Tcb); + } + + /* Get the create time */ + KeQuerySystemTime(&Thread->CreateTime); + ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000)); /* Set the thread access mask */ Thread->GrantedAccess = THREAD_ALL_ACCESS; @@ -370,6 +431,24 @@ PspCreateThread(OUT PHANDLE ThreadHandle, /* Return */ return Status; + + /* Most annoying failure case ever, where we undo almost all manually */ +Quickie: + /* When we get here, the process is locked, unlock it */ + ExReleasePushLockExclusive(&Process->ProcessLock); + + /* Uninitailize it */ + KeUninitThread(&Thread->Tcb); + + /* If we had a TEB, delete it */ + if (TebBase) MmDeleteTeb(Process, TebBase); + + /* Release rundown protection, which we also hold */ + ExReleaseRundownProtection(&Process->RundownProtect); + + /* Dereference the thread and return failure */ + ObDereferenceObject(Thread); + return STATUS_PROCESS_IS_TERMINATING; } /* PUBLIC FUNCTIONS **********************************************************/