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 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 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 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 685 PsGetThreadFreezeCount(IN PETHREAD Thread) 686 { 687 return Thread->Tcb.FreezeCount; 688 } 689 690 /* 691 * @implemented 692 */ 693 BOOLEAN 694 NTAPI 695 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread) 696 { 697 return Thread->HardErrorsAreDisabled ? TRUE : FALSE; 698 } 699 700 /* 701 * @implemented 702 */ 703 HANDLE 704 NTAPI 705 PsGetThreadId(IN PETHREAD Thread) 706 { 707 return Thread->Cid.UniqueThread; 708 } 709 710 /* 711 * @implemented 712 */ 713 HANDLE 714 NTAPI 715 PsGetCurrentThreadId(VOID) 716 { 717 return PsGetCurrentThread()->Cid.UniqueThread; 718 } 719 720 /* 721 * @implemented 722 */ 723 PEPROCESS 724 NTAPI 725 PsGetThreadProcess(IN PETHREAD Thread) 726 { 727 return Thread->ThreadsProcess; 728 } 729 730 /* 731 * @implemented 732 */ 733 PEPROCESS 734 NTAPI 735 PsGetCurrentThreadProcess(VOID) 736 { 737 return PsGetCurrentThread()->ThreadsProcess; 738 } 739 740 /* 741 * @implemented 742 */ 743 HANDLE 744 NTAPI 745 PsGetThreadProcessId(IN PETHREAD Thread) 746 { 747 return Thread->Cid.UniqueProcess; 748 } 749 750 /* 751 * @implemented 752 */ 753 HANDLE 754 NTAPI 755 PsGetCurrentThreadProcessId(VOID) 756 { 757 return PsGetCurrentThread()->Cid.UniqueProcess; 758 } 759 760 /* 761 * @implemented 762 */ 763 ULONG 764 NTAPI 765 PsGetThreadSessionId(IN PETHREAD Thread) 766 { 767 return MmGetSessionId(Thread->ThreadsProcess); 768 } 769 770 /* 771 * @implemented 772 */ 773 PTEB 774 NTAPI 775 PsGetThreadTeb(IN PETHREAD Thread) 776 { 777 return Thread->Tcb.Teb; 778 } 779 780 /* 781 * @implemented 782 */ 783 PVOID 784 NTAPI 785 PsGetCurrentThreadTeb(VOID) 786 { 787 return PsGetCurrentThread()->Tcb.Teb; 788 } 789 790 /* 791 * @implemented 792 */ 793 PVOID 794 NTAPI 795 PsGetThreadWin32Thread(IN PETHREAD Thread) 796 { 797 return Thread->Tcb.Win32Thread; 798 } 799 800 /* 801 * @implemented 802 */ 803 PVOID 804 NTAPI 805 PsGetCurrentThreadWin32Thread(VOID) 806 { 807 return PsGetCurrentThread()->Tcb.Win32Thread; 808 } 809 810 /* 811 * @implemented 812 */ 813 PVOID 814 NTAPI 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 838 PsGetCurrentThreadPreviousMode(VOID) 839 { 840 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; 841 } 842 843 /* 844 * @implemented 845 */ 846 PVOID 847 NTAPI 848 PsGetCurrentThreadStackBase(VOID) 849 { 850 return PsGetCurrentThread()->Tcb.StackBase; 851 } 852 853 /* 854 * @implemented 855 */ 856 PVOID 857 NTAPI 858 PsGetCurrentThreadStackLimit(VOID) 859 { 860 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit; 861 } 862 863 /* 864 * @implemented 865 */ 866 BOOLEAN 867 NTAPI 868 PsIsThreadTerminating(IN PETHREAD Thread) 869 { 870 return Thread->Terminated ? TRUE : FALSE; 871 } 872 873 /* 874 * @implemented 875 */ 876 BOOLEAN 877 NTAPI 878 PsIsSystemThread(IN PETHREAD Thread) 879 { 880 return Thread->SystemThread ? TRUE: FALSE; 881 } 882 883 /* 884 * @implemented 885 */ 886 BOOLEAN 887 NTAPI 888 PsIsThreadImpersonating(IN PETHREAD Thread) 889 { 890 return Thread->ActiveImpersonationInfo ? TRUE : FALSE; 891 } 892 893 /* 894 * @implemented 895 */ 896 VOID 897 NTAPI 898 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread, 899 IN BOOLEAN HardErrorsAreDisabled) 900 { 901 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled; 902 } 903 904 /* 905 * @implemented 906 */ 907 PVOID 908 NTAPI 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 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 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 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