1 /*
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)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 extern BOOLEAN CcPfEnablePrefetcher;
19 extern ULONG MmReadClusterSize;
20 POBJECT_TYPE PsThreadType = NULL;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 VOID
25 NTAPI
PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,IN PVOID StartContext)26 PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
27 IN PVOID StartContext)
28 {
29 PETHREAD Thread;
30 PTEB Teb;
31 BOOLEAN DeadThread = FALSE;
32 KIRQL OldIrql;
33 PAGED_CODE();
34 PSTRACE(PS_THREAD_DEBUG,
35 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
36
37 /* Go to Passive Level */
38 KeLowerIrql(PASSIVE_LEVEL);
39 Thread = PsGetCurrentThread();
40
41 /* Check if the thread is dead */
42 if (Thread->DeadThread)
43 {
44 /* Remember that we're dead */
45 DeadThread = TRUE;
46 }
47 else
48 {
49 /* Get the Locale ID and save Preferred Proc */
50 Teb = NtCurrentTeb();
51 Teb->CurrentLocale = MmGetSessionLocaleId();
52 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
53 }
54
55 /* Check if this is a dead thread, or if we're hiding */
56 if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
57 {
58 /* We're not, so notify the debugger */
59 DbgkCreateThread(Thread, StartContext);
60 }
61
62 /* Make sure we're not already dead */
63 if (!DeadThread)
64 {
65 /* Check if the Prefetcher is enabled */
66 if (CcPfEnablePrefetcher)
67 {
68 /* FIXME: Prepare to prefetch this process */
69 }
70
71 /* Raise to APC */
72 KeRaiseIrql(APC_LEVEL, &OldIrql);
73
74 /* Queue the User APC */
75 KiInitializeUserApc(KeGetExceptionFrame(&Thread->Tcb),
76 KeGetTrapFrame(&Thread->Tcb),
77 PspSystemDllEntryPoint,
78 NULL,
79 PspSystemDllBase,
80 NULL);
81
82 /* Lower it back to passive */
83 KeLowerIrql(PASSIVE_LEVEL);
84 }
85 else
86 {
87 /* We're dead, kill us now */
88 PspTerminateThreadByPointer(Thread,
89 STATUS_THREAD_IS_TERMINATING,
90 TRUE);
91 }
92
93 /* Do we have a cookie set yet? */
94 while (!SharedUserData->Cookie)
95 {
96 LARGE_INTEGER SystemTime;
97 ULONG NewCookie;
98 PKPRCB Prcb;
99
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);
106
107 /* Set the new cookie*/
108 InterlockedCompareExchange((LONG*)&SharedUserData->Cookie,
109 NewCookie,
110 0);
111 }
112 }
113
114 LONG
PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers)115 PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers)
116 {
117 /* Print debugging information */
118 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
119 ExceptionPointers);
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]);
127
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);
134 return 0;
135 }
136
137 VOID
138 NTAPI
PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,IN PVOID StartContext)139 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
140 IN PVOID StartContext)
141 {
142 PETHREAD Thread;
143 PSTRACE(PS_THREAD_DEBUG,
144 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
145
146 /* Unlock the dispatcher Database */
147 KeLowerIrql(PASSIVE_LEVEL);
148 Thread = PsGetCurrentThread();
149
150 /* Make sure the thread isn't gone */
151 _SEH2_TRY
152 {
153 if (!(Thread->Terminated) && !(Thread->DeadThread))
154 {
155 /* Call the Start Routine */
156 StartRoutine(StartContext);
157 }
158 }
159 _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation()))
160 {
161 /* Bugcheck if we got here */
162 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
163 }
164 _SEH2_END;
165
166 /* Exit the thread */
167 PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
168 }
169
170 NTSTATUS
171 NTAPI
PspCreateThread(OUT PHANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN HANDLE ProcessHandle,IN PEPROCESS TargetProcess,OUT PCLIENT_ID ClientId,IN PCONTEXT ThreadContext,IN PINITIAL_TEB InitialTeb,IN BOOLEAN CreateSuspended,IN PKSTART_ROUTINE StartRoutine OPTIONAL,IN PVOID StartContext OPTIONAL)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)
183 {
184 HANDLE hThread;
185 PEPROCESS Process;
186 PETHREAD Thread;
187 PTEB TebBase = NULL;
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;
197 PAGED_CODE();
198 PSTRACE(PS_THREAD_DEBUG,
199 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
200 ThreadContext, TargetProcess, ProcessHandle);
201
202 /* If we were called from PsCreateSystemThread, then we're kernel mode */
203 if (StartRoutine) PreviousMode = KernelMode;
204
205 /* Reference the Process by handle or pointer, depending on what we got */
206 if (ProcessHandle)
207 {
208 /* Normal thread or System Thread */
209 Status = ObReferenceObjectByHandle(ProcessHandle,
210 PROCESS_CREATE_THREAD,
211 PsProcessType,
212 PreviousMode,
213 (PVOID*)&Process,
214 NULL);
215 PSREFTRACE(Process);
216 }
217 else
218 {
219 /* System thread inside System Process, or Normal Thread with a bug */
220 if (StartRoutine)
221 {
222 /* Reference the Process by Pointer */
223 ObReferenceObject(TargetProcess);
224 Process = TargetProcess;
225 Status = STATUS_SUCCESS;
226 }
227 else
228 {
229 /* Fake ObReference returning this */
230 Status = STATUS_INVALID_HANDLE;
231 }
232 }
233
234 /* Check for success */
235 if (!NT_SUCCESS(Status)) return Status;
236
237 /* Also make sure that User-Mode isn't trying to create a system thread */
238 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
239 {
240 /* Fail */
241 ObDereferenceObject(Process);
242 return STATUS_INVALID_HANDLE;
243 }
244
245 /* Create Thread Object */
246 Status = ObCreateObject(PreviousMode,
247 PsThreadType,
248 ObjectAttributes,
249 PreviousMode,
250 NULL,
251 sizeof(ETHREAD),
252 0,
253 0,
254 (PVOID*)&Thread);
255 if (!NT_SUCCESS(Status))
256 {
257 /* We failed; dereference the process and exit */
258 ObDereferenceObject(Process);
259 return Status;
260 }
261
262 /* Zero the Object entirely */
263 RtlZeroMemory(Thread, sizeof(ETHREAD));
264
265 /* Initialize rundown protection */
266 ExInitializeRundownProtection(&Thread->RundownProtect);
267
268 /* Initialize exit code */
269 Thread->ExitStatus = STATUS_PENDING;
270
271 /* Set the Process CID */
272 Thread->ThreadsProcess = Process;
273 Thread->Cid.UniqueProcess = Process->UniqueProcessId;
274
275 /* Create Cid Handle */
276 CidEntry.Object = Thread;
277 CidEntry.GrantedAccess = 0;
278 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
279 if (!Thread->Cid.UniqueThread)
280 {
281 /* We couldn't create the CID, dereference the thread and fail */
282 ObDereferenceObject(Thread);
283 return STATUS_INSUFFICIENT_RESOURCES;
284 }
285
286 /* Save the read cluster size */
287 Thread->ReadClusterSize = MmReadClusterSize;
288
289 /* Initialize the LPC Reply Semaphore */
290 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
291
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);
298
299 /* Acquire rundown protection */
300 if (!ExAcquireRundownProtection (&Process->RundownProtect))
301 {
302 /* Fail */
303 ObDereferenceObject(Thread);
304 return STATUS_PROCESS_IS_TERMINATING;
305 }
306
307 /* Now let the kernel initialize the context */
308 if (ThreadContext)
309 {
310 /* User-mode Thread, create Teb */
311 Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase);
312 if (!NT_SUCCESS(Status))
313 {
314 /* Failed to create the TEB. Release rundown and dereference */
315 ExReleaseRundownProtection(&Process->RundownProtect);
316 ObDereferenceObject(Thread);
317 return Status;
318 }
319
320 /* Set the Start Addresses from the untrusted ThreadContext */
321 _SEH2_TRY
322 {
323 Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
324 Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);
325 }
326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
327 {
328 Status = _SEH2_GetExceptionCode();
329 }
330 _SEH2_END;
331
332 /* Let the kernel intialize the Thread */
333 if (NT_SUCCESS(Status))
334 {
335 Status = KeInitThread(&Thread->Tcb,
336 NULL,
337 PspUserThreadStartup,
338 NULL,
339 Thread->StartAddress,
340 ThreadContext,
341 TebBase,
342 &Process->Pcb);
343 }
344 }
345 else
346 {
347 /* System Thread */
348 Thread->StartAddress = StartRoutine;
349 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
350
351 /* Let the kernel intialize the Thread */
352 Status = KeInitThread(&Thread->Tcb,
353 NULL,
354 PspSystemThreadStartup,
355 StartRoutine,
356 StartContext,
357 NULL,
358 NULL,
359 &Process->Pcb);
360 }
361
362 /* Check if we failed */
363 if (!NT_SUCCESS(Status))
364 {
365 /* Delete the TEB if we had done */
366 if (TebBase) MmDeleteTeb(Process, TebBase);
367
368 /* Release rundown and dereference */
369 ExReleaseRundownProtection(&Process->RundownProtect);
370 ObDereferenceObject(Thread);
371 return Status;
372 }
373
374 /* Lock the process */
375 KeEnterCriticalRegion();
376 ExAcquirePushLockExclusive(&Process->ProcessLock);
377
378 /* Make sure the process didn't just die on us */
379 if (Process->ProcessDelete) goto Quickie;
380
381 /* Check if the thread was ours, terminated and it was user mode */
382 if ((Thread->Terminated) &&
383 (ThreadContext) &&
384 (Thread->ThreadsProcess == Process))
385 {
386 /* Cleanup, we don't want to start it up and context switch */
387 goto Quickie;
388 }
389
390 /*
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.
394 */
395 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
396 Process->ActiveThreads++;
397
398 /* Start the thread */
399 KeStartThread(&Thread->Tcb);
400
401 /* Release the process lock */
402 ExReleasePushLockExclusive(&Process->ProcessLock);
403 KeLeaveCriticalRegion();
404
405 /* Release rundown */
406 ExReleaseRundownProtection(&Process->RundownProtect);
407
408 /* Notify WMI */
409 //WmiTraceProcess(Process, TRUE);
410 //WmiTraceThread(Thread, InitialTeb, TRUE);
411
412 /* Notify Thread Creation */
413 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
414
415 /* Reference ourselves as a keep-alive */
416 ObReferenceObjectEx(Thread, 2);
417
418 /* Suspend the Thread if we have to */
419 if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
420
421 /* Check if we were already terminated */
422 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
423
424 /* Create an access state */
425 Status = SeCreateAccessStateEx(NULL,
426 ThreadContext ?
427 PsGetCurrentProcess() : Process,
428 &LocalAccessState,
429 &AuxData,
430 DesiredAccess,
431 &PsThreadType->TypeInfo.GenericMapping);
432 if (!NT_SUCCESS(Status))
433 {
434 /* Access state failed, thread is dead */
435 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
436
437 /* If we were suspended, wake it up */
438 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
439
440 /* Dispatch thread */
441 KeReadyThread(&Thread->Tcb);
442
443 /* Dereference completely to kill it */
444 ObDereferenceObjectEx(Thread, 2);
445 return Status;
446 }
447
448 /* Insert the Thread into the Object Manager */
449 Status = ObInsertObject(Thread,
450 AccessState,
451 DesiredAccess,
452 0,
453 NULL,
454 &hThread);
455
456 /* Delete the access state if we had one */
457 if (AccessState) SeDeleteAccessState(AccessState);
458
459 /* Check for success */
460 if (NT_SUCCESS(Status))
461 {
462 /* Wrap in SEH to protect against bad user-mode pointers */
463 _SEH2_TRY
464 {
465 /* Return Cid and Handle */
466 if (ClientId) *ClientId = Thread->Cid;
467 *ThreadHandle = hThread;
468 }
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
470 {
471 /* Thread insertion failed, thread is dead */
472 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
473
474 /* If we were suspended, wake it up */
475 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
476
477 /* Dispatch thread */
478 KeReadyThread(&Thread->Tcb);
479
480 /* Dereference it, leaving only the keep-alive */
481 ObDereferenceObject(Thread);
482
483 /* Close its handle, killing it */
484 ObCloseHandle(hThread, PreviousMode);
485
486 /* Return the exception code */
487 _SEH2_YIELD(return _SEH2_GetExceptionCode());
488 }
489 _SEH2_END;
490 }
491 else
492 {
493 /* Thread insertion failed, thread is dead */
494 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
495
496 /* If we were suspended, wake it up */
497 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
498 }
499
500 /* Get the create time */
501 KeQuerySystemTime(&Thread->CreateTime);
502 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
503
504 /* Make sure the thread isn't dead */
505 if (!Thread->DeadThread)
506 {
507 /* Get the thread's SD */
508 Status = ObGetObjectSecurity(Thread,
509 &SecurityDescriptor,
510 &SdAllocated);
511 if (!NT_SUCCESS(Status))
512 {
513 /* Thread insertion failed, thread is dead */
514 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
515
516 /* If we were suspended, wake it up */
517 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
518
519 /* Dispatch thread */
520 KeReadyThread(&Thread->Tcb);
521
522 /* Dereference it, leaving only the keep-alive */
523 ObDereferenceObject(Thread);
524
525 /* Close its handle, killing it */
526 ObCloseHandle(hThread, PreviousMode);
527 return Status;
528 }
529
530 /* Create the subject context */
531 SubjectContext.ProcessAuditId = Process;
532 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
533 SubjectContext.ClientToken = NULL;
534
535 /* Do the access check */
536 Result = SeAccessCheck(SecurityDescriptor,
537 &SubjectContext,
538 FALSE,
539 MAXIMUM_ALLOWED,
540 0,
541 NULL,
542 &PsThreadType->TypeInfo.GenericMapping,
543 PreviousMode,
544 &Thread->GrantedAccess,
545 &AccessStatus);
546
547 /* Dereference the token and let go the SD */
548 ObFastDereferenceObject(&Process->Token,
549 SubjectContext.PrimaryToken);
550 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
551
552 /* Remove access if it failed */
553 if (!Result) Process->GrantedAccess = 0;
554
555 /* Set least some minimum access */
556 Thread->GrantedAccess |= (THREAD_TERMINATE |
557 THREAD_SET_INFORMATION |
558 THREAD_QUERY_INFORMATION);
559 }
560 else
561 {
562 /* Set the thread access mask to maximum */
563 Thread->GrantedAccess = THREAD_ALL_ACCESS;
564 }
565
566 /* Dispatch thread */
567 KeReadyThread(&Thread->Tcb);
568
569 /* Dereference it, leaving only the keep-alive */
570 ObDereferenceObject(Thread);
571
572 /* Return */
573 return Status;
574
575 /* Most annoying failure case ever, where we undo almost all manually */
576 Quickie:
577 /* When we get here, the process is locked, unlock it */
578 ExReleasePushLockExclusive(&Process->ProcessLock);
579 KeLeaveCriticalRegion();
580
581 /* Uninitailize it */
582 KeUninitThread(&Thread->Tcb);
583
584 /* If we had a TEB, delete it */
585 if (TebBase) MmDeleteTeb(Process, TebBase);
586
587 /* Release rundown protection, which we also hold */
588 ExReleaseRundownProtection(&Process->RundownProtect);
589
590 /* Dereference the thread and return failure */
591 ObDereferenceObject(Thread);
592 return STATUS_PROCESS_IS_TERMINATING;
593 }
594
595 /* PUBLIC FUNCTIONS **********************************************************/
596
597 /*
598 * @implemented
599 */
600 NTSTATUS
601 NTAPI
PsCreateSystemThread(OUT PHANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN HANDLE ProcessHandle,IN PCLIENT_ID ClientId,IN PKSTART_ROUTINE StartRoutine,IN PVOID StartContext)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)
609 {
610 PEPROCESS TargetProcess = NULL;
611 HANDLE Handle = ProcessHandle;
612 PAGED_CODE();
613 PSTRACE(PS_THREAD_DEBUG,
614 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
615 ProcessHandle, StartRoutine, StartContext);
616
617 /* Check if we have a handle. If not, use the System Process */
618 if (!ProcessHandle)
619 {
620 Handle = NULL;
621 TargetProcess = PsInitialSystemProcess;
622 }
623
624 /* Call the shared function */
625 return PspCreateThread(ThreadHandle,
626 DesiredAccess,
627 ObjectAttributes,
628 Handle,
629 TargetProcess,
630 ClientId,
631 NULL,
632 NULL,
633 FALSE,
634 StartRoutine,
635 StartContext);
636 }
637
638 /*
639 * @implemented
640 */
641 NTSTATUS
642 NTAPI
PsLookupThreadByThreadId(IN HANDLE ThreadId,OUT PETHREAD * Thread)643 PsLookupThreadByThreadId(IN HANDLE ThreadId,
644 OUT PETHREAD *Thread)
645 {
646 PHANDLE_TABLE_ENTRY CidEntry;
647 PETHREAD FoundThread;
648 NTSTATUS Status = STATUS_INVALID_PARAMETER;
649 PAGED_CODE();
650 PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
651 KeEnterCriticalRegion();
652
653 /* Get the CID Handle Entry */
654 CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
655 if (CidEntry)
656 {
657 /* Get the Thread */
658 FoundThread = CidEntry->Object;
659
660 /* Make sure it's really a thread */
661 if (FoundThread->Tcb.Header.Type == ThreadObject)
662 {
663 /* Safe Reference and return it */
664 if (ObReferenceObjectSafe(FoundThread))
665 {
666 *Thread = FoundThread;
667 Status = STATUS_SUCCESS;
668 }
669 }
670
671 /* Unlock the Entry */
672 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
673 }
674
675 /* Return to caller */
676 KeLeaveCriticalRegion();
677 return Status;
678 }
679
680 /*
681 * @implemented
682 */
683 ULONG
684 NTAPI
PsGetThreadFreezeCount(IN PETHREAD Thread)685 PsGetThreadFreezeCount(IN PETHREAD Thread)
686 {
687 return Thread->Tcb.FreezeCount;
688 }
689
690 /*
691 * @implemented
692 */
693 BOOLEAN
694 NTAPI
PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)695 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
696 {
697 return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
698 }
699
700 /*
701 * @implemented
702 */
703 HANDLE
704 NTAPI
PsGetThreadId(IN PETHREAD Thread)705 PsGetThreadId(IN PETHREAD Thread)
706 {
707 return Thread->Cid.UniqueThread;
708 }
709
710 /*
711 * @implemented
712 */
713 HANDLE
714 NTAPI
PsGetCurrentThreadId(VOID)715 PsGetCurrentThreadId(VOID)
716 {
717 return PsGetCurrentThread()->Cid.UniqueThread;
718 }
719
720 /*
721 * @implemented
722 */
723 PEPROCESS
724 NTAPI
PsGetThreadProcess(IN PETHREAD Thread)725 PsGetThreadProcess(IN PETHREAD Thread)
726 {
727 return Thread->ThreadsProcess;
728 }
729
730 /*
731 * @implemented
732 */
733 PEPROCESS
734 NTAPI
PsGetCurrentThreadProcess(VOID)735 PsGetCurrentThreadProcess(VOID)
736 {
737 return PsGetCurrentThread()->ThreadsProcess;
738 }
739
740 /*
741 * @implemented
742 */
743 HANDLE
744 NTAPI
PsGetThreadProcessId(IN PETHREAD Thread)745 PsGetThreadProcessId(IN PETHREAD Thread)
746 {
747 return Thread->Cid.UniqueProcess;
748 }
749
750 /*
751 * @implemented
752 */
753 HANDLE
754 NTAPI
PsGetCurrentThreadProcessId(VOID)755 PsGetCurrentThreadProcessId(VOID)
756 {
757 return PsGetCurrentThread()->Cid.UniqueProcess;
758 }
759
760 /*
761 * @implemented
762 */
763 ULONG
764 NTAPI
PsGetThreadSessionId(IN PETHREAD Thread)765 PsGetThreadSessionId(IN PETHREAD Thread)
766 {
767 return MmGetSessionId(Thread->ThreadsProcess);
768 }
769
770 /*
771 * @implemented
772 */
773 PTEB
774 NTAPI
PsGetThreadTeb(IN PETHREAD Thread)775 PsGetThreadTeb(IN PETHREAD Thread)
776 {
777 return Thread->Tcb.Teb;
778 }
779
780 /*
781 * @implemented
782 */
783 PVOID
784 NTAPI
PsGetCurrentThreadTeb(VOID)785 PsGetCurrentThreadTeb(VOID)
786 {
787 return PsGetCurrentThread()->Tcb.Teb;
788 }
789
790 /*
791 * @implemented
792 */
793 PVOID
794 NTAPI
PsGetThreadWin32Thread(IN PETHREAD Thread)795 PsGetThreadWin32Thread(IN PETHREAD Thread)
796 {
797 return Thread->Tcb.Win32Thread;
798 }
799
800 /*
801 * @implemented
802 */
803 PVOID
804 NTAPI
PsGetCurrentThreadWin32Thread(VOID)805 PsGetCurrentThreadWin32Thread(VOID)
806 {
807 return PsGetCurrentThread()->Tcb.Win32Thread;
808 }
809
810 /*
811 * @implemented
812 */
813 PVOID
814 NTAPI
PsGetCurrentThreadWin32ThreadAndEnterCriticalRegion(_Out_ HANDLE * OutProcessId)815 PsGetCurrentThreadWin32ThreadAndEnterCriticalRegion(
816 _Out_ HANDLE* OutProcessId)
817 {
818 PETHREAD CurrentThread;
819
820 /* Get the current thread */
821 CurrentThread = PsGetCurrentThread();
822
823 /* Return the process id */
824 *OutProcessId = CurrentThread->Cid.UniqueProcess;
825
826 /* Enter critical region */
827 KeEnterCriticalRegion();
828
829 /* Return the win32 thread */
830 return CurrentThread->Tcb.Win32Thread;
831 }
832
833 /*
834 * @implemented
835 */
836 KPROCESSOR_MODE
837 NTAPI
PsGetCurrentThreadPreviousMode(VOID)838 PsGetCurrentThreadPreviousMode(VOID)
839 {
840 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
841 }
842
843 /*
844 * @implemented
845 */
846 PVOID
847 NTAPI
PsGetCurrentThreadStackBase(VOID)848 PsGetCurrentThreadStackBase(VOID)
849 {
850 return PsGetCurrentThread()->Tcb.StackBase;
851 }
852
853 /*
854 * @implemented
855 */
856 PVOID
857 NTAPI
PsGetCurrentThreadStackLimit(VOID)858 PsGetCurrentThreadStackLimit(VOID)
859 {
860 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
861 }
862
863 /*
864 * @implemented
865 */
866 BOOLEAN
867 NTAPI
PsIsThreadTerminating(IN PETHREAD Thread)868 PsIsThreadTerminating(IN PETHREAD Thread)
869 {
870 return Thread->Terminated ? TRUE : FALSE;
871 }
872
873 /*
874 * @implemented
875 */
876 BOOLEAN
877 NTAPI
PsIsSystemThread(IN PETHREAD Thread)878 PsIsSystemThread(IN PETHREAD Thread)
879 {
880 return Thread->SystemThread ? TRUE: FALSE;
881 }
882
883 /*
884 * @implemented
885 */
886 BOOLEAN
887 NTAPI
PsIsThreadImpersonating(IN PETHREAD Thread)888 PsIsThreadImpersonating(IN PETHREAD Thread)
889 {
890 return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
891 }
892
893 /*
894 * @implemented
895 */
896 VOID
897 NTAPI
PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,IN BOOLEAN HardErrorsAreDisabled)898 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,
899 IN BOOLEAN HardErrorsAreDisabled)
900 {
901 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
902 }
903
904 /*
905 * @implemented
906 */
907 PVOID
908 NTAPI
PsSetThreadWin32Thread(_Inout_ PETHREAD Thread,_In_ PVOID Win32Thread,_In_ PVOID OldWin32Thread)909 PsSetThreadWin32Thread(
910 _Inout_ PETHREAD Thread,
911 _In_ PVOID Win32Thread,
912 _In_ PVOID OldWin32Thread)
913 {
914 /* Are we setting the win32 process? */
915 if (Win32Thread != NULL)
916 {
917 /* Just exchange it */
918 return InterlockedExchangePointer(&Thread->Tcb.Win32Thread,
919 Win32Thread);
920 }
921 else
922 {
923 /* We are resetting, only exchange when the old win32 thread matches */
924 return InterlockedCompareExchangePointer(&Thread->Tcb.Win32Thread,
925 Win32Thread,
926 OldWin32Thread);
927 }
928 }
929
930 NTSTATUS
931 NTAPI
PsWrapApcWow64Thread(IN OUT PVOID * ApcContext,IN OUT PVOID * ApcRoutine)932 PsWrapApcWow64Thread(IN OUT PVOID *ApcContext,
933 IN OUT PVOID *ApcRoutine)
934 {
935 UNIMPLEMENTED;
936 return STATUS_NOT_IMPLEMENTED;
937 }
938
939 NTSTATUS
940 NTAPI
NtCreateThread(OUT PHANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN HANDLE ProcessHandle,OUT PCLIENT_ID ClientId,IN PCONTEXT ThreadContext,IN PINITIAL_TEB InitialTeb,IN BOOLEAN CreateSuspended)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)
949 {
950 INITIAL_TEB SafeInitialTeb;
951 PAGED_CODE();
952 PSTRACE(PS_THREAD_DEBUG,
953 "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
954
955 /* Check if this was from user-mode */
956 if (KeGetPreviousMode() != KernelMode)
957 {
958 /* Make sure that we got a context */
959 if (!ThreadContext) return STATUS_INVALID_PARAMETER;
960
961 /* Protect checks */
962 _SEH2_TRY
963 {
964 /* Make sure the handle pointer we got is valid */
965 ProbeForWriteHandle(ThreadHandle);
966
967 /* Check if the caller wants a client id */
968 if (ClientId)
969 {
970 /* Make sure we can write to it */
971 ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
972 }
973
974 /* Make sure that the entire context is readable */
975 ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
976
977 /* Check the Initial TEB */
978 ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
979 SafeInitialTeb = *InitialTeb;
980 }
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
982 {
983 /* Return the exception code */
984 _SEH2_YIELD(return _SEH2_GetExceptionCode());
985 }
986 _SEH2_END;
987 }
988 else
989 {
990 /* Use the Initial TEB as is */
991 SafeInitialTeb = *InitialTeb;
992 }
993
994 /* Call the shared function */
995 return PspCreateThread(ThreadHandle,
996 DesiredAccess,
997 ObjectAttributes,
998 ProcessHandle,
999 NULL,
1000 ClientId,
1001 ThreadContext,
1002 &SafeInitialTeb,
1003 CreateSuspended,
1004 NULL,
1005 NULL);
1006 }
1007
1008 /*
1009 * @implemented
1010 */
1011 NTSTATUS
1012 NTAPI
NtOpenThread(OUT PHANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)1013 NtOpenThread(OUT PHANDLE ThreadHandle,
1014 IN ACCESS_MASK DesiredAccess,
1015 IN POBJECT_ATTRIBUTES ObjectAttributes,
1016 IN PCLIENT_ID ClientId OPTIONAL)
1017 {
1018 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1019 CLIENT_ID SafeClientId;
1020 ULONG Attributes = 0;
1021 HANDLE hThread = NULL;
1022 NTSTATUS Status;
1023 PETHREAD Thread;
1024 BOOLEAN HasObjectName = FALSE;
1025 ACCESS_STATE AccessState;
1026 AUX_ACCESS_DATA AuxData;
1027 PAGED_CODE();
1028 PSTRACE(PS_THREAD_DEBUG,
1029 "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
1030
1031 /* Check if we were called from user mode */
1032 if (PreviousMode != KernelMode)
1033 {
1034 /* Enter SEH for probing */
1035 _SEH2_TRY
1036 {
1037 /* Probe the thread handle */
1038 ProbeForWriteHandle(ThreadHandle);
1039
1040 /* Check for a CID structure */
1041 if (ClientId)
1042 {
1043 /* Probe and capture it */
1044 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
1045 SafeClientId = *ClientId;
1046 ClientId = &SafeClientId;
1047 }
1048
1049 /*
1050 * Just probe the object attributes structure, don't capture it
1051 * completely. This is done later if necessary
1052 */
1053 ProbeForRead(ObjectAttributes,
1054 sizeof(OBJECT_ATTRIBUTES),
1055 sizeof(ULONG));
1056 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1057
1058 /* Validate user attributes */
1059 Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
1060 }
1061 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1062 {
1063 /* Return the exception code */
1064 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1065 }
1066 _SEH2_END;
1067 }
1068 else
1069 {
1070 /* Otherwise just get the data directly */
1071 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1072
1073 /* Still have to sanitize attributes */
1074 Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode);
1075 }
1076
1077 /* Can't pass both, fail */
1078 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1079
1080 /* Create an access state */
1081 Status = SeCreateAccessState(&AccessState,
1082 &AuxData,
1083 DesiredAccess,
1084 &PsThreadType->TypeInfo.GenericMapping);
1085 if (!NT_SUCCESS(Status)) return Status;
1086
1087 /* Check if this is a debugger */
1088 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1089 {
1090 /* Did he want full access? */
1091 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1092 {
1093 /* Give it to him */
1094 AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS;
1095 }
1096 else
1097 {
1098 /* Otherwise just give every other access he could want */
1099 AccessState.PreviouslyGrantedAccess |=
1100 AccessState.RemainingDesiredAccess;
1101 }
1102
1103 /* The caller desires nothing else now */
1104 AccessState.RemainingDesiredAccess = 0;
1105 }
1106
1107 /* Open by name if one was given */
1108 if (HasObjectName)
1109 {
1110 /* Open it */
1111 Status = ObOpenObjectByName(ObjectAttributes,
1112 PsThreadType,
1113 PreviousMode,
1114 &AccessState,
1115 0,
1116 NULL,
1117 &hThread);
1118
1119 /* Get rid of the access state */
1120 SeDeleteAccessState(&AccessState);
1121 }
1122 else if (ClientId)
1123 {
1124 /* Open by Thread ID */
1125 if (ClientId->UniqueProcess)
1126 {
1127 /* Get the Process */
1128 Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread);
1129 }
1130 else
1131 {
1132 /* Get the Process */
1133 Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread);
1134 }
1135
1136 /* Check if we didn't find anything */
1137 if (!NT_SUCCESS(Status))
1138 {
1139 /* Get rid of the access state and return */
1140 SeDeleteAccessState(&AccessState);
1141 return Status;
1142 }
1143
1144 /* Open the Thread Object */
1145 Status = ObOpenObjectByPointer(Thread,
1146 Attributes,
1147 &AccessState,
1148 0,
1149 PsThreadType,
1150 PreviousMode,
1151 &hThread);
1152
1153 /* Delete the access state and dereference the thread */
1154 SeDeleteAccessState(&AccessState);
1155 ObDereferenceObject(Thread);
1156 }
1157 else
1158 {
1159 /* Neither an object name nor a client id was passed */
1160 return STATUS_INVALID_PARAMETER_MIX;
1161 }
1162
1163 /* Check for success */
1164 if (NT_SUCCESS(Status))
1165 {
1166 /* Protect against bad user-mode pointers */
1167 _SEH2_TRY
1168 {
1169 /* Write back the handle */
1170 *ThreadHandle = hThread;
1171 }
1172 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1173 {
1174 /* Get the exception code */
1175 Status = _SEH2_GetExceptionCode();
1176 }
1177 _SEH2_END;
1178 }
1179
1180 /* Return status */
1181 return Status;
1182 }
1183
1184 /* EOF */
1185