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