#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
/* GLOBALS ******************************************************************/
PETHREAD Thread;
PTEB Teb;
BOOLEAN DeadThread = FALSE;
+ KIRQL OldIrql;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG,
+ "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
/* Go to Passive Level */
KeLowerIrql(PASSIVE_LEVEL);
Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
}
- /* Check if this is a system thread, or if we're hiding */
- if (!(Thread->SystemThread) && !(Thread->HideFromDebugger))
+ /* Check if this is a dead thread, or if we're hiding */
+ if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
{
/* We're not, so notify the debugger */
- DbgkCreateThread(StartContext);
+ DbgkCreateThread(Thread, StartContext);
}
/* Make sure we're not already dead */
}
/* Raise to APC */
- KfRaiseIrql(APC_LEVEL);
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
/* Queue the User APC */
- KiInitializeUserApc(NULL,
- (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
- sizeof(KTRAP_FRAME) -
- sizeof(FX_SAVE_AREA)),
+ KiInitializeUserApc(KeGetExceptionFrame(&Thread->Tcb),
+ KeGetTrapFrame(&Thread->Tcb),
PspSystemDllEntryPoint,
NULL,
PspSystemDllBase,
/* Do we have a cookie set yet? */
if (!SharedUserData->Cookie)
{
- /*
- * FIXME: Generate cookie
- * Formula (roughly): Per-CPU Page Fault ^ Per-CPU Interrupt Time ^
- * Global System Time ^ Stack Address of where
- * the LARGE_INTEGER containing the Global System
- * Time is.
- */
+ LARGE_INTEGER SystemTime;
+ ULONG NewCookie;
+ PKPRCB Prcb;
+
+ /* Generate a new cookie */
+ KeQuerySystemTime(&SystemTime);
+ Prcb = KeGetCurrentPrcb();
+ NewCookie = Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^
+ SystemTime.u.LowPart ^ SystemTime.u.HighPart ^
+ (ULONG_PTR)&SystemTime;
+
+ /* Set the new cookie*/
+ InterlockedCompareExchange((LONG*)&SharedUserData->Cookie,
+ NewCookie,
+ 0);
}
}
+LONG
+PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers)
+{
+ /* Print debugging information */
+ DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
+ ExceptionPointers);
+ DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
+ ExceptionPointers->ExceptionRecord->ExceptionCode,
+ ExceptionPointers->ExceptionRecord->ExceptionAddress,
+ ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
+ ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
+ ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
+ ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
+
+ /* Bugcheck the system */
+ KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED,
+ ExceptionPointers->ExceptionRecord->ExceptionCode,
+ (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
+ (ULONG_PTR)ExceptionPointers->ExceptionRecord,
+ (ULONG_PTR)ExceptionPointers->ContextRecord);
+ return 0;
+}
+
VOID
NTAPI
PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext)
{
PETHREAD Thread;
+ PSTRACE(PS_THREAD_DEBUG,
+ "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
/* Unlock the dispatcher Database */
KeLowerIrql(PASSIVE_LEVEL);
Thread = PsGetCurrentThread();
/* Make sure the thread isn't gone */
- if (!(Thread->Terminated) && !(Thread->DeadThread))
+ _SEH2_TRY
{
- /* Call it the Start Routine */
- StartRoutine(StartContext);
+ if (!(Thread->Terminated) && !(Thread->DeadThread))
+ {
+ /* Call the Start Routine */
+ StartRoutine(StartContext);
+ }
}
+ _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation()))
+ {
+ /* Bugcheck if we got here */
+ KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
+ }
+ _SEH2_END;
/* Exit the thread */
PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
NTAPI
PspCreateThread(OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+ IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS TargetProcess,
OUT PCLIENT_ID ClientId,
PEPROCESS Process;
PETHREAD Thread;
PTEB TebBase = NULL;
- KIRQL OldIrql;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- NTSTATUS Status;
+ NTSTATUS Status, AccessStatus;
HANDLE_TABLE_ENTRY CidEntry;
+ ACCESS_STATE LocalAccessState;
+ PACCESS_STATE AccessState = &LocalAccessState;
+ AUX_ACCESS_DATA AuxData;
+ BOOLEAN Result, SdAllocated;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ SECURITY_SUBJECT_CONTEXT SubjectContext;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG,
+ "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
+ ThreadContext, TargetProcess, ProcessHandle);
/* If we were called from PsCreateSystemThread, then we're kernel mode */
if (StartRoutine) PreviousMode = KernelMode;
PreviousMode,
(PVOID*)&Process,
NULL);
+ PSREFTRACE(Process);
}
else
{
/* Also make sure that User-Mode isn't trying to create a system thread */
if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
{
+ /* Fail */
ObDereferenceObject(Process);
return STATUS_INVALID_HANDLE;
}
/* Initialize rundown protection */
ExInitializeRundownProtection(&Thread->RundownProtect);
+ /* Initialize exit code */
+ Thread->ExitStatus = STATUS_PENDING;
+
/* Set the Process CID */
Thread->ThreadsProcess = Process;
Thread->Cid.UniqueProcess = Process->UniqueProcessId;
KeInitializeSpinLock(&Thread->ActiveTimerListLock);
/* Acquire rundown protection */
- ExAcquireRundownProtection(&Process->RundownProtect);
+ if (!ExAcquireRundownProtection (&Process->RundownProtect))
+ {
+ /* Fail */
+ ObDereferenceObject(Thread);
+ return STATUS_PROCESS_IS_TERMINATING;
+ }
/* Now let the kernel initialize the context */
if (ThreadContext)
{
/* User-mode Thread, create Teb */
- TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
- if (!TebBase)
+ Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase);
+ if (!NT_SUCCESS(Status))
{
/* Failed to create the TEB. Release rundown and dereference */
ExReleaseRundownProtection(&Process->RundownProtect);
ObDereferenceObject(Thread);
- return STATUS_INSUFFICIENT_RESOURCES;
+ return Status;
}
/* Set the Start Addresses */
- Thread->StartAddress = (PVOID)ThreadContext->Eip;
- Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
+ Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
+ Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);
/* Let the kernel intialize the Thread */
Status = KeInitThread(&Thread->Tcb,
{
/* System Thread */
Thread->StartAddress = StartRoutine;
- InterlockedOr((PLONG)&Thread->CrossThreadFlags, CT_SYSTEM_THREAD_BIT);
+ PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
/* Let the kernel intialize the Thread */
Status = KeInitThread(&Thread->Tcb,
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
/* Start the thread */
KeStartThread(&Thread->Tcb);
- /* FIXME: Wake pushlock */
+ /* Release the process lock */
+ ExReleasePushLockExclusive(&Process->ProcessLock);
+ KeLeaveCriticalRegion();
/* Release rundown */
ExReleaseRundownProtection(&Process->RundownProtect);
/* 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 */
+ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
+
+ /* If we were suspended, wake it up */
+ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
+
+ /* Dispatch thread */
+ KeReadyThread(&Thread->Tcb);
+
+ /* Dereference completely to kill it */
+ ObDereferenceObjectEx(Thread, 2);
+ return Status;
+ }
+
/* 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 */
- _SEH_TRY
+ _SEH2_TRY
{
/* Return Cid and Handle */
if (ClientId) *ClientId = Thread->Cid;
*ThreadHandle = hThread;
}
- _SEH_HANDLE
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Get the exception code */
- Status = _SEH_GetExceptionCode();
+ /* Thread insertion failed, thread is dead */
+ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
+
+ /* If we were suspended, wake it up */
+ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
+
+ /* Dispatch thread */
+ KeReadyThread(&Thread->Tcb);
+
+ /* Dereference it, leaving only the keep-alive */
+ ObDereferenceObject(Thread);
+
+ /* Close its handle, killing it */
+ ObCloseHandle(ThreadHandle, PreviousMode);
+
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
- _SEH_END;
+ _SEH2_END;
+ }
+ else
+ {
+ /* Thread insertion failed, thread is dead */
+ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
+
+ /* If we were suspended, wake it up */
+ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
}
- /* Set the thread access mask */
- Thread->GrantedAccess = THREAD_ALL_ACCESS;
+ /* Get the create time */
+ KeQuerySystemTime(&Thread->CreateTime);
+ ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
+
+ /* Make sure the thread isn't dead */
+ if (!Thread->DeadThread)
+ {
+ /* Get the thread's SD */
+ Status = ObGetObjectSecurity(Thread,
+ &SecurityDescriptor,
+ &SdAllocated);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Thread insertion failed, thread is dead */
+ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
+
+ /* If we were suspended, wake it up */
+ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
+
+ /* Dispatch thread */
+ KeReadyThread(&Thread->Tcb);
+
+ /* Dereference it, leaving only the keep-alive */
+ ObDereferenceObject(Thread);
+
+ /* Close its handle, killing it */
+ ObCloseHandle(ThreadHandle, PreviousMode);
+ return Status;
+ }
+
+ /* Create the subject context */
+ SubjectContext.ProcessAuditId = Process;
+ SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
+ SubjectContext.ClientToken = NULL;
+
+ /* Do the access check */
+ Result = SeAccessCheck(SecurityDescriptor,
+ &SubjectContext,
+ FALSE,
+ MAXIMUM_ALLOWED,
+ 0,
+ NULL,
+ &PsThreadType->TypeInfo.GenericMapping,
+ PreviousMode,
+ &Thread->GrantedAccess,
+ &AccessStatus);
+
+ /* Dereference the token and let go the SD */
+ ObFastDereferenceObject(&Process->Token,
+ SubjectContext.PrimaryToken);
+ ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
+
+ /* Remove access if it failed */
+ if (!Result) Process->GrantedAccess = 0;
+
+ /* Set least some minimum access */
+ Thread->GrantedAccess |= (THREAD_TERMINATE |
+ THREAD_SET_INFORMATION |
+ THREAD_QUERY_INFORMATION);
+ }
+ else
+ {
+ /* Set the thread access mask to maximum */
+ Thread->GrantedAccess = THREAD_ALL_ACCESS;
+ }
/* Dispatch thread */
- OldIrql = KeAcquireDispatcherDatabaseLock ();
- KiReadyThread(&Thread->Tcb);
- KeReleaseDispatcherDatabaseLock(OldIrql);
+ KeReadyThread(&Thread->Tcb);
/* Dereference it, leaving only the keep-alive */
ObDereferenceObject(Thread);
/* 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);
+ KeLeaveCriticalRegion();
+
+ /* 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 **********************************************************/
PEPROCESS TargetProcess = NULL;
HANDLE Handle = ProcessHandle;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG,
+ "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
+ ProcessHandle, StartRoutine, StartContext);
/* Check if we have a handle. If not, use the System Process */
if (!ProcessHandle)
PETHREAD FoundThread;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
KeEnterCriticalRegion();
/* Get the CID Handle Entry */
NTAPI
PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
{
- return Thread->HardErrorsAreDisabled;
+ return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
}
/*
NTAPI
PsIsThreadImpersonating(IN PETHREAD Thread)
{
- return Thread->ActiveImpersonationInfo;
+ return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
}
/*
/*
* @implemented
*/
-struct _W32THREAD*
+PVOID
NTAPI
PsGetCurrentThreadWin32Thread(VOID)
{
IN BOOLEAN CreateSuspended)
{
INITIAL_TEB SafeInitialTeb;
- NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG,
+ "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
/* Check if this was from user-mode */
- if(KeGetPreviousMode() != KernelMode)
+ if (KeGetPreviousMode() != KernelMode)
{
/* Make sure that we got a context */
if (!ThreadContext) return STATUS_INVALID_PARAMETER;
/* Protect checks */
- _SEH_TRY
+ _SEH2_TRY
{
/* Make sure the handle pointer we got is valid */
ProbeForWriteHandle(ThreadHandle);
/* Check if the caller wants a client id */
- if(ClientId)
+ if (ClientId)
{
/* Make sure we can write to it */
ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
/* Check the Initial TEB */
ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
SafeInitialTeb = *InitialTeb;
- }
- _SEH_HANDLE
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- Status = _SEH_GetExceptionCode();
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
- _SEH_END;
-
- /* Handle any failures in our SEH checks */
- if (!NT_SUCCESS(Status)) return Status;
+ _SEH2_END;
}
else
{
CLIENT_ID SafeClientId;
ULONG Attributes = 0;
HANDLE hThread = NULL;
- NTSTATUS Status = STATUS_SUCCESS;
+ NTSTATUS Status;
PETHREAD Thread;
BOOLEAN HasObjectName = FALSE;
ACCESS_STATE AccessState;
- AUX_DATA AuxData;
+ AUX_ACCESS_DATA AuxData;
PAGED_CODE();
+ PSTRACE(PS_THREAD_DEBUG,
+ "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
/* Check if we were called from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
- _SEH_TRY
+ _SEH2_TRY
{
/* Probe the thread handle */
ProbeForWriteHandle(ThreadHandle);
HasObjectName = (ObjectAttributes->ObjectName != NULL);
Attributes = ObjectAttributes->Attributes;
}
- _SEH_HANDLE
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Get the exception code */
- Status = _SEH_GetExceptionCode();
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
- _SEH_END;
- if (!NT_SUCCESS(Status)) return Status;
+ _SEH2_END;
}
else
{
if (NT_SUCCESS(Status))
{
/* Protect against bad user-mode pointers */
- _SEH_TRY
+ _SEH2_TRY
{
/* Write back the handle */
*ThreadHandle = hThread;
}
- _SEH_HANDLE
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
- Status = _SEH_GetExceptionCode();
+ Status = _SEH2_GetExceptionCode();
}
- _SEH_END;
+ _SEH2_END;
}
/* Return status */
return Status;
}
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtYieldExecution(VOID)
-{
- KiDispatchThread(Ready);
- return STATUS_SUCCESS;
-}
-
/* EOF */