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(NULL
,
76 (PVOID
)((ULONG_PTR
)Thread
->Tcb
.InitialStack
-
79 PspSystemDllEntryPoint
,
84 /* Lower it back to passive */
85 KeLowerIrql(PASSIVE_LEVEL
);
89 /* We're dead, kill us now */
90 PspTerminateThreadByPointer(Thread
,
91 STATUS_THREAD_IS_TERMINATING
,
95 /* Do we have a cookie set yet? */
96 if (!SharedUserData
->Cookie
)
98 LARGE_INTEGER SystemTime
;
102 /* Generate a new cookie */
103 KeQuerySystemTime(&SystemTime
);
104 Prcb
= KeGetCurrentPrcb();
105 NewCookie
= Prcb
->MmPageFaultCount
^ Prcb
->InterruptTime
^
106 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
^
107 (ULONG_PTR
)&SystemTime
;
109 /* Set the new cookie*/
110 InterlockedCompareExchange((LONG
*)&SharedUserData
->Cookie
,
117 PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers
)
119 /* Print debugging information */
120 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
122 DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
123 ExceptionPointers
->ExceptionRecord
->ExceptionCode
,
124 ExceptionPointers
->ExceptionRecord
->ExceptionAddress
,
125 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[0],
126 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[1],
127 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[2],
128 ExceptionPointers
->ExceptionRecord
->ExceptionInformation
[3]);
130 /* Bugcheck the system */
131 KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
,
132 ExceptionPointers
->ExceptionRecord
->ExceptionCode
,
133 (ULONG_PTR
)ExceptionPointers
->ExceptionRecord
->ExceptionAddress
,
134 (ULONG_PTR
)ExceptionPointers
->ExceptionRecord
,
135 (ULONG_PTR
)ExceptionPointers
->ContextRecord
);
141 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine
,
142 IN PVOID StartContext
)
145 PSTRACE(PS_THREAD_DEBUG
,
146 "StartRoutine: %p StartContext: %p\n", StartRoutine
, StartContext
);
148 /* Unlock the dispatcher Database */
149 KeLowerIrql(PASSIVE_LEVEL
);
150 Thread
= PsGetCurrentThread();
152 /* Make sure the thread isn't gone */
155 if (!(Thread
->Terminated
) && !(Thread
->DeadThread
))
157 /* Call the Start Routine */
158 StartRoutine(StartContext
);
161 _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation()))
163 /* Bugcheck if we got here */
164 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED
);
168 /* Exit the thread */
169 PspTerminateThreadByPointer(Thread
, STATUS_SUCCESS
, TRUE
);
174 PspCreateThread(OUT PHANDLE ThreadHandle
,
175 IN ACCESS_MASK DesiredAccess
,
176 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
177 IN HANDLE ProcessHandle
,
178 IN PEPROCESS TargetProcess
,
179 OUT PCLIENT_ID ClientId
,
180 IN PCONTEXT ThreadContext
,
181 IN PINITIAL_TEB InitialTeb
,
182 IN BOOLEAN CreateSuspended
,
183 IN PKSTART_ROUTINE StartRoutine OPTIONAL
,
184 IN PVOID StartContext OPTIONAL
)
190 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
191 NTSTATUS Status
, AccessStatus
;
192 HANDLE_TABLE_ENTRY CidEntry
;
193 ACCESS_STATE LocalAccessState
;
194 PACCESS_STATE AccessState
= &LocalAccessState
;
195 AUX_ACCESS_DATA AuxData
;
196 BOOLEAN Result
, SdAllocated
;
197 PSECURITY_DESCRIPTOR SecurityDescriptor
;
198 SECURITY_SUBJECT_CONTEXT SubjectContext
;
200 PSTRACE(PS_THREAD_DEBUG
,
201 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
202 ThreadContext
, TargetProcess
, ProcessHandle
);
204 /* If we were called from PsCreateSystemThread, then we're kernel mode */
205 if (StartRoutine
) PreviousMode
= KernelMode
;
207 /* Reference the Process by handle or pointer, depending on what we got */
210 /* Normal thread or System Thread */
211 Status
= ObReferenceObjectByHandle(ProcessHandle
,
212 PROCESS_CREATE_THREAD
,
221 /* System thread inside System Process, or Normal Thread with a bug */
224 /* Reference the Process by Pointer */
225 ObReferenceObject(TargetProcess
);
226 Process
= TargetProcess
;
227 Status
= STATUS_SUCCESS
;
231 /* Fake ObReference returning this */
232 Status
= STATUS_INVALID_HANDLE
;
236 /* Check for success */
237 if (!NT_SUCCESS(Status
)) return Status
;
239 /* Also make sure that User-Mode isn't trying to create a system thread */
240 if ((PreviousMode
!= KernelMode
) && (Process
== PsInitialSystemProcess
))
243 ObDereferenceObject(Process
);
244 return STATUS_INVALID_HANDLE
;
247 /* Create Thread Object */
248 Status
= ObCreateObject(PreviousMode
,
257 if (!NT_SUCCESS(Status
))
259 /* We failed; dereference the process and exit */
260 ObDereferenceObject(Process
);
264 /* Zero the Object entirely */
265 RtlZeroMemory(Thread
, sizeof(ETHREAD
));
267 /* Initialize rundown protection */
268 ExInitializeRundownProtection(&Thread
->RundownProtect
);
270 /* Initialize exit code */
271 Thread
->ExitStatus
= STATUS_PENDING
;
273 /* Set the Process CID */
274 Thread
->ThreadsProcess
= Process
;
275 Thread
->Cid
.UniqueProcess
= Process
->UniqueProcessId
;
277 /* Create Cid Handle */
278 CidEntry
.Object
= Thread
;
279 CidEntry
.GrantedAccess
= 0;
280 Thread
->Cid
.UniqueThread
= ExCreateHandle(PspCidTable
, &CidEntry
);
281 if (!Thread
->Cid
.UniqueThread
)
283 /* We couldn't create the CID, dereference the thread and fail */
284 ObDereferenceObject(Thread
);
285 return STATUS_INSUFFICIENT_RESOURCES
;
288 /* Save the read cluster size */
289 Thread
->ReadClusterSize
= MmReadClusterSize
;
291 /* Initialize the LPC Reply Semaphore */
292 KeInitializeSemaphore(&Thread
->LpcReplySemaphore
, 0, 1);
294 /* Initialize the list heads and locks */
295 InitializeListHead(&Thread
->LpcReplyChain
);
296 InitializeListHead(&Thread
->IrpList
);
297 InitializeListHead(&Thread
->PostBlockList
);
298 InitializeListHead(&Thread
->ActiveTimerListHead
);
299 KeInitializeSpinLock(&Thread
->ActiveTimerListLock
);
301 /* Acquire rundown protection */
302 if (!ExAcquireRundownProtection (&Process
->RundownProtect
))
305 ObDereferenceObject(Thread
);
306 return STATUS_PROCESS_IS_TERMINATING
;
309 /* Now let the kernel initialize the context */
312 /* User-mode Thread, create Teb */
313 TebBase
= MmCreateTeb(Process
, &Thread
->Cid
, InitialTeb
);
316 /* Failed to create the TEB. Release rundown and dereference */
317 ExReleaseRundownProtection(&Process
->RundownProtect
);
318 ObDereferenceObject(Thread
);
319 return STATUS_INSUFFICIENT_RESOURCES
;
322 /* Set the Start Addresses */
324 Thread
->StartAddress
= (PVOID
)ThreadContext
->Eip
;
325 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->Eax
;
326 #elif defined(_M_PPC)
327 Thread
->StartAddress
= (PVOID
)ThreadContext
->Dr0
;
328 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->Gpr3
;
329 #elif defined(_M_MIPS)
330 Thread
->StartAddress
= (PVOID
)ThreadContext
->Psr
;
331 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->IntA0
;
332 #elif defined(_M_ARM)
333 Thread
->StartAddress
= (PVOID
)ThreadContext
->Pc
;
334 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->R0
;
335 #elif defined(_M_AMD64)
336 Thread
->StartAddress
= (PVOID
)ThreadContext
->Rip
;
337 Thread
->Win32StartAddress
= (PVOID
)ThreadContext
->Rax
;
339 #error Unknown architecture
342 /* Let the kernel intialize the Thread */
343 Status
= KeInitThread(&Thread
->Tcb
,
345 PspUserThreadStartup
,
347 Thread
->StartAddress
,
355 Thread
->StartAddress
= StartRoutine
;
356 PspSetCrossThreadFlag(Thread
, CT_SYSTEM_THREAD_BIT
);
358 /* Let the kernel intialize the Thread */
359 Status
= KeInitThread(&Thread
->Tcb
,
361 PspSystemThreadStartup
,
369 /* Check if we failed */
370 if (!NT_SUCCESS(Status
))
372 /* Delete the TEB if we had done */
373 if (TebBase
) MmDeleteTeb(Process
, TebBase
);
375 /* Release rundown and dereference */
376 ExReleaseRundownProtection(&Process
->RundownProtect
);
377 ObDereferenceObject(Thread
);
381 /* Lock the process */
382 KeEnterCriticalRegion();
383 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
385 /* Make sure the proces didn't just die on us */
386 if (Process
->ProcessDelete
) goto Quickie
;
388 /* Check if the thread was ours, terminated and it was user mode */
389 if ((Thread
->Terminated
) &&
391 (Thread
->ThreadsProcess
== Process
))
393 /* Cleanup, we don't want to start it up and context switch */
398 * Insert the Thread into the Process's Thread List
399 * Note, this is the ETHREAD Thread List. It is removed in
400 * ps/kill.c!PspExitThread.
402 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
403 Process
->ActiveThreads
++;
405 /* Start the thread */
406 KeStartThread(&Thread
->Tcb
);
408 /* Release the process lock */
409 ExReleasePushLockExclusive(&Process
->ProcessLock
);
410 KeLeaveCriticalRegion();
412 /* Release rundown */
413 ExReleaseRundownProtection(&Process
->RundownProtect
);
416 //WmiTraceProcess(Process, TRUE);
417 //WmiTraceThread(Thread, InitialTeb, TRUE);
419 /* Notify Thread Creation */
420 PspRunCreateThreadNotifyRoutines(Thread
, TRUE
);
422 /* Reference ourselves as a keep-alive */
423 ObReferenceObjectEx(Thread
, 2);
425 /* Suspend the Thread if we have to */
426 if (CreateSuspended
) KeSuspendThread(&Thread
->Tcb
);
428 /* Check if we were already terminated */
429 if (Thread
->Terminated
) KeForceResumeThread(&Thread
->Tcb
);
431 /* Create an access state */
432 Status
= SeCreateAccessStateEx(NULL
,
434 PsGetCurrentProcess() : Process
,
438 &PsThreadType
->TypeInfo
.GenericMapping
);
439 if (!NT_SUCCESS(Status
))
441 /* Access state failed, thread is dead */
442 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
444 /* If we were suspended, wake it up */
445 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
447 /* Dispatch thread */
448 KeReadyThread(&Thread
->Tcb
);
450 /* Dereference completely to kill it */
451 ObDereferenceObjectEx(Thread
, 2);
455 /* Insert the Thread into the Object Manager */
456 Status
= ObInsertObject(Thread
,
463 /* Delete the access state if we had one */
464 if (AccessState
) SeDeleteAccessState(AccessState
);
466 /* Check for success */
467 if (NT_SUCCESS(Status
))
469 /* Wrap in SEH to protect against bad user-mode pointers */
472 /* Return Cid and Handle */
473 if (ClientId
) *ClientId
= Thread
->Cid
;
474 *ThreadHandle
= hThread
;
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
478 /* Thread insertion failed, thread is dead */
479 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
481 /* If we were suspended, wake it up */
482 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
484 /* Dispatch thread */
485 KeReadyThread(&Thread
->Tcb
);
487 /* Dereference it, leaving only the keep-alive */
488 ObDereferenceObject(Thread
);
490 /* Close its handle, killing it */
491 ObCloseHandle(ThreadHandle
, PreviousMode
);
493 /* Return the exception code */
494 _SEH2_YIELD(return _SEH2_GetExceptionCode());
500 /* Thread insertion failed, thread is dead */
501 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
503 /* If we were suspended, wake it up */
504 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
507 /* Get the create time */
508 KeQuerySystemTime(&Thread
->CreateTime
);
509 ASSERT(!(Thread
->CreateTime
.HighPart
& 0xF0000000));
511 /* Make sure the thread isn't dead */
512 if (!Thread
->DeadThread
)
514 /* Get the thread's SD */
515 Status
= ObGetObjectSecurity(Thread
,
518 if (!NT_SUCCESS(Status
))
520 /* Thread insertion failed, thread is dead */
521 PspSetCrossThreadFlag(Thread
, CT_DEAD_THREAD_BIT
);
523 /* If we were suspended, wake it up */
524 if (CreateSuspended
) KeResumeThread(&Thread
->Tcb
);
526 /* Dispatch thread */
527 KeReadyThread(&Thread
->Tcb
);
529 /* Dereference it, leaving only the keep-alive */
530 ObDereferenceObject(Thread
);
532 /* Close its handle, killing it */
533 ObCloseHandle(ThreadHandle
, PreviousMode
);
537 /* Create the subject context */
538 SubjectContext
.ProcessAuditId
= Process
;
539 SubjectContext
.PrimaryToken
= PsReferencePrimaryToken(Process
);
540 SubjectContext
.ClientToken
= NULL
;
542 /* Do the access check */
543 Result
= SeAccessCheck(SecurityDescriptor
,
549 &PsThreadType
->TypeInfo
.GenericMapping
,
551 &Thread
->GrantedAccess
,
554 /* Dereference the token and let go the SD */
555 ObFastDereferenceObject(&Process
->Token
,
556 SubjectContext
.PrimaryToken
);
557 ObReleaseObjectSecurity(SecurityDescriptor
, SdAllocated
);
559 /* Remove access if it failed */
560 if (!Result
) Process
->GrantedAccess
= 0;
562 /* Set least some minimum access */
563 Thread
->GrantedAccess
|= (THREAD_TERMINATE
|
564 THREAD_SET_INFORMATION
|
565 THREAD_QUERY_INFORMATION
);
569 /* Set the thread access mask to maximum */
570 Thread
->GrantedAccess
= THREAD_ALL_ACCESS
;
573 /* Dispatch thread */
574 KeReadyThread(&Thread
->Tcb
);
576 /* Dereference it, leaving only the keep-alive */
577 ObDereferenceObject(Thread
);
582 /* Most annoying failure case ever, where we undo almost all manually */
584 /* When we get here, the process is locked, unlock it */
585 ExReleasePushLockExclusive(&Process
->ProcessLock
);
586 KeLeaveCriticalRegion();
588 /* Uninitailize it */
589 KeUninitThread(&Thread
->Tcb
);
591 /* If we had a TEB, delete it */
592 if (TebBase
) MmDeleteTeb(Process
, TebBase
);
594 /* Release rundown protection, which we also hold */
595 ExReleaseRundownProtection(&Process
->RundownProtect
);
597 /* Dereference the thread and return failure */
598 ObDereferenceObject(Thread
);
599 return STATUS_PROCESS_IS_TERMINATING
;
602 /* PUBLIC FUNCTIONS **********************************************************/
609 PsCreateSystemThread(OUT PHANDLE ThreadHandle
,
610 IN ACCESS_MASK DesiredAccess
,
611 IN POBJECT_ATTRIBUTES ObjectAttributes
,
612 IN HANDLE ProcessHandle
,
613 IN PCLIENT_ID ClientId
,
614 IN PKSTART_ROUTINE StartRoutine
,
615 IN PVOID StartContext
)
617 PEPROCESS TargetProcess
= NULL
;
618 HANDLE Handle
= ProcessHandle
;
620 PSTRACE(PS_THREAD_DEBUG
,
621 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
622 ProcessHandle
, StartRoutine
, StartContext
);
624 /* Check if we have a handle. If not, use the System Process */
628 TargetProcess
= PsInitialSystemProcess
;
631 /* Call the shared function */
632 return PspCreateThread(ThreadHandle
,
650 PsLookupThreadByThreadId(IN HANDLE ThreadId
,
651 OUT PETHREAD
*Thread
)
653 PHANDLE_TABLE_ENTRY CidEntry
;
654 PETHREAD FoundThread
;
655 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
657 PSTRACE(PS_THREAD_DEBUG
, "ThreadId: %p\n", ThreadId
);
658 KeEnterCriticalRegion();
660 /* Get the CID Handle Entry */
661 CidEntry
= ExMapHandleToPointer(PspCidTable
, ThreadId
);
664 /* Get the Process */
665 FoundThread
= CidEntry
->Object
;
667 /* Make sure it's really a process */
668 if (FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
)
670 /* Safe Reference and return it */
671 if (ObReferenceObjectSafe(FoundThread
))
673 *Thread
= FoundThread
;
674 Status
= STATUS_SUCCESS
;
678 /* Unlock the Entry */
679 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
682 /* Return to caller */
683 KeLeaveCriticalRegion();
692 PsGetCurrentThreadId(VOID
)
694 return PsGetCurrentThread()->Cid
.UniqueThread
;
702 PsGetThreadFreezeCount(IN PETHREAD Thread
)
704 return Thread
->Tcb
.FreezeCount
;
712 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread
)
714 return Thread
->HardErrorsAreDisabled
? TRUE
: FALSE
;
722 PsGetThreadId(IN PETHREAD Thread
)
724 return Thread
->Cid
.UniqueThread
;
732 PsGetThreadProcess(IN PETHREAD Thread
)
734 return Thread
->ThreadsProcess
;
742 PsGetThreadProcessId(IN PETHREAD Thread
)
744 return Thread
->Cid
.UniqueProcess
;
752 PsGetThreadSessionId(IN PETHREAD Thread
)
754 return (HANDLE
)Thread
->ThreadsProcess
->Session
;
762 PsGetThreadTeb(IN PETHREAD Thread
)
764 return Thread
->Tcb
.Teb
;
772 PsGetThreadWin32Thread(IN PETHREAD Thread
)
774 return Thread
->Tcb
.Win32Thread
;
782 PsGetCurrentThreadPreviousMode(VOID
)
784 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
792 PsGetCurrentThreadStackBase(VOID
)
794 return PsGetCurrentThread()->Tcb
.StackBase
;
802 PsGetCurrentThreadStackLimit(VOID
)
804 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
812 PsIsThreadTerminating(IN PETHREAD Thread
)
814 return Thread
->Terminated
? TRUE
: FALSE
;
822 PsIsSystemThread(IN PETHREAD Thread
)
824 return Thread
->SystemThread
? TRUE
: FALSE
;
832 PsIsThreadImpersonating(IN PETHREAD Thread
)
834 return Thread
->ActiveImpersonationInfo
? TRUE
: FALSE
;
842 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread
,
843 IN BOOLEAN HardErrorsAreDisabled
)
845 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
853 PsGetCurrentThreadWin32Thread(VOID
)
855 return PsGetCurrentThread()->Tcb
.Win32Thread
;
863 PsSetThreadWin32Thread(IN PETHREAD Thread
,
864 IN PVOID Win32Thread
)
866 Thread
->Tcb
.Win32Thread
= Win32Thread
;
871 NtCreateThread(OUT PHANDLE ThreadHandle
,
872 IN ACCESS_MASK DesiredAccess
,
873 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
874 IN HANDLE ProcessHandle
,
875 OUT PCLIENT_ID ClientId
,
876 IN PCONTEXT ThreadContext
,
877 IN PINITIAL_TEB InitialTeb
,
878 IN BOOLEAN CreateSuspended
)
880 INITIAL_TEB SafeInitialTeb
;
882 PSTRACE(PS_THREAD_DEBUG
,
883 "ProcessHandle: %p Context: %p\n", ProcessHandle
, ThreadContext
);
885 /* Check if this was from user-mode */
886 if (KeGetPreviousMode() != KernelMode
)
888 /* Make sure that we got a context */
889 if (!ThreadContext
) return STATUS_INVALID_PARAMETER
;
894 /* Make sure the handle pointer we got is valid */
895 ProbeForWriteHandle(ThreadHandle
);
897 /* Check if the caller wants a client id */
900 /* Make sure we can write to it */
901 ProbeForWrite(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
904 /* Make sure that the entire context is readable */
905 ProbeForRead(ThreadContext
, sizeof(CONTEXT
), sizeof(ULONG
));
907 /* Check the Initial TEB */
908 ProbeForRead(InitialTeb
, sizeof(INITIAL_TEB
), sizeof(ULONG
));
909 SafeInitialTeb
= *InitialTeb
;
911 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
913 /* Return the exception code */
914 _SEH2_YIELD(return _SEH2_GetExceptionCode());
920 /* Use the Initial TEB as is */
921 SafeInitialTeb
= *InitialTeb
;
924 /* Call the shared function */
925 return PspCreateThread(ThreadHandle
,
943 NtOpenThread(OUT PHANDLE ThreadHandle
,
944 IN ACCESS_MASK DesiredAccess
,
945 IN POBJECT_ATTRIBUTES ObjectAttributes
,
946 IN PCLIENT_ID ClientId OPTIONAL
)
948 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
949 CLIENT_ID SafeClientId
;
950 ULONG Attributes
= 0;
951 HANDLE hThread
= NULL
;
954 BOOLEAN HasObjectName
= FALSE
;
955 ACCESS_STATE AccessState
;
956 AUX_ACCESS_DATA AuxData
;
958 PSTRACE(PS_THREAD_DEBUG
,
959 "ClientId: %p ObjectAttributes: %p\n", ClientId
, ObjectAttributes
);
961 /* Check if we were called from user mode */
962 if (PreviousMode
!= KernelMode
)
964 /* Enter SEH for probing */
967 /* Probe the thread handle */
968 ProbeForWriteHandle(ThreadHandle
);
970 /* Check for a CID structure */
973 /* Probe and capture it */
974 ProbeForRead(ClientId
, sizeof(CLIENT_ID
), sizeof(ULONG
));
975 SafeClientId
= *ClientId
;
976 ClientId
= &SafeClientId
;
980 * Just probe the object attributes structure, don't capture it
981 * completely. This is done later if necessary
983 ProbeForRead(ObjectAttributes
,
984 sizeof(OBJECT_ATTRIBUTES
),
986 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
987 Attributes
= ObjectAttributes
->Attributes
;
989 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
991 /* Return the exception code */
992 _SEH2_YIELD(return _SEH2_GetExceptionCode());
998 /* Otherwise just get the data directly */
999 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
1000 Attributes
= ObjectAttributes
->Attributes
;
1003 /* Can't pass both, fail */
1004 if ((HasObjectName
) && (ClientId
)) return STATUS_INVALID_PARAMETER_MIX
;
1006 /* Create an access state */
1007 Status
= SeCreateAccessState(&AccessState
,
1010 &PsProcessType
->TypeInfo
.GenericMapping
);
1011 if (!NT_SUCCESS(Status
)) return Status
;
1013 /* Check if this is a debugger */
1014 if (SeSinglePrivilegeCheck(SeDebugPrivilege
, PreviousMode
))
1016 /* Did he want full access? */
1017 if (AccessState
.RemainingDesiredAccess
& MAXIMUM_ALLOWED
)
1019 /* Give it to him */
1020 AccessState
.PreviouslyGrantedAccess
|= THREAD_ALL_ACCESS
;
1024 /* Otherwise just give every other access he could want */
1025 AccessState
.PreviouslyGrantedAccess
|=
1026 AccessState
.RemainingDesiredAccess
;
1029 /* The caller desires nothing else now */
1030 AccessState
.RemainingDesiredAccess
= 0;
1033 /* Open by name if one was given */
1037 Status
= ObOpenObjectByName(ObjectAttributes
,
1045 /* Get rid of the access state */
1046 SeDeleteAccessState(&AccessState
);
1050 /* Open by Thread ID */
1051 if (ClientId
->UniqueProcess
)
1053 /* Get the Process */
1054 Status
= PsLookupProcessThreadByCid(ClientId
, NULL
, &Thread
);
1058 /* Get the Process */
1059 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
, &Thread
);
1062 /* Check if we didn't find anything */
1063 if (!NT_SUCCESS(Status
))
1065 /* Get rid of the access state and return */
1066 SeDeleteAccessState(&AccessState
);
1070 /* Open the Thread Object */
1071 Status
= ObOpenObjectByPointer(Thread
,
1079 /* Delete the access state and dereference the thread */
1080 SeDeleteAccessState(&AccessState
);
1081 ObDereferenceObject(Thread
);
1085 /* Neither an object name nor a client id was passed */
1086 return STATUS_INVALID_PARAMETER_MIX
;
1089 /* Check for success */
1090 if (NT_SUCCESS(Status
))
1092 /* Protect against bad user-mode pointers */
1095 /* Write back the handle */
1096 *ThreadHandle
= hThread
;
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 /* Get the exception code */
1101 Status
= _SEH2_GetExceptionCode();