2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Process Manager: Thread Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
10 /* INCLUDES ****************************************************************/
16 /* GLOBALS ******************************************************************/
18 extern BOOLEAN CcPfEnablePrefetcher
;
19 extern ULONG MmReadClusterSize
;
20 POBJECT_TYPE PsThreadType
= NULL
;
22 /* PRIVATE FUNCTIONS *********************************************************/
26 PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine
,
27 IN PVOID StartContext
)
31 BOOLEAN DeadThread
= FALSE
;
34 PSTRACE(PS_THREAD_DEBUG
,
35 "StartRoutine: %p StartContext: %p\n", StartRoutine
, StartContext
);
37 /* Go to Passive Level */
38 KeLowerIrql(PASSIVE_LEVEL
);
39 Thread
= PsGetCurrentThread();
41 /* Check if the thread is dead */
42 if (Thread
->DeadThread
)
44 /* Remember that we're dead */
49 /* Get the Locale ID and save Preferred Proc */
51 Teb
->CurrentLocale
= MmGetSessionLocaleId();
52 Teb
->IdealProcessor
= Thread
->Tcb
.IdealProcessor
;
55 /* Check if this is a dead thread, or if we're hiding */
56 if (!(Thread
->DeadThread
) && !(Thread
->HideFromDebugger
))
58 /* We're not, so notify the debugger */
59 DbgkCreateThread(Thread
, StartContext
);
62 /* Make sure we're not already dead */
65 /* Check if the Prefetcher is enabled */
66 if (CcPfEnablePrefetcher
)
68 /* FIXME: Prepare to prefetch this process */
72 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
74 /* Queue the User APC */
75 KiInitializeUserApc(KeGetExceptionFrame(&Thread
->Tcb
),
76 KeGetTrapFrame(&Thread
->Tcb
),
77 PspSystemDllEntryPoint
,
82 /* Lower it back to passive */
83 KeLowerIrql(PASSIVE_LEVEL
);
87 /* We're dead, kill us now */
88 PspTerminateThreadByPointer(Thread
,
89 STATUS_THREAD_IS_TERMINATING
,
93 /* Do we have a cookie set yet? */
94 while (!SharedUserData
->Cookie
)
96 LARGE_INTEGER SystemTime
;
100 /* Generate a new cookie */
101 KeQuerySystemTime(&SystemTime
);
102 Prcb
= KeGetCurrentPrcb();
103 NewCookie
= (Prcb
->MmPageFaultCount
^ Prcb
->InterruptTime
^
104 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
^
105 (ULONG
)(ULONG_PTR
)&SystemTime
);
107 /* Set the new cookie*/
108 InterlockedCompareExchange((LONG
*)&SharedUserData
->Cookie
,
115 PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers
)
117 /* Print debugging information */
118 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
120 DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
121 ExceptionPointers
->ExceptionRecord
->ExceptionCode
,
122 ExceptionPointers
->ExceptionRecord
->ExceptionAddress
,
123 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[0],
124 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[1],
125 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[2],
126 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[3]);
128 /* Bugcheck the system */
129 KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
,
130 ExceptionPointers
->ExceptionRecord
->ExceptionCode
,
131 (ULONG_PTR
)ExceptionPointers
->ExceptionRecord
->ExceptionAddress
,
132 (ULONG_PTR
)ExceptionPointers
->ExceptionRecord
,
133 (ULONG_PTR
)ExceptionPointers
->ContextRecord
);
139 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine
,
140 IN PVOID StartContext
)
143 PSTRACE(PS_THREAD_DEBUG
,
144 "StartRoutine: %p StartContext: %p\n", StartRoutine
, StartContext
);
146 /* Unlock the dispatcher Database */
147 KeLowerIrql(PASSIVE_LEVEL
);
148 Thread
= PsGetCurrentThread();
150 /* Make sure the thread isn't gone */
153 if (!(Thread
->Terminated
) && !(Thread
->DeadThread
))
155 /* Call the Start Routine */
156 StartRoutine(StartContext
);
159 _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation()))
161 /* Bugcheck if we got here */
162 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED
);
166 /* Exit the thread */
167 PspTerminateThreadByPointer(Thread
, STATUS_SUCCESS
, TRUE
);
172 PspCreateThread(OUT PHANDLE ThreadHandle
,
173 IN ACCESS_MASK DesiredAccess
,
174 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
175 IN HANDLE ProcessHandle
,
176 IN PEPROCESS TargetProcess
,
177 OUT PCLIENT_ID ClientId
,
178 IN PCONTEXT ThreadContext
,
179 IN PINITIAL_TEB InitialTeb
,
180 IN BOOLEAN CreateSuspended
,
181 IN PKSTART_ROUTINE StartRoutine OPTIONAL
,
182 IN PVOID StartContext OPTIONAL
)
188 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
189 NTSTATUS Status
, AccessStatus
;
190 HANDLE_TABLE_ENTRY CidEntry
;
191 ACCESS_STATE LocalAccessState
;
192 PACCESS_STATE AccessState
= &LocalAccessState
;
193 AUX_ACCESS_DATA AuxData
;
194 BOOLEAN Result
, SdAllocated
;
195 PSECURITY_DESCRIPTOR SecurityDescriptor
;
196 SECURITY_SUBJECT_CONTEXT SubjectContext
;
198 PSTRACE(PS_THREAD_DEBUG
,
199 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
200 ThreadContext
, TargetProcess
, ProcessHandle
);
202 /* If we were called from PsCreateSystemThread, then we're kernel mode */
203 if (StartRoutine
) PreviousMode
= KernelMode
;
205 /* Reference the Process by handle or pointer, depending on what we got */
208 /* Normal thread or System Thread */
209 Status
= ObReferenceObjectByHandle(ProcessHandle
,
210 PROCESS_CREATE_THREAD
,
219 /* System thread inside System Process, or Normal Thread with a bug */
222 /* Reference the Process by Pointer */
223 ObReferenceObject(TargetProcess
);
224 Process
= TargetProcess
;
225 Status
= STATUS_SUCCESS
;
229 /* Fake ObReference returning this */
230 Status
= STATUS_INVALID_HANDLE
;
234 /* Check for success */
235 if (!NT_SUCCESS(Status
)) return Status
;
237 /* Also make sure that User-Mode isn't trying to create a system thread */
238 if ((PreviousMode
!= KernelMode
) && (Process
== PsInitialSystemProcess
))
241 ObDereferenceObject(Process
);
242 return STATUS_INVALID_HANDLE
;
245 /* Create Thread Object */
246 Status
= ObCreateObject(PreviousMode
,
255 if (!NT_SUCCESS(Status
))
257 /* We failed; dereference the process and exit */
258 ObDereferenceObject(Process
);
262 /* Zero the Object entirely */
263 RtlZeroMemory(Thread
, sizeof(ETHREAD
));
265 /* Initialize rundown protection */
266 ExInitializeRundownProtection(&Thread
->RundownProtect
);
268 /* Initialize exit code */
269 Thread
->ExitStatus
= STATUS_PENDING
;
271 /* Set the Process CID */
272 Thread
->ThreadsProcess
= Process
;
273 Thread
->Cid
.UniqueProcess
= Process
->UniqueProcessId
;
275 /* Create Cid Handle */
276 CidEntry
.Object
= Thread
;
277 CidEntry
.GrantedAccess
= 0;
278 Thread
->Cid
.UniqueThread
= ExCreateHandle(PspCidTable
, &CidEntry
);
279 if (!Thread
->Cid
.UniqueThread
)
281 /* We couldn't create the CID, dereference the thread and fail */
282 ObDereferenceObject(Thread
);
283 return STATUS_INSUFFICIENT_RESOURCES
;
286 /* Save the read cluster size */
287 Thread
->ReadClusterSize
= MmReadClusterSize
;
289 /* Initialize the LPC Reply Semaphore */
290 KeInitializeSemaphore(&Thread
->LpcReplySemaphore
, 0, 1);
292 /* Initialize the list heads and locks */
293 InitializeListHead(&Thread
->LpcReplyChain
);
294 InitializeListHead(&Thread
->IrpList
);
295 InitializeListHead(&Thread
->PostBlockList
);
296 InitializeListHead(&Thread
->ActiveTimerListHead
);
297 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
299 /* Acquire rundown protection */
300 if (!ExAcquireRundownProtection (&Process
->RundownProtect
))
303 ObDereferenceObject(Thread
);
304 return STATUS_PROCESS_IS_TERMINATING
;
307 /* Now let the kernel initialize the context */
310 /* User-mode Thread, create Teb */
311 Status
= MmCreateTeb(Process
, &Thread
->Cid
, InitialTeb
, &TebBase
);
312 if (!NT_SUCCESS(Status
))
314 /* Failed to create the TEB. Release rundown and dereference */
315 ExReleaseRundownProtection(&Process
->RundownProtect
);
316 ObDereferenceObject(Thread
);
320 /* Set the Start Addresses from the untrusted ThreadContext */
323 Thread
->StartAddress
= (PVOID
)KeGetContextPc(ThreadContext
);
324 Thread
->Win32StartAddress
= (PVOID
)KeGetContextReturnRegister(ThreadContext
);
326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
328 Status
= _SEH2_GetExceptionCode();
332 /* Let the kernel intialize the Thread */
333 if (NT_SUCCESS(Status
))
335 Status
= KeInitThread(&Thread
->Tcb
,
337 PspUserThreadStartup
,
339 Thread
->StartAddress
,
348 Thread
->StartAddress
= StartRoutine
;
349 PspSetCrossThreadFlag(Thread
, CT_SYSTEM_THREAD_BIT
);
351 /* Let the kernel intialize the Thread */
352 Status
= KeInitThread(&Thread
->Tcb
,
354 PspSystemThreadStartup
,
362 /* Check if we failed */
363 if (!NT_SUCCESS(Status
))
365 /* Delete the TEB if we had done */
366 if (TebBase
) MmDeleteTeb(Process
, TebBase
);
368 /* Release rundown and dereference */
369 ExReleaseRundownProtection(&Process
->RundownProtect
);
370 ObDereferenceObject(Thread
);
374 /* Lock the process */
375 KeEnterCriticalRegion();
376 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
378 /* Make sure the proces didn't just die on us */
379 if (Process
->ProcessDelete
) goto Quickie
;
381 /* Check if the thread was ours, terminated and it was user mode */
382 if ((Thread
->Terminated
) &&
384 (Thread
->ThreadsProcess
== Process
))
386 /* Cleanup, we don't want to start it up and context switch */
391 * Insert the Thread into the Process's Thread List
392 * Note, this is the ETHREAD Thread List. It is removed in
393 * ps/kill.c!PspExitThread.
395 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
396 Process
->ActiveThreads
++;
398 /* Start the thread */
399 KeStartThread(&Thread
->Tcb
);
401 /* Release the process lock */
402 ExReleasePushLockExclusive(&Process
->ProcessLock
);
403 KeLeaveCriticalRegion();
405 /* Release rundown */
406 ExReleaseRundownProtection(&Process
->RundownProtect
);
409 //WmiTraceProcess(Process, TRUE);
410 //WmiTraceThread(Thread, InitialTeb, TRUE);
412 /* Notify Thread Creation */
413 PspRunCreateThreadNotifyRoutines(Thread
, TRUE
);
415 /* Reference ourselves as a keep-alive */
416 ObReferenceObjectEx(Thread
, 2);
418 /* Suspend the Thread if we have to */
419 if (CreateSuspended
) KeSuspendThread(&Thread
->Tcb
);
421 /* Check if we were already terminated */
422 if (Thread
->Terminated
) KeForceResumeThread(&Thread
->Tcb
);
424 /* Create an access state */
425 Status
= SeCreateAccessStateEx(NULL
,
427 PsGetCurrentProcess() : Process
,
431 &PsThreadType
->TypeInfo
.GenericMapping
);
432 if (!NT_SUCCESS(Status
))
434 /* Access state failed, thread is dead */
435 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
437 /* If we were suspended, wake it up */
438 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
440 /* Dispatch thread */
441 KeReadyThread(&Thread
->Tcb
);
443 /* Dereference completely to kill it */
444 ObDereferenceObjectEx(Thread
, 2);
448 /* Insert the Thread into the Object Manager */
449 Status
= ObInsertObject(Thread
,
456 /* Delete the access state if we had one */
457 if (AccessState
) SeDeleteAccessState(AccessState
);
459 /* Check for success */
460 if (NT_SUCCESS(Status
))
462 /* Wrap in SEH to protect against bad user-mode pointers */
465 /* Return Cid and Handle */
466 if (ClientId
) *ClientId
= Thread
->Cid
;
467 *ThreadHandle
= hThread
;
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
471 /* Thread insertion failed, thread is dead */
472 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
474 /* If we were suspended, wake it up */
475 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
477 /* Dispatch thread */
478 KeReadyThread(&Thread
->Tcb
);
480 /* Dereference it, leaving only the keep-alive */
481 ObDereferenceObject(Thread
);
483 /* Close its handle, killing it */
484 ObCloseHandle(hThread
, PreviousMode
);
486 /* Return the exception code */
487 _SEH2_YIELD(return _SEH2_GetExceptionCode());
493 /* Thread insertion failed, thread is dead */
494 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
496 /* If we were suspended, wake it up */
497 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
500 /* Get the create time */
501 KeQuerySystemTime(&Thread
->CreateTime
);
502 ASSERT(!(Thread
->CreateTime
.HighPart
& 0xF0000000));
504 /* Make sure the thread isn't dead */
505 if (!Thread
->DeadThread
)
507 /* Get the thread's SD */
508 Status
= ObGetObjectSecurity(Thread
,
511 if (!NT_SUCCESS(Status
))
513 /* Thread insertion failed, thread is dead */
514 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
516 /* If we were suspended, wake it up */
517 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
519 /* Dispatch thread */
520 KeReadyThread(&Thread
->Tcb
);
522 /* Dereference it, leaving only the keep-alive */
523 ObDereferenceObject(Thread
);
525 /* Close its handle, killing it */
526 ObCloseHandle(hThread
, PreviousMode
);
530 /* Create the subject context */
531 SubjectContext
.ProcessAuditId
= Process
;
532 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
533 SubjectContext
.ClientToken
= NULL
;
535 /* Do the access check */
536 Result
= SeAccessCheck(SecurityDescriptor
,
542 &PsThreadType
->TypeInfo
.GenericMapping
,
544 &Thread
->GrantedAccess
,
547 /* Dereference the token and let go the SD */
548 ObFastDereferenceObject(&Process
->Token
,
549 SubjectContext
.PrimaryToken
);
550 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
552 /* Remove access if it failed */
553 if (!Result
) Process
->GrantedAccess
= 0;
555 /* Set least some minimum access */
556 Thread
->GrantedAccess
|= (THREAD_TERMINATE
|
557 THREAD_SET_INFORMATION
|
558 THREAD_QUERY_INFORMATION
);
562 /* Set the thread access mask to maximum */
563 Thread
->GrantedAccess
= THREAD_ALL_ACCESS
;
566 /* Dispatch thread */
567 KeReadyThread(&Thread
->Tcb
);
569 /* Dereference it, leaving only the keep-alive */
570 ObDereferenceObject(Thread
);
575 /* Most annoying failure case ever, where we undo almost all manually */
577 /* When we get here, the process is locked, unlock it */
578 ExReleasePushLockExclusive(&Process
->ProcessLock
);
579 KeLeaveCriticalRegion();
581 /* Uninitailize it */
582 KeUninitThread(&Thread
->Tcb
);
584 /* If we had a TEB, delete it */
585 if (TebBase
) MmDeleteTeb(Process
, TebBase
);
587 /* Release rundown protection, which we also hold */
588 ExReleaseRundownProtection(&Process
->RundownProtect
);
590 /* Dereference the thread and return failure */
591 ObDereferenceObject(Thread
);
592 return STATUS_PROCESS_IS_TERMINATING
;
595 /* PUBLIC FUNCTIONS **********************************************************/
602 PsCreateSystemThread(OUT PHANDLE ThreadHandle
,
603 IN ACCESS_MASK DesiredAccess
,
604 IN POBJECT_ATTRIBUTES ObjectAttributes
,
605 IN HANDLE ProcessHandle
,
606 IN PCLIENT_ID ClientId
,
607 IN PKSTART_ROUTINE StartRoutine
,
608 IN PVOID StartContext
)
610 PEPROCESS TargetProcess
= NULL
;
611 HANDLE Handle
= ProcessHandle
;
613 PSTRACE(PS_THREAD_DEBUG
,
614 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
615 ProcessHandle
, StartRoutine
, StartContext
);
617 /* Check if we have a handle. If not, use the System Process */
621 TargetProcess
= PsInitialSystemProcess
;
624 /* Call the shared function */
625 return PspCreateThread(ThreadHandle
,
643 PsLookupThreadByThreadId(IN HANDLE ThreadId
,
644 OUT PETHREAD
*Thread
)
646 PHANDLE_TABLE_ENTRY CidEntry
;
647 PETHREAD FoundThread
;
648 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
650 PSTRACE(PS_THREAD_DEBUG
, "ThreadId: %p\n", ThreadId
);
651 KeEnterCriticalRegion();
653 /* Get the CID Handle Entry */
654 CidEntry
= ExMapHandleToPointer(PspCidTable
, ThreadId
);
657 /* Get the Process */
658 FoundThread
= CidEntry
->Object
;
660 /* Make sure it's really a process */
661 if (FoundThread
->Tcb
.Header
.Type
== ThreadObject
)
663 /* Safe Reference and return it */
664 if (ObReferenceObjectSafe(FoundThread
))
666 *Thread
= FoundThread
;
667 Status
= STATUS_SUCCESS
;
671 /* Unlock the Entry */
672 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
675 /* Return to caller */
676 KeLeaveCriticalRegion();
685 PsGetThreadFreezeCount(IN PETHREAD Thread
)
687 return Thread
->Tcb
.FreezeCount
;
695 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread
)
697 return Thread
->HardErrorsAreDisabled
? TRUE
: FALSE
;
705 PsGetThreadId(IN PETHREAD Thread
)
707 return Thread
->Cid
.UniqueThread
;
715 PsGetCurrentThreadId(VOID
)
717 return PsGetCurrentThread()->Cid
.UniqueThread
;
725 PsGetThreadProcess(IN PETHREAD Thread
)
727 return Thread
->ThreadsProcess
;
735 PsGetCurrentThreadProcess(VOID
)
737 return PsGetCurrentThread()->ThreadsProcess
;
745 PsGetThreadProcessId(IN PETHREAD Thread
)
747 return Thread
->Cid
.UniqueProcess
;
755 PsGetCurrentThreadProcessId(VOID
)
757 return PsGetCurrentThread()->Cid
.UniqueProcess
;
765 PsGetThreadSessionId(IN PETHREAD Thread
)
767 return MmGetSessionId(Thread
->ThreadsProcess
);
775 PsGetThreadTeb(IN PETHREAD Thread
)
777 return Thread
->Tcb
.Teb
;
785 PsGetCurrentThreadTeb(VOID
)
787 return PsGetCurrentThread()->Tcb
.Teb
;
795 PsGetThreadWin32Thread(IN PETHREAD Thread
)
797 return Thread
->Tcb
.Win32Thread
;
805 PsGetCurrentThreadWin32Thread(VOID
)
807 return PsGetCurrentThread()->Tcb
.Win32Thread
;
815 PsGetCurrentThreadWin32ThreadAndEnterCriticalRegion(
816 _Out_ HANDLE
* OutProcessId
)
818 PETHREAD CurrentThread
;
820 /* Get the current thread */
821 CurrentThread
= PsGetCurrentThread();
823 /* Return the process id */
824 *OutProcessId
= CurrentThread
->Cid
.UniqueProcess
;
826 /* Enter critical region */
827 KeEnterCriticalRegion();
829 /* Return the win32 thread */
830 return CurrentThread
->Tcb
.Win32Thread
;
838 PsGetCurrentThreadPreviousMode(VOID
)
840 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
848 PsGetCurrentThreadStackBase(VOID
)
850 return PsGetCurrentThread()->Tcb
.StackBase
;
858 PsGetCurrentThreadStackLimit(VOID
)
860 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
868 PsIsThreadTerminating(IN PETHREAD Thread
)
870 return Thread
->Terminated
? TRUE
: FALSE
;
878 PsIsSystemThread(IN PETHREAD Thread
)
880 return Thread
->SystemThread
? TRUE
: FALSE
;
888 PsIsThreadImpersonating(IN PETHREAD Thread
)
890 return Thread
->ActiveImpersonationInfo
? TRUE
: FALSE
;
898 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread
,
899 IN BOOLEAN HardErrorsAreDisabled
)
901 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
909 PsSetThreadWin32Thread(
910 _Inout_ PETHREAD Thread
,
911 _In_ PVOID Win32Thread
,
912 _In_ PVOID OldWin32Thread
)
914 /* Are we setting the win32 process? */
915 if (Win32Thread
!= NULL
)
917 /* Just exchange it */
918 return InterlockedExchangePointer(&Thread
->Tcb
.Win32Thread
,
923 /* We are resetting, only exchange when the old win32 thread matches */
924 return InterlockedCompareExchangePointer(&Thread
->Tcb
.Win32Thread
,
932 PsWrapApcWow64Thread(IN OUT PVOID
*ApcContext
,
933 IN OUT PVOID
*ApcRoutine
)
936 return STATUS_NOT_IMPLEMENTED
;
941 NtCreateThread(OUT PHANDLE ThreadHandle
,
942 IN ACCESS_MASK DesiredAccess
,
943 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
944 IN HANDLE ProcessHandle
,
945 OUT PCLIENT_ID ClientId
,
946 IN PCONTEXT ThreadContext
,
947 IN PINITIAL_TEB InitialTeb
,
948 IN BOOLEAN CreateSuspended
)
950 INITIAL_TEB SafeInitialTeb
;
952 PSTRACE(PS_THREAD_DEBUG
,
953 "ProcessHandle: %p Context: %p\n", ProcessHandle
, ThreadContext
);
955 /* Check if this was from user-mode */
956 if (KeGetPreviousMode() != KernelMode
)
958 /* Make sure that we got a context */
959 if (!ThreadContext
) return STATUS_INVALID_PARAMETER
;
964 /* Make sure the handle pointer we got is valid */
965 ProbeForWriteHandle(ThreadHandle
);
967 /* Check if the caller wants a client id */
970 /* Make sure we can write to it */
971 ProbeForWrite(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
974 /* Make sure that the entire context is readable */
975 ProbeForRead(ThreadContext
, sizeof(CONTEXT
), sizeof(ULONG
));
977 /* Check the Initial TEB */
978 ProbeForRead(InitialTeb
, sizeof(INITIAL_TEB
), sizeof(ULONG
));
979 SafeInitialTeb
= *InitialTeb
;
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
983 /* Return the exception code */
984 _SEH2_YIELD(return _SEH2_GetExceptionCode());
990 /* Use the Initial TEB as is */
991 SafeInitialTeb
= *InitialTeb
;
994 /* Call the shared function */
995 return PspCreateThread(ThreadHandle
,
1013 NtOpenThread(OUT PHANDLE ThreadHandle
,
1014 IN ACCESS_MASK DesiredAccess
,
1015 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1016 IN PCLIENT_ID ClientId OPTIONAL
)
1018 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
1019 CLIENT_ID SafeClientId
;
1020 ULONG Attributes
= 0;
1021 HANDLE hThread
= NULL
;
1024 BOOLEAN HasObjectName
= FALSE
;
1025 ACCESS_STATE AccessState
;
1026 AUX_ACCESS_DATA AuxData
;
1028 PSTRACE(PS_THREAD_DEBUG
,
1029 "ClientId: %p ObjectAttributes: %p\n", ClientId
, ObjectAttributes
);
1031 /* Check if we were called from user mode */
1032 if (PreviousMode
!= KernelMode
)
1034 /* Enter SEH for probing */
1037 /* Probe the thread handle */
1038 ProbeForWriteHandle(ThreadHandle
);
1040 /* Check for a CID structure */
1043 /* Probe and capture it */
1044 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
1045 SafeClientId
= *ClientId
;
1046 ClientId
= &SafeClientId
;
1050 * Just probe the object attributes structure, don't capture it
1051 * completely. This is done later if necessary
1053 ProbeForRead(ObjectAttributes
,
1054 sizeof(OBJECT_ATTRIBUTES
),
1056 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1057 Attributes
= ObjectAttributes
->Attributes
;
1059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1061 /* Return the exception code */
1062 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1068 /* Otherwise just get the data directly */
1069 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1070 Attributes
= ObjectAttributes
->Attributes
;
1073 /* Can't pass both, fail */
1074 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1076 /* Create an access state */
1077 Status
= SeCreateAccessState(&AccessState
,
1080 &PsProcessType
->TypeInfo
.GenericMapping
);
1081 if (!NT_SUCCESS(Status
)) return Status
;
1083 /* Check if this is a debugger */
1084 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1086 /* Did he want full access? */
1087 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1089 /* Give it to him */
1090 AccessState
.PreviouslyGrantedAccess
|= THREAD_ALL_ACCESS
;
1094 /* Otherwise just give every other access he could want */
1095 AccessState
.PreviouslyGrantedAccess
|=
1096 AccessState
.RemainingDesiredAccess
;
1099 /* The caller desires nothing else now */
1100 AccessState
.RemainingDesiredAccess
= 0;
1103 /* Open by name if one was given */
1107 Status
= ObOpenObjectByName(ObjectAttributes
,
1115 /* Get rid of the access state */
1116 SeDeleteAccessState(&AccessState
);
1120 /* Open by Thread ID */
1121 if (ClientId
->UniqueProcess
)
1123 /* Get the Process */
1124 Status
= PsLookupProcessThreadByCid(ClientId
, NULL
, &Thread
);
1128 /* Get the Process */
1129 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
, &Thread
);
1132 /* Check if we didn't find anything */
1133 if (!NT_SUCCESS(Status
))
1135 /* Get rid of the access state and return */
1136 SeDeleteAccessState(&AccessState
);
1140 /* Open the Thread Object */
1141 Status
= ObOpenObjectByPointer(Thread
,
1149 /* Delete the access state and dereference the thread */
1150 SeDeleteAccessState(&AccessState
);
1151 ObDereferenceObject(Thread
);
1155 /* Neither an object name nor a client id was passed */
1156 return STATUS_INVALID_PARAMETER_MIX
;
1159 /* Check for success */
1160 if (NT_SUCCESS(Status
))
1162 /* Protect against bad user-mode pointers */
1165 /* Write back the handle */
1166 *ThreadHandle
= hThread
;
1168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1170 /* Get the exception code */
1171 Status
= _SEH2_GetExceptionCode();