07e8f99e85c2d624c730d63b9b039789e37cd191
[reactos.git] / reactos / ntoskrnl / ps / thread.c
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
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
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
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
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 */
321 Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
322 Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);
323
324 /* Let the kernel intialize the Thread */
325 Status = KeInitThread(&Thread->Tcb,
326 NULL,
327 PspUserThreadStartup,
328 NULL,
329 Thread->StartAddress,
330 ThreadContext,
331 TebBase,
332 &Process->Pcb);
333 }
334 else
335 {
336 /* System Thread */
337 Thread->StartAddress = StartRoutine;
338 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
339
340 /* Let the kernel intialize the Thread */
341 Status = KeInitThread(&Thread->Tcb,
342 NULL,
343 PspSystemThreadStartup,
344 StartRoutine,
345 StartContext,
346 NULL,
347 NULL,
348 &Process->Pcb);
349 }
350
351 /* Check if we failed */
352 if (!NT_SUCCESS(Status))
353 {
354 /* Delete the TEB if we had done */
355 if (TebBase) MmDeleteTeb(Process, TebBase);
356
357 /* Release rundown and dereference */
358 ExReleaseRundownProtection(&Process->RundownProtect);
359 ObDereferenceObject(Thread);
360 return Status;
361 }
362
363 /* Lock the process */
364 KeEnterCriticalRegion();
365 ExAcquirePushLockExclusive(&Process->ProcessLock);
366
367 /* Make sure the proces didn't just die on us */
368 if (Process->ProcessDelete) goto Quickie;
369
370 /* Check if the thread was ours, terminated and it was user mode */
371 if ((Thread->Terminated) &&
372 (ThreadContext) &&
373 (Thread->ThreadsProcess == Process))
374 {
375 /* Cleanup, we don't want to start it up and context switch */
376 goto Quickie;
377 }
378
379 /*
380 * Insert the Thread into the Process's Thread List
381 * Note, this is the ETHREAD Thread List. It is removed in
382 * ps/kill.c!PspExitThread.
383 */
384 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
385 Process->ActiveThreads++;
386
387 /* Start the thread */
388 KeStartThread(&Thread->Tcb);
389
390 /* Release the process lock */
391 ExReleasePushLockExclusive(&Process->ProcessLock);
392 KeLeaveCriticalRegion();
393
394 /* Release rundown */
395 ExReleaseRundownProtection(&Process->RundownProtect);
396
397 /* Notify WMI */
398 //WmiTraceProcess(Process, TRUE);
399 //WmiTraceThread(Thread, InitialTeb, TRUE);
400
401 /* Notify Thread Creation */
402 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
403
404 /* Reference ourselves as a keep-alive */
405 ObReferenceObjectEx(Thread, 2);
406
407 /* Suspend the Thread if we have to */
408 if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
409
410 /* Check if we were already terminated */
411 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
412
413 /* Create an access state */
414 Status = SeCreateAccessStateEx(NULL,
415 ThreadContext ?
416 PsGetCurrentProcess() : Process,
417 &LocalAccessState,
418 &AuxData,
419 DesiredAccess,
420 &PsThreadType->TypeInfo.GenericMapping);
421 if (!NT_SUCCESS(Status))
422 {
423 /* Access state failed, thread is dead */
424 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
425
426 /* If we were suspended, wake it up */
427 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
428
429 /* Dispatch thread */
430 KeReadyThread(&Thread->Tcb);
431
432 /* Dereference completely to kill it */
433 ObDereferenceObjectEx(Thread, 2);
434 return Status;
435 }
436
437 /* Insert the Thread into the Object Manager */
438 Status = ObInsertObject(Thread,
439 AccessState,
440 DesiredAccess,
441 0,
442 NULL,
443 &hThread);
444
445 /* Delete the access state if we had one */
446 if (AccessState) SeDeleteAccessState(AccessState);
447
448 /* Check for success */
449 if (NT_SUCCESS(Status))
450 {
451 /* Wrap in SEH to protect against bad user-mode pointers */
452 _SEH2_TRY
453 {
454 /* Return Cid and Handle */
455 if (ClientId) *ClientId = Thread->Cid;
456 *ThreadHandle = hThread;
457 }
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
459 {
460 /* Thread insertion failed, thread is dead */
461 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
462
463 /* If we were suspended, wake it up */
464 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
465
466 /* Dispatch thread */
467 KeReadyThread(&Thread->Tcb);
468
469 /* Dereference it, leaving only the keep-alive */
470 ObDereferenceObject(Thread);
471
472 /* Close its handle, killing it */
473 ObCloseHandle(ThreadHandle, PreviousMode);
474
475 /* Return the exception code */
476 _SEH2_YIELD(return _SEH2_GetExceptionCode());
477 }
478 _SEH2_END;
479 }
480 else
481 {
482 /* Thread insertion failed, thread is dead */
483 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
484
485 /* If we were suspended, wake it up */
486 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
487 }
488
489 /* Get the create time */
490 KeQuerySystemTime(&Thread->CreateTime);
491 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
492
493 /* Make sure the thread isn't dead */
494 if (!Thread->DeadThread)
495 {
496 /* Get the thread's SD */
497 Status = ObGetObjectSecurity(Thread,
498 &SecurityDescriptor,
499 &SdAllocated);
500 if (!NT_SUCCESS(Status))
501 {
502 /* Thread insertion failed, thread is dead */
503 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
504
505 /* If we were suspended, wake it up */
506 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
507
508 /* Dispatch thread */
509 KeReadyThread(&Thread->Tcb);
510
511 /* Dereference it, leaving only the keep-alive */
512 ObDereferenceObject(Thread);
513
514 /* Close its handle, killing it */
515 ObCloseHandle(ThreadHandle, PreviousMode);
516 return Status;
517 }
518
519 /* Create the subject context */
520 SubjectContext.ProcessAuditId = Process;
521 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
522 SubjectContext.ClientToken = NULL;
523
524 /* Do the access check */
525 Result = SeAccessCheck(SecurityDescriptor,
526 &SubjectContext,
527 FALSE,
528 MAXIMUM_ALLOWED,
529 0,
530 NULL,
531 &PsThreadType->TypeInfo.GenericMapping,
532 PreviousMode,
533 &Thread->GrantedAccess,
534 &AccessStatus);
535
536 /* Dereference the token and let go the SD */
537 ObFastDereferenceObject(&Process->Token,
538 SubjectContext.PrimaryToken);
539 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
540
541 /* Remove access if it failed */
542 if (!Result) Process->GrantedAccess = 0;
543
544 /* Set least some minimum access */
545 Thread->GrantedAccess |= (THREAD_TERMINATE |
546 THREAD_SET_INFORMATION |
547 THREAD_QUERY_INFORMATION);
548 }
549 else
550 {
551 /* Set the thread access mask to maximum */
552 Thread->GrantedAccess = THREAD_ALL_ACCESS;
553 }
554
555 /* Dispatch thread */
556 KeReadyThread(&Thread->Tcb);
557
558 /* Dereference it, leaving only the keep-alive */
559 ObDereferenceObject(Thread);
560
561 /* Return */
562 return Status;
563
564 /* Most annoying failure case ever, where we undo almost all manually */
565 Quickie:
566 /* When we get here, the process is locked, unlock it */
567 ExReleasePushLockExclusive(&Process->ProcessLock);
568 KeLeaveCriticalRegion();
569
570 /* Uninitailize it */
571 KeUninitThread(&Thread->Tcb);
572
573 /* If we had a TEB, delete it */
574 if (TebBase) MmDeleteTeb(Process, TebBase);
575
576 /* Release rundown protection, which we also hold */
577 ExReleaseRundownProtection(&Process->RundownProtect);
578
579 /* Dereference the thread and return failure */
580 ObDereferenceObject(Thread);
581 return STATUS_PROCESS_IS_TERMINATING;
582 }
583
584 /* PUBLIC FUNCTIONS **********************************************************/
585
586 /*
587 * @implemented
588 */
589 NTSTATUS
590 NTAPI
591 PsCreateSystemThread(OUT PHANDLE ThreadHandle,
592 IN ACCESS_MASK DesiredAccess,
593 IN POBJECT_ATTRIBUTES ObjectAttributes,
594 IN HANDLE ProcessHandle,
595 IN PCLIENT_ID ClientId,
596 IN PKSTART_ROUTINE StartRoutine,
597 IN PVOID StartContext)
598 {
599 PEPROCESS TargetProcess = NULL;
600 HANDLE Handle = ProcessHandle;
601 PAGED_CODE();
602 PSTRACE(PS_THREAD_DEBUG,
603 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
604 ProcessHandle, StartRoutine, StartContext);
605
606 /* Check if we have a handle. If not, use the System Process */
607 if (!ProcessHandle)
608 {
609 Handle = NULL;
610 TargetProcess = PsInitialSystemProcess;
611 }
612
613 /* Call the shared function */
614 return PspCreateThread(ThreadHandle,
615 DesiredAccess,
616 ObjectAttributes,
617 Handle,
618 TargetProcess,
619 ClientId,
620 NULL,
621 NULL,
622 FALSE,
623 StartRoutine,
624 StartContext);
625 }
626
627 /*
628 * @implemented
629 */
630 NTSTATUS
631 NTAPI
632 PsLookupThreadByThreadId(IN HANDLE ThreadId,
633 OUT PETHREAD *Thread)
634 {
635 PHANDLE_TABLE_ENTRY CidEntry;
636 PETHREAD FoundThread;
637 NTSTATUS Status = STATUS_INVALID_PARAMETER;
638 PAGED_CODE();
639 PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
640 KeEnterCriticalRegion();
641
642 /* Get the CID Handle Entry */
643 CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
644 if (CidEntry)
645 {
646 /* Get the Process */
647 FoundThread = CidEntry->Object;
648
649 /* Make sure it's really a process */
650 if (FoundThread->Tcb.Header.Type == ThreadObject)
651 {
652 /* Safe Reference and return it */
653 if (ObReferenceObjectSafe(FoundThread))
654 {
655 *Thread = FoundThread;
656 Status = STATUS_SUCCESS;
657 }
658 }
659
660 /* Unlock the Entry */
661 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
662 }
663
664 /* Return to caller */
665 KeLeaveCriticalRegion();
666 return Status;
667 }
668
669 /*
670 * @implemented
671 */
672 ULONG
673 NTAPI
674 PsGetThreadFreezeCount(IN PETHREAD Thread)
675 {
676 return Thread->Tcb.FreezeCount;
677 }
678
679 /*
680 * @implemented
681 */
682 BOOLEAN
683 NTAPI
684 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
685 {
686 return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
687 }
688
689 /*
690 * @implemented
691 */
692 HANDLE
693 NTAPI
694 PsGetThreadId(IN PETHREAD Thread)
695 {
696 return Thread->Cid.UniqueThread;
697 }
698
699 /*
700 * @implemented
701 */
702 HANDLE
703 NTAPI
704 PsGetCurrentThreadId(VOID)
705 {
706 return PsGetCurrentThread()->Cid.UniqueThread;
707 }
708
709 /*
710 * @implemented
711 */
712 PEPROCESS
713 NTAPI
714 PsGetThreadProcess(IN PETHREAD Thread)
715 {
716 return Thread->ThreadsProcess;
717 }
718
719 /*
720 * @implemented
721 */
722 PEPROCESS
723 NTAPI
724 PsGetCurrentThreadProcess(VOID)
725 {
726 return PsGetCurrentThread()->ThreadsProcess;
727 }
728
729 /*
730 * @implemented
731 */
732 HANDLE
733 NTAPI
734 PsGetThreadProcessId(IN PETHREAD Thread)
735 {
736 return Thread->Cid.UniqueProcess;
737 }
738
739 /*
740 * @implemented
741 */
742 HANDLE
743 NTAPI
744 PsGetCurrentThreadProcessId(VOID)
745 {
746 return PsGetCurrentThread()->Cid.UniqueProcess;
747 }
748
749 /*
750 * @implemented
751 */
752 ULONG
753 NTAPI
754 PsGetThreadSessionId(IN PETHREAD Thread)
755 {
756 return MmGetSessionId(Thread->ThreadsProcess);
757 }
758
759 /*
760 * @implemented
761 */
762 PTEB
763 NTAPI
764 PsGetThreadTeb(IN PETHREAD Thread)
765 {
766 return Thread->Tcb.Teb;
767 }
768
769 /*
770 * @implemented
771 */
772 PTEB
773 NTAPI
774 PsGetCurrentThreadTeb(VOID)
775 {
776 return PsGetCurrentThread()->Tcb.Teb;
777 }
778
779 /*
780 * @implemented
781 */
782 PVOID
783 NTAPI
784 PsGetThreadWin32Thread(IN PETHREAD Thread)
785 {
786 return Thread->Tcb.Win32Thread;
787 }
788
789 /*
790 * @implemented
791 */
792 PVOID
793 NTAPI
794 PsGetCurrentThreadWin32Thread(VOID)
795 {
796 return PsGetCurrentThread()->Tcb.Win32Thread;
797 }
798
799 /*
800 * @implemented
801 */
802 KPROCESSOR_MODE
803 NTAPI
804 PsGetCurrentThreadPreviousMode(VOID)
805 {
806 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
807 }
808
809 /*
810 * @implemented
811 */
812 PVOID
813 NTAPI
814 PsGetCurrentThreadStackBase(VOID)
815 {
816 return PsGetCurrentThread()->Tcb.StackBase;
817 }
818
819 /*
820 * @implemented
821 */
822 PVOID
823 NTAPI
824 PsGetCurrentThreadStackLimit(VOID)
825 {
826 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
827 }
828
829 /*
830 * @implemented
831 */
832 BOOLEAN
833 NTAPI
834 PsIsThreadTerminating(IN PETHREAD Thread)
835 {
836 return Thread->Terminated ? TRUE : FALSE;
837 }
838
839 /*
840 * @implemented
841 */
842 BOOLEAN
843 NTAPI
844 PsIsSystemThread(IN PETHREAD Thread)
845 {
846 return Thread->SystemThread ? TRUE: FALSE;
847 }
848
849 /*
850 * @implemented
851 */
852 BOOLEAN
853 NTAPI
854 PsIsThreadImpersonating(IN PETHREAD Thread)
855 {
856 return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
857 }
858
859 /*
860 * @implemented
861 */
862 VOID
863 NTAPI
864 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,
865 IN BOOLEAN HardErrorsAreDisabled)
866 {
867 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
868 }
869
870 /*
871 * @implemented
872 */
873 VOID
874 NTAPI
875 PsSetThreadWin32Thread(IN PETHREAD Thread,
876 IN PVOID Win32Thread)
877 {
878 Thread->Tcb.Win32Thread = Win32Thread;
879 }
880
881 NTSTATUS
882 NTAPI
883 NtCreateThread(OUT PHANDLE ThreadHandle,
884 IN ACCESS_MASK DesiredAccess,
885 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
886 IN HANDLE ProcessHandle,
887 OUT PCLIENT_ID ClientId,
888 IN PCONTEXT ThreadContext,
889 IN PINITIAL_TEB InitialTeb,
890 IN BOOLEAN CreateSuspended)
891 {
892 INITIAL_TEB SafeInitialTeb;
893 PAGED_CODE();
894 PSTRACE(PS_THREAD_DEBUG,
895 "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
896
897 /* Check if this was from user-mode */
898 if (KeGetPreviousMode() != KernelMode)
899 {
900 /* Make sure that we got a context */
901 if (!ThreadContext) return STATUS_INVALID_PARAMETER;
902
903 /* Protect checks */
904 _SEH2_TRY
905 {
906 /* Make sure the handle pointer we got is valid */
907 ProbeForWriteHandle(ThreadHandle);
908
909 /* Check if the caller wants a client id */
910 if (ClientId)
911 {
912 /* Make sure we can write to it */
913 ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
914 }
915
916 /* Make sure that the entire context is readable */
917 ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
918
919 /* Check the Initial TEB */
920 ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
921 SafeInitialTeb = *InitialTeb;
922 }
923 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
924 {
925 /* Return the exception code */
926 _SEH2_YIELD(return _SEH2_GetExceptionCode());
927 }
928 _SEH2_END;
929 }
930 else
931 {
932 /* Use the Initial TEB as is */
933 SafeInitialTeb = *InitialTeb;
934 }
935
936 /* Call the shared function */
937 return PspCreateThread(ThreadHandle,
938 DesiredAccess,
939 ObjectAttributes,
940 ProcessHandle,
941 NULL,
942 ClientId,
943 ThreadContext,
944 &SafeInitialTeb,
945 CreateSuspended,
946 NULL,
947 NULL);
948 }
949
950 /*
951 * @implemented
952 */
953 NTSTATUS
954 NTAPI
955 NtOpenThread(OUT PHANDLE ThreadHandle,
956 IN ACCESS_MASK DesiredAccess,
957 IN POBJECT_ATTRIBUTES ObjectAttributes,
958 IN PCLIENT_ID ClientId OPTIONAL)
959 {
960 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
961 CLIENT_ID SafeClientId;
962 ULONG Attributes = 0;
963 HANDLE hThread = NULL;
964 NTSTATUS Status;
965 PETHREAD Thread;
966 BOOLEAN HasObjectName = FALSE;
967 ACCESS_STATE AccessState;
968 AUX_ACCESS_DATA AuxData;
969 PAGED_CODE();
970 PSTRACE(PS_THREAD_DEBUG,
971 "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
972
973 /* Check if we were called from user mode */
974 if (PreviousMode != KernelMode)
975 {
976 /* Enter SEH for probing */
977 _SEH2_TRY
978 {
979 /* Probe the thread handle */
980 ProbeForWriteHandle(ThreadHandle);
981
982 /* Check for a CID structure */
983 if (ClientId)
984 {
985 /* Probe and capture it */
986 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
987 SafeClientId = *ClientId;
988 ClientId = &SafeClientId;
989 }
990
991 /*
992 * Just probe the object attributes structure, don't capture it
993 * completely. This is done later if necessary
994 */
995 ProbeForRead(ObjectAttributes,
996 sizeof(OBJECT_ATTRIBUTES),
997 sizeof(ULONG));
998 HasObjectName = (ObjectAttributes->ObjectName != NULL);
999 Attributes = ObjectAttributes->Attributes;
1000 }
1001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1002 {
1003 /* Return the exception code */
1004 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1005 }
1006 _SEH2_END;
1007 }
1008 else
1009 {
1010 /* Otherwise just get the data directly */
1011 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1012 Attributes = ObjectAttributes->Attributes;
1013 }
1014
1015 /* Can't pass both, fail */
1016 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1017
1018 /* Create an access state */
1019 Status = SeCreateAccessState(&AccessState,
1020 &AuxData,
1021 DesiredAccess,
1022 &PsProcessType->TypeInfo.GenericMapping);
1023 if (!NT_SUCCESS(Status)) return Status;
1024
1025 /* Check if this is a debugger */
1026 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1027 {
1028 /* Did he want full access? */
1029 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1030 {
1031 /* Give it to him */
1032 AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS;
1033 }
1034 else
1035 {
1036 /* Otherwise just give every other access he could want */
1037 AccessState.PreviouslyGrantedAccess |=
1038 AccessState.RemainingDesiredAccess;
1039 }
1040
1041 /* The caller desires nothing else now */
1042 AccessState.RemainingDesiredAccess = 0;
1043 }
1044
1045 /* Open by name if one was given */
1046 if (HasObjectName)
1047 {
1048 /* Open it */
1049 Status = ObOpenObjectByName(ObjectAttributes,
1050 PsThreadType,
1051 PreviousMode,
1052 &AccessState,
1053 0,
1054 NULL,
1055 &hThread);
1056
1057 /* Get rid of the access state */
1058 SeDeleteAccessState(&AccessState);
1059 }
1060 else if (ClientId)
1061 {
1062 /* Open by Thread ID */
1063 if (ClientId->UniqueProcess)
1064 {
1065 /* Get the Process */
1066 Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread);
1067 }
1068 else
1069 {
1070 /* Get the Process */
1071 Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread);
1072 }
1073
1074 /* Check if we didn't find anything */
1075 if (!NT_SUCCESS(Status))
1076 {
1077 /* Get rid of the access state and return */
1078 SeDeleteAccessState(&AccessState);
1079 return Status;
1080 }
1081
1082 /* Open the Thread Object */
1083 Status = ObOpenObjectByPointer(Thread,
1084 Attributes,
1085 &AccessState,
1086 0,
1087 PsThreadType,
1088 PreviousMode,
1089 &hThread);
1090
1091 /* Delete the access state and dereference the thread */
1092 SeDeleteAccessState(&AccessState);
1093 ObDereferenceObject(Thread);
1094 }
1095 else
1096 {
1097 /* Neither an object name nor a client id was passed */
1098 return STATUS_INVALID_PARAMETER_MIX;
1099 }
1100
1101 /* Check for success */
1102 if (NT_SUCCESS(Status))
1103 {
1104 /* Protect against bad user-mode pointers */
1105 _SEH2_TRY
1106 {
1107 /* Write back the handle */
1108 *ThreadHandle = hThread;
1109 }
1110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1111 {
1112 /* Get the exception code */
1113 Status = _SEH2_GetExceptionCode();
1114 }
1115 _SEH2_END;
1116 }
1117
1118 /* Return status */
1119 return Status;
1120 }
1121
1122 /* EOF */