1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ps/kill.c 5 * PURPOSE: Process Manager: Process and Thread Termination 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Filip Navara (xnavara@reactos.org) 8 * Thomas Weidenmueller (w3seek@reactos.org 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <internal/debug.h> 16 17 /* GLOBALS *******************************************************************/ 18 19 LIST_ENTRY PspReaperListHead = {0}; 20 WORK_QUEUE_ITEM PspReaperWorkItem; 21 LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}}; 22 23 /* PRIVATE FUNCTIONS *********************************************************/ 24 25 VOID 26 NTAPI 27 PspCatchCriticalBreak(IN PCHAR Message, 28 IN PVOID ProcessOrThread, 29 IN PCHAR ImageName) 30 { 31 CHAR Action[2]; 32 BOOLEAN Handled = FALSE; 33 PAGED_CODE(); 34 35 /* Check if a debugger is enabled */ 36 if (KdDebuggerEnabled) 37 { 38 /* Print out the message */ 39 DbgPrint(Message, ProcessOrThread, ImageName); 40 do 41 { 42 /* If a debugger isn't present, don't prompt */ 43 if (KdDebuggerNotPresent) break; 44 45 /* A debuger is active, prompt for action */ 46 DbgPrompt("Break, or Ignore (bi)?", Action, sizeof(Action)); 47 switch (Action[0]) 48 { 49 /* Break */ 50 case 'B': case 'b': 51 52 /* Do a breakpoint */ 53 DbgBreakPoint(); 54 55 /* Ignore */ 56 case 'I': case 'i': 57 58 /* Handle it */ 59 Handled = TRUE; 60 61 /* Unrecognized */ 62 default: 63 break; 64 } 65 } while (!Handled); 66 } 67 68 /* Did we ultimately handle this? */ 69 if (!Handled) 70 { 71 /* We didn't, bugcheck */ 72 KeBugCheckEx(CRITICAL_OBJECT_TERMINATION, 73 ((PKPROCESS)ProcessOrThread)->Header.Type, 74 (ULONG_PTR)ProcessOrThread, 75 (ULONG_PTR)ImageName, 76 (ULONG_PTR)Message); 77 } 78 } 79 80 NTSTATUS 81 NTAPI 82 PspTerminateProcess(IN PEPROCESS Process, 83 IN NTSTATUS ExitStatus) 84 { 85 PETHREAD Thread; 86 NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE; 87 PAGED_CODE(); 88 PSTRACE(PS_KILL_DEBUG, 89 "Process: %p ExitStatus: %p\n", Process, ExitStatus); 90 PSREFTRACE(Process); 91 92 /* Check if this is a Critical Process */ 93 if (Process->BreakOnTermination) 94 { 95 /* Break to debugger */ 96 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", 97 Process, 98 Process->ImageFileName); 99 } 100 101 /* Set the delete flag */ 102 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT); 103 104 /* Get the first thread */ 105 Thread = PsGetNextProcessThread(Process, NULL); 106 while (Thread) 107 { 108 /* Kill it */ 109 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 110 Thread = PsGetNextProcessThread(Process, Thread); 111 112 /* We had at least one thread, so termination is OK */ 113 Status = STATUS_SUCCESS; 114 } 115 116 /* Check if there was nothing to terminate or if we have a debug port */ 117 if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort)) 118 { 119 /* Clear the handle table anyway */ 120 ObClearProcessHandleTable(Process); 121 } 122 123 /* Return status */ 124 return Status; 125 } 126 127 NTSTATUS 128 NTAPI 129 PsTerminateProcess(IN PEPROCESS Process, 130 IN NTSTATUS ExitStatus) 131 { 132 /* Call the internal API */ 133 return PspTerminateProcess(Process, ExitStatus); 134 } 135 136 VOID 137 NTAPI 138 PspShutdownProcessManager(VOID) 139 { 140 PEPROCESS Process = NULL; 141 142 /* Loop every process */ 143 Process = PsGetNextProcess(Process); 144 while (Process) 145 { 146 /* Make sure this isn't the idle or initial process */ 147 if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess)) 148 { 149 /* Kill it */ 150 PspTerminateProcess(Process, STATUS_SYSTEM_SHUTDOWN); 151 } 152 153 /* Get the next process */ 154 Process = PsGetNextProcess(Process); 155 } 156 } 157 158 VOID 159 NTAPI 160 PspExitApcRundown(IN PKAPC Apc) 161 { 162 PAGED_CODE(); 163 164 /* Free the APC */ 165 ExFreePool(Apc); 166 } 167 168 VOID 169 NTAPI 170 PspReapRoutine(IN PVOID Context) 171 { 172 PSINGLE_LIST_ENTRY NextEntry; 173 PETHREAD Thread; 174 PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context); 175 176 /* Start main loop */ 177 do 178 { 179 /* Write magic value and return the next entry to process */ 180 NextEntry = InterlockedExchangePointer(&PspReaperListHead.Flink, 181 (PVOID)1); 182 ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1)); 183 184 /* Start inner loop */ 185 do 186 { 187 /* Get the first Thread Entry */ 188 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink); 189 190 /* Delete this entry's kernel stack */ 191 MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, 192 Thread->Tcb.LargeStack); 193 Thread->Tcb.InitialStack = NULL; 194 195 /* Move to the next entry */ 196 NextEntry = NextEntry->Next; 197 198 /* Dereference this thread */ 199 ObDereferenceObject(Thread); 200 } while ((NextEntry != NULL) && (NextEntry != (PVOID)1)); 201 202 /* Remove magic value, keep looping if it got changed */ 203 } while (InterlockedCompareExchangePointer(&PspReaperListHead.Flink, 204 0, 205 1) != (PVOID)1); 206 } 207 208 VOID 209 NTAPI 210 PspDeleteProcess(IN PVOID ObjectBody) 211 { 212 PEPROCESS Process = (PEPROCESS)ObjectBody; 213 KAPC_STATE ApcState; 214 PAGED_CODE(); 215 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody); 216 PSREFTRACE(Process); 217 218 /* Check if it has an Active Process Link */ 219 if (Process->ActiveProcessLinks.Flink) 220 { 221 /* Remove it from the Active List */ 222 KeAcquireGuardedMutex(&PspActiveProcessMutex); 223 RemoveEntryList(&Process->ActiveProcessLinks); 224 KeReleaseGuardedMutex(&PspActiveProcessMutex); 225 } 226 227 /* Check for Auditing information */ 228 if (Process->SeAuditProcessCreationInfo.ImageFileName) 229 { 230 /* Free it */ 231 ExFreePool(Process->SeAuditProcessCreationInfo.ImageFileName); 232 Process->SeAuditProcessCreationInfo.ImageFileName = NULL; 233 } 234 235 /* Check if we have a job */ 236 if (Process->Job) 237 { 238 /* Remove the process from the job */ 239 PspRemoveProcessFromJob(Process, Process->Job); 240 241 /* Dereference it */ 242 ObDereferenceObject(Process->Job); 243 Process->Job = NULL; 244 } 245 246 /* Increase the stack count */ 247 Process->Pcb.StackCount++; 248 249 /* Check if we have a debug port */ 250 if (Process->DebugPort) 251 { 252 /* Deference the Debug Port */ 253 ObDereferenceObject(Process->DebugPort); 254 Process->DebugPort = NULL; 255 } 256 257 /* Check if we have an exception port */ 258 if (Process->ExceptionPort) 259 { 260 /* Deference the Exception Port */ 261 ObDereferenceObject(Process->ExceptionPort); 262 Process->ExceptionPort = NULL; 263 } 264 265 /* Check if we have a section object */ 266 if (Process->SectionObject) 267 { 268 /* Deference the Section Object */ 269 ObDereferenceObject(Process->SectionObject); 270 Process->SectionObject = NULL; 271 } 272 273 /* Clean LDT and VDM_OBJECTS */ 274 PspDeleteLdt(Process); 275 PspDeleteVdmObjects(Process); 276 277 /* Delete the Object Table */ 278 if (Process->ObjectTable) 279 { 280 /* Attach to the process */ 281 KeStackAttachProcess(&Process->Pcb, &ApcState); 282 283 /* Kill the Object Info */ 284 ObKillProcess(Process); 285 286 /* Detach */ 287 KeUnstackDetachProcess(&ApcState); 288 } 289 290 /* Check if we have an address space, and clean it */ 291 if (Process->HasAddressSpace) 292 { 293 /* Attach to the process */ 294 KeStackAttachProcess(&Process->Pcb, &ApcState); 295 296 /* Clean the Address Space */ 297 PspExitProcess(FALSE, Process); 298 299 /* Detach */ 300 KeUnstackDetachProcess(&ApcState); 301 302 /* Completely delete the Address Space */ 303 MmDeleteProcessAddressSpace(Process); 304 } 305 306 /* See if we have a PID */ 307 if (Process->UniqueProcessId) 308 { 309 /* Delete the PID */ 310 if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId, NULL))) 311 { 312 /* Something wrong happened, bugcheck */ 313 KEBUGCHECK(CID_HANDLE_DELETION); 314 } 315 } 316 317 /* Cleanup security information */ 318 PspDeleteProcessSecurity(Process); 319 320 /* Check if we have kept information on the Working Set */ 321 if (Process->WorkingSetWatch) 322 { 323 /* Free it */ 324 ExFreePool(Process->WorkingSetWatch); 325 326 /* And return the quota it was taking up */ 327 PsReturnProcessNonPagedPoolQuota(Process, 0x2000); 328 } 329 330 /* Dereference the Device Map */ 331 ObDereferenceDeviceMap(Process); 332 333 /* Destroy the Quota Block */ 334 PspDestroyQuotaBlock(Process); 335 } 336 337 VOID 338 NTAPI 339 PspDeleteThread(IN PVOID ObjectBody) 340 { 341 PETHREAD Thread = (PETHREAD)ObjectBody; 342 PEPROCESS Process = Thread->ThreadsProcess; 343 PAGED_CODE(); 344 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody); 345 PSREFTRACE(Thread); 346 ASSERT(Thread->Tcb.Win32Thread == NULL); 347 348 /* Check if we have a stack */ 349 if (Thread->Tcb.InitialStack) 350 { 351 /* Release it */ 352 MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, 353 Thread->Tcb.LargeStack); 354 } 355 356 /* Check if we have a CID Handle */ 357 if (Thread->Cid.UniqueThread) 358 { 359 /* Delete the CID Handle */ 360 if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread, NULL))) 361 { 362 /* Something wrong happened, bugcheck */ 363 KEBUGCHECK(CID_HANDLE_DELETION); 364 } 365 } 366 367 /* Cleanup impersionation information */ 368 PspDeleteThreadSecurity(Thread); 369 370 /* Make sure the thread was inserted, before continuing */ 371 if (!Process) return; 372 373 /* Check if the thread list is valid */ 374 if (Thread->ThreadListEntry.Flink) 375 { 376 /* Lock the thread's process */ 377 KeEnterCriticalRegion(); 378 ExAcquirePushLockExclusive(&Process->ProcessLock); 379 380 /* Remove us from the list */ 381 RemoveEntryList(&Thread->ThreadListEntry); 382 383 /* Release the lock */ 384 ExReleasePushLockExclusive(&Process->ProcessLock); 385 KeLeaveCriticalRegion(); 386 } 387 388 /* Dereference the Process */ 389 ObDereferenceObject(Process); 390 } 391 392 /* 393 * FUNCTION: Terminates the current thread 394 * See "Windows Internals" - Chapter 13, Page 50-53 395 */ 396 VOID 397 NTAPI 398 PspExitThread(IN NTSTATUS ExitStatus) 399 { 400 CLIENT_DIED_MSG TerminationMsg; 401 NTSTATUS Status; 402 PTEB Teb; 403 PEPROCESS CurrentProcess; 404 PETHREAD Thread, OtherThread, PreviousThread = NULL; 405 PVOID DeallocationStack; 406 ULONG Dummy; 407 BOOLEAN Last = FALSE; 408 PTERMINATION_PORT TerminationPort, NextPort; 409 PLIST_ENTRY FirstEntry, CurrentEntry; 410 PKAPC Apc; 411 PTOKEN PrimaryToken; 412 PAGED_CODE(); 413 PSTRACE(PS_KILL_DEBUG, "ExitStatus: %p\n", ExitStatus); 414 415 /* Get the Current Thread and Process */ 416 Thread = PsGetCurrentThread(); 417 CurrentProcess = Thread->ThreadsProcess; 418 ASSERT((Thread) == PsGetCurrentThread()); 419 420 /* Can't terminate a thread if it attached another process */ 421 if (KeIsAttachedProcess()) 422 { 423 /* Bugcheck */ 424 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, 425 (ULONG_PTR)CurrentProcess, 426 (ULONG_PTR)Thread->Tcb.ApcState.Process, 427 (ULONG_PTR)Thread->Tcb.ApcStateIndex, 428 (ULONG_PTR)Thread); 429 } 430 431 /* Lower to Passive Level */ 432 KeLowerIrql(PASSIVE_LEVEL); 433 434 /* Can't be a worker thread */ 435 if (Thread->ActiveExWorker) 436 { 437 /* Bugcheck */ 438 KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION, 439 (ULONG_PTR)Thread, 440 0, 441 0, 442 0); 443 } 444 445 /* Can't have pending APCs */ 446 if (Thread->Tcb.CombinedApcDisable != 0) 447 { 448 /* Bugcheck */ 449 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, 450 0, 451 Thread->Tcb.CombinedApcDisable, 452 0, 453 1); 454 } 455 456 /* Lock the thread */ 457 ExWaitForRundownProtectionRelease(&Thread->RundownProtect); 458 459 /* Cleanup the power state */ 460 PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState); 461 462 /* Call the WMI Callback for Threads */ 463 //WmiTraceThread(Thread, NULL, FALSE); 464 465 /* Run Thread Notify Routines before we desintegrate the thread */ 466 PspRunCreateThreadNotifyRoutines(Thread, FALSE); 467 468 /* Lock the Process before we modify its thread entries */ 469 KeEnterCriticalRegion(); 470 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); 471 472 /* Decrease the active thread count, and check if it's 0 */ 473 if (!(--CurrentProcess->ActiveThreads)) 474 { 475 /* Set the delete flag */ 476 InterlockedOr((PLONG)&CurrentProcess->Flags, PSF_PROCESS_DELETE_BIT); 477 478 /* Remember we are last */ 479 Last = TRUE; 480 481 /* Check if this termination is due to the thread dying */ 482 if (ExitStatus == STATUS_THREAD_IS_TERMINATING) 483 { 484 /* Check if the last thread was pending */ 485 if (CurrentProcess->ExitStatus == STATUS_PENDING) 486 { 487 /* Use the last exit status */ 488 CurrentProcess->ExitStatus = CurrentProcess-> 489 LastThreadExitStatus; 490 } 491 } 492 else 493 { 494 /* Just a normal exit, write the code */ 495 CurrentProcess->ExitStatus = ExitStatus; 496 } 497 498 /* Loop all the current threads */ 499 FirstEntry = &CurrentProcess->ThreadListHead; 500 CurrentEntry = FirstEntry->Flink; 501 while (FirstEntry != CurrentEntry) 502 { 503 /* Get the thread on the list */ 504 OtherThread = CONTAINING_RECORD(CurrentEntry, 505 ETHREAD, 506 ThreadListEntry); 507 508 /* Check if it's a thread that's still alive */ 509 if ((OtherThread != Thread) && 510 !(KeReadStateThread(&OtherThread->Tcb)) && 511 (ObReferenceObjectSafe(OtherThread))) 512 { 513 /* It's a live thread and we referenced it, unlock process */ 514 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); 515 KeLeaveCriticalRegion(); 516 517 /* Wait on the thread */ 518 KeWaitForSingleObject(OtherThread, 519 Executive, 520 KernelMode, 521 FALSE, 522 NULL); 523 524 /* Check if we had a previous thread to dereference */ 525 if (PreviousThread) ObDereferenceObject(PreviousThread); 526 527 /* Remember the thread and re-lock the process */ 528 PreviousThread = OtherThread; 529 KeEnterCriticalRegion(); 530 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); 531 } 532 533 /* Go to the next thread */ 534 CurrentEntry = CurrentEntry->Flink; 535 } 536 } 537 else if (ExitStatus != STATUS_THREAD_IS_TERMINATING) 538 { 539 /* Write down the exit status of the last thread to get killed */ 540 CurrentProcess->LastThreadExitStatus = ExitStatus; 541 } 542 543 /* Unlock the Process */ 544 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); 545 KeLeaveCriticalRegion(); 546 547 /* Check if we had a previous thread to dereference */ 548 if (PreviousThread) ObDereferenceObject(PreviousThread); 549 550 /* Check if the process has a debug port and if this is a user thread */ 551 if ((CurrentProcess->DebugPort) && !(Thread->SystemThread)) 552 { 553 /* Notify the Debug API. */ 554 Last ? DbgkExitProcess(CurrentProcess->ExitStatus) : 555 DbgkExitThread(ExitStatus); 556 } 557 558 /* Check if this is a Critical Thread */ 559 if ((KdDebuggerEnabled) && (Thread->BreakOnTermination)) 560 { 561 /* Break to debugger */ 562 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n", 563 Thread, 564 CurrentProcess->ImageFileName); 565 } 566 567 /* Check if it's the last thread and this is a Critical Process */ 568 if ((Last) && (CurrentProcess->BreakOnTermination)) 569 { 570 /* Check if a debugger is here to handle this */ 571 if (KdDebuggerEnabled) 572 { 573 /* Break to debugger */ 574 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n", 575 CurrentProcess, 576 CurrentProcess->ImageFileName); 577 } 578 else 579 { 580 /* Bugcheck, we can't allow this */ 581 KEBUGCHECKEX(CRITICAL_PROCESS_DIED, 582 (ULONG_PTR)CurrentProcess, 583 0, 584 0, 585 0); 586 } 587 } 588 589 /* Sanity check */ 590 ASSERT(Thread->Tcb.CombinedApcDisable == 0); 591 592 /* Process the Termination Ports */ 593 TerminationPort = Thread->TerminationPort; 594 if (TerminationPort) 595 { 596 /* Setup the message header */ 597 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; 598 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); 599 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - 600 sizeof(PORT_MESSAGE); 601 602 /* Loop each port */ 603 do 604 { 605 /* Save the Create Time */ 606 TerminationMsg.CreateTime = Thread->CreateTime; 607 608 /* Loop trying to send message */ 609 while (TRUE) 610 { 611 /* Send the LPC Message */ 612 Status = LpcRequestPort(TerminationPort->Port, 613 &TerminationMsg.h); 614 if ((Status == STATUS_NO_MEMORY) || 615 (Status == STATUS_INSUFFICIENT_RESOURCES)) 616 { 617 /* Wait a bit and try again */ 618 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); 619 continue; 620 } 621 break; 622 } 623 624 /* Dereference this LPC Port */ 625 ObDereferenceObject(TerminationPort->Port); 626 627 /* Move to the next one */ 628 NextPort = TerminationPort->Next; 629 630 /* Free the Termination Port Object */ 631 ExFreePool(TerminationPort); 632 633 /* Keep looping as long as there is a port */ 634 TerminationPort = NextPort; 635 } while (TerminationPort); 636 } 637 else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) && 638 (Thread->DeadThread)) || 639 !(Thread->DeadThread)) 640 { 641 /* 642 * This case is special and deserves some extra comments. What 643 * basically happens here is that this thread doesn't have a termination 644 * port, which means that it died before being fully created. Since we 645 * still have to notify an LPC Server, we'll use the exception port, 646 * which we know exists. However, we need to know how far the thread 647 * actually got created. We have three possibilites: 648 * 649 * - NtCreateThread returned an error really early: DeadThread is set. 650 * - NtCreateThread managed to create the thread: DeadThread is off. 651 * - NtCreateThread was creating the thread (with Deadthread set, 652 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING 653 * is our exit code.) 654 * 655 * For the 2 & 3rd scenarios, the thread has been created far enough to 656 * warrant notification to the LPC Server. 657 */ 658 659 /* Setup the message header */ 660 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; 661 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); 662 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - 663 sizeof(PORT_MESSAGE); 664 665 /* Make sure the process has an exception port */ 666 if (CurrentProcess->ExceptionPort) 667 { 668 /* Save the Create Time */ 669 TerminationMsg.CreateTime = Thread->CreateTime; 670 671 /* Loop trying to send message */ 672 while (TRUE) 673 { 674 /* Send the LPC Message */ 675 Status = LpcRequestPort(CurrentProcess->ExceptionPort, 676 &TerminationMsg.h); 677 if ((Status == STATUS_NO_MEMORY) || 678 (Status == STATUS_INSUFFICIENT_RESOURCES)) 679 { 680 /* Wait a bit and try again */ 681 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); 682 continue; 683 } 684 break; 685 } 686 } 687 } 688 689 /* Rundown Win32 Thread if there is one */ 690 if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread, 691 PsW32ThreadCalloutExit); 692 693 /* If we are the last thread and have a W32 Process */ 694 if ((Last) && (CurrentProcess->Win32Process)) 695 { 696 /* Run it down too */ 697 PspW32ProcessCallout(CurrentProcess, FALSE); 698 } 699 700 /* Make sure Stack Swap isn't enabled */ 701 if (Thread->Tcb.EnableStackSwap) 702 { 703 /* Stack swap really shouldn't be on during exit !*/ 704 KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0); 705 } 706 707 /* Cancel I/O for the thread. */ 708 IoCancelThreadIo(Thread); 709 710 /* Rundown Timers */ 711 ExTimerRundown(); 712 713 /* FIXME: Rundown Registry Notifications (NtChangeNotify) 714 CmNotifyRunDown(Thread); */ 715 716 /* Rundown Mutexes */ 717 KeRundownThread(); 718 719 /* Check if we have a TEB */ 720 Teb = Thread->Tcb.Teb; 721 if (Teb) 722 { 723 /* Check if the thread is still alive */ 724 if (!Thread->DeadThread) 725 { 726 /* Check if we need to free its stack */ 727 if (Teb->FreeStackOnTermination) 728 { 729 /* Set the TEB's Deallocation Stack as the Base Address */ 730 Dummy = 0; 731 DeallocationStack = Teb->DeallocationStack; 732 733 /* Free the Thread's Stack */ 734 ZwFreeVirtualMemory(NtCurrentProcess(), 735 &DeallocationStack, 736 &Dummy, 737 MEM_RELEASE); 738 } 739 740 /* Free the debug handle */ 741 if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1], 742 UserMode); 743 } 744 745 /* Decommit the TEB */ 746 MmDeleteTeb(CurrentProcess, Teb); 747 Thread->Tcb.Teb = NULL; 748 } 749 750 /* Free LPC Data */ 751 LpcExitThread(Thread); 752 753 /* Save the exit status and exit time */ 754 Thread->ExitStatus = ExitStatus; 755 KeQuerySystemTime(&Thread->ExitTime); 756 757 /* Sanity check */ 758 ASSERT(Thread->Tcb.CombinedApcDisable == 0); 759 760 /* Check if this is the final thread or not */ 761 if (Last) 762 { 763 /* Set the process exit time */ 764 CurrentProcess->ExitTime = Thread->ExitTime; 765 766 /* Exit the process */ 767 PspExitProcess(TRUE, CurrentProcess); 768 769 /* Get the process token and check if we need to audit */ 770 PrimaryToken = PsReferencePrimaryToken(CurrentProcess); 771 if (SeDetailedAuditingWithToken(PrimaryToken)) 772 { 773 /* Audit the exit */ 774 SeAuditProcessExit(CurrentProcess); 775 } 776 777 /* Dereference the process token */ 778 ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken); 779 780 /* Check if this is a VDM Process and rundown the VDM DPCs if so */ 781 if (CurrentProcess->VdmObjects);// VdmRundownDpcs(CurrentProcess); 782 783 /* Kill the process in the Object Manager */ 784 ObKillProcess(CurrentProcess); 785 786 /* Check if we have a section object */ 787 if (CurrentProcess->SectionObject) 788 { 789 /* Dereference and clear the Section Object */ 790 ObDereferenceObject(CurrentProcess->SectionObject); 791 CurrentProcess->SectionObject = NULL; 792 } 793 794 /* Check if the process is part of a job */ 795 if (CurrentProcess->Job) 796 { 797 /* Remove the process from the job */ 798 PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess); 799 } 800 } 801 802 /* Disable APCs */ 803 KeEnterCriticalRegion(); 804 805 /* Disable APC queueing, force a resumption */ 806 Thread->Tcb.ApcQueueable = FALSE; 807 KeForceResumeThread(&Thread->Tcb); 808 809 /* Re-enable APCs */ 810 KeLeaveCriticalRegion(); 811 812 /* Flush the User APCs */ 813 FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode); 814 if (FirstEntry) 815 { 816 /* Start with the first entry */ 817 CurrentEntry = FirstEntry; 818 do 819 { 820 /* Get the APC */ 821 Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry); 822 823 /* Move to the next one */ 824 CurrentEntry = CurrentEntry->Flink; 825 826 /* Rundown the APC or de-allocate it */ 827 if (Apc->RundownRoutine) 828 { 829 /* Call its own routine */ 830 Apc->RundownRoutine(Apc); 831 } 832 else 833 { 834 /* Do it ourselves */ 835 ExFreePool(Apc); 836 } 837 } 838 while (CurrentEntry != FirstEntry); 839 } 840 841 /* Clean address space if this was the last thread */ 842 if (Last) MmCleanProcessAddressSpace(CurrentProcess); 843 844 /* Call the Lego routine */ 845 if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb); 846 847 /* Flush the APC queue, which should be empty */ 848 FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode); 849 if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0)) 850 { 851 /* Bugcheck time */ 852 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, 853 (ULONG_PTR)FirstEntry, 854 Thread->Tcb.CombinedApcDisable, 855 KeGetCurrentIrql(), 856 0); 857 } 858 859 /* Signal the process if this was the last thread */ 860 if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE); 861 862 /* Terminate the Thread from the Scheduler */ 863 KeTerminateThread(0); 864 } 865 866 VOID 867 NTAPI 868 PsExitSpecialApc(IN PKAPC Apc, 869 IN OUT PKNORMAL_ROUTINE* NormalRoutine, 870 IN OUT PVOID* NormalContext, 871 IN OUT PVOID* SystemArgument1, 872 IN OUT PVOID* SystemArgument2) 873 { 874 NTSTATUS Status; 875 PAGED_CODE(); 876 PSTRACE(PS_KILL_DEBUG, 877 "Apc: %p SystemArgument2: %p \n", Apc, SystemArgument2); 878 879 /* Don't do anything unless we are in User-Mode */ 880 if (Apc->SystemArgument2) 881 { 882 /* Free the APC */ 883 Status = (NTSTATUS)Apc->NormalContext; 884 PspExitApcRundown(Apc); 885 886 /* Terminate the Thread */ 887 PspExitThread(Status); 888 } 889 } 890 891 VOID 892 NTAPI 893 PspExitNormalApc(IN PVOID NormalContext, 894 IN PVOID SystemArgument1, 895 IN PVOID SystemArgument2) 896 { 897 PKAPC Apc = (PKAPC)SystemArgument1; 898 PETHREAD Thread = PsGetCurrentThread(); 899 PAGED_CODE(); 900 PSTRACE(PS_KILL_DEBUG, "SystemArgument2: %p \n", SystemArgument2); 901 902 /* This should never happen */ 903 ASSERT(!(((ULONG_PTR)SystemArgument2) & 1)); 904 905 /* If we're here, this is not a System Thread, so kill it from User-Mode */ 906 KeInitializeApc(Apc, 907 &Thread->Tcb, 908 OriginalApcEnvironment, 909 PsExitSpecialApc, 910 PspExitApcRundown, 911 PspExitNormalApc, 912 UserMode, 913 NormalContext); 914 915 /* Now insert the APC with the User-Mode Flag */ 916 if (!(KeInsertQueueApc(Apc, 917 Apc, 918 (PVOID)((ULONG_PTR)SystemArgument2 | 1), 919 2))) 920 { 921 /* Failed to insert, free the APC */ 922 PspExitApcRundown(Apc); 923 } 924 925 /* Set the APC Pending flag */ 926 Thread->Tcb.ApcState.UserApcPending = TRUE; 927 } 928 929 /* 930 * See "Windows Internals" - Chapter 13, Page 49 931 */ 932 NTSTATUS 933 NTAPI 934 PspTerminateThreadByPointer(IN PETHREAD Thread, 935 IN NTSTATUS ExitStatus, 936 IN BOOLEAN bSelf) 937 { 938 PKAPC Apc; 939 NTSTATUS Status = STATUS_SUCCESS; 940 ULONG Flags; 941 PAGED_CODE(); 942 PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %p\n", Thread, ExitStatus); 943 PSREFTRACE(Thread); 944 945 /* Check if this is a Critical Thread, and Bugcheck */ 946 if (Thread->BreakOnTermination) 947 { 948 /* Break to debugger */ 949 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n", 950 Thread, 951 Thread->ThreadsProcess->ImageFileName); 952 } 953 954 /* Check if we are already inside the thread */ 955 if ((bSelf) || (PsGetCurrentThread() == Thread)) 956 { 957 /* This should only happen at passive */ 958 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 959 960 /* Mark it as terminated */ 961 PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT); 962 963 /* Directly terminate the thread */ 964 PspExitThread(ExitStatus); 965 } 966 967 /* This shouldn't be a system thread */ 968 if (Thread->SystemThread) return STATUS_ACCESS_DENIED; 969 970 /* Allocate the APC */ 971 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); 972 973 /* Set the Terminated Flag */ 974 Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT; 975 976 /* Set it, and check if it was already set while we were running */ 977 if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) & 978 CT_TERMINATED_BIT)) 979 { 980 /* Initialize a Kernel Mode APC to Kill the Thread */ 981 KeInitializeApc(Apc, 982 &Thread->Tcb, 983 OriginalApcEnvironment, 984 PsExitSpecialApc, 985 PspExitApcRundown, 986 PspExitNormalApc, 987 KernelMode, 988 (PVOID)ExitStatus); 989 990 /* Insert it into the APC Queue */ 991 if (!KeInsertQueueApc(Apc, Apc, NULL, 2)) 992 { 993 /* The APC was already in the queue, fail */ 994 ExFreePool(Apc); 995 Status = STATUS_UNSUCCESSFUL; 996 } 997 else 998 { 999 /* Forcefully resume the thread and return */ 1000 KeForceResumeThread(&Thread->Tcb); 1001 return Status; 1002 } 1003 } 1004 1005 /* We failed, free the APC */ 1006 ExFreePool(Apc); 1007 1008 /* Return Status */ 1009 return Status; 1010 } 1011 1012 VOID 1013 NTAPI 1014 PspExitProcess(IN BOOLEAN LastThread, 1015 IN PEPROCESS Process) 1016 { 1017 ULONG Actual; 1018 PAGED_CODE(); 1019 PSTRACE(PS_KILL_DEBUG, 1020 "LastThread: %p Process: %p\n", LastThread, Process); 1021 PSREFTRACE(Process); 1022 1023 /* Set Process Exit flag */ 1024 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_EXITING_BIT); 1025 1026 /* Check if we are the last thread */ 1027 if (LastThread) 1028 { 1029 /* Notify the WMI Process Callback */ 1030 //WmiTraceProcess(Process, FALSE); 1031 1032 /* Run the Notification Routines */ 1033 PspRunCreateProcessNotifyRoutines(Process, FALSE); 1034 } 1035 1036 /* Cleanup the power state */ 1037 PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState); 1038 1039 /* Clear the security port */ 1040 if (!Process->SecurityPort) 1041 { 1042 /* So we don't double-dereference */ 1043 Process->SecurityPort = (PVOID)1; 1044 } 1045 else if (Process->SecurityPort != (PVOID)1) 1046 { 1047 /* Dereference it */ 1048 ObDereferenceObject(Process->SecurityPort); 1049 Process->SecurityPort = (PVOID)1; 1050 } 1051 1052 /* Check if we are the last thread */ 1053 if (LastThread) 1054 { 1055 /* Check if we have to set the Timer Resolution */ 1056 if (Process->SetTimerResolution) 1057 { 1058 /* Set it to default */ 1059 ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual); 1060 } 1061 1062 /* Check if we are part of a Job that has a completion port */ 1063 if ((Process->Job) && (Process->Job->CompletionPort)) 1064 { 1065 /* FIXME: Check job status code and do I/O completion if needed */ 1066 } 1067 1068 /* FIXME: Notify the Prefetcher */ 1069 } 1070 else 1071 { 1072 /* Clear process' address space here */ 1073 MmCleanProcessAddressSpace(Process); 1074 } 1075 } 1076 1077 /* PUBLIC FUNCTIONS **********************************************************/ 1078 1079 /* 1080 * @implemented 1081 */ 1082 NTSTATUS 1083 NTAPI 1084 PsTerminateSystemThread(IN NTSTATUS ExitStatus) 1085 { 1086 PETHREAD Thread = PsGetCurrentThread(); 1087 1088 /* Make sure this is a system thread */ 1089 if (Thread->SystemThread) return STATUS_INVALID_PARAMETER; 1090 1091 /* Terminate it for real */ 1092 return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE); 1093 } 1094 1095 /* 1096 * @implemented 1097 */ 1098 NTSTATUS 1099 NTAPI 1100 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, 1101 IN NTSTATUS ExitStatus) 1102 { 1103 NTSTATUS Status; 1104 PEPROCESS Process, CurrentProcess = PsGetCurrentProcess(); 1105 PETHREAD Thread, CurrentThread = PsGetCurrentThread(); 1106 BOOLEAN KillByHandle; 1107 PAGED_CODE(); 1108 PSTRACE(PS_KILL_DEBUG, 1109 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle, ExitStatus); 1110 1111 /* Were we passed a process handle? */ 1112 if (ProcessHandle) 1113 { 1114 /* Yes we were, use it */ 1115 KillByHandle = TRUE; 1116 } 1117 else 1118 { 1119 /* We weren't... we assume this is suicide */ 1120 KillByHandle = FALSE; 1121 ProcessHandle = NtCurrentProcess(); 1122 } 1123 1124 /* Get the Process Object */ 1125 Status = ObReferenceObjectByHandle(ProcessHandle, 1126 PROCESS_TERMINATE, 1127 PsProcessType, 1128 KeGetPreviousMode(), 1129 (PVOID*)&Process, 1130 NULL); 1131 if (!NT_SUCCESS(Status)) return(Status); 1132 1133 /* Check if this is a Critical Process, and Bugcheck */ 1134 if (Process->BreakOnTermination) 1135 { 1136 /* Break to debugger */ 1137 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", 1138 Process, 1139 Process->ImageFileName); 1140 } 1141 1142 /* Lock the Process */ 1143 if (!ExAcquireRundownProtection(&Process->RundownProtect)) 1144 { 1145 /* Failed to lock, fal */ 1146 ObDereferenceObject (Process); 1147 return STATUS_PROCESS_IS_TERMINATING; 1148 } 1149 1150 /* Set the delete flag, unless the process is comitting suicide */ 1151 if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT); 1152 1153 /* Get the first thread */ 1154 Status = STATUS_NOTHING_TO_TERMINATE; 1155 Thread = PsGetNextProcessThread(Process, NULL); 1156 if (Thread) 1157 { 1158 /* We know we have at least a thread */ 1159 Status = STATUS_SUCCESS; 1160 1161 /* Loop and kill the others */ 1162 do 1163 { 1164 /* Ensure it's not ours*/ 1165 if (Thread != CurrentThread) 1166 { 1167 /* Kill it */ 1168 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 1169 } 1170 1171 /* Move to the next thread */ 1172 Thread = PsGetNextProcessThread(Process, Thread); 1173 } while (Thread); 1174 } 1175 1176 /* Unlock the process */ 1177 ExReleaseRundownProtection(&Process->RundownProtect); 1178 1179 /* Check if we are killing ourselves */ 1180 if (Process == CurrentProcess) 1181 { 1182 /* Also make sure the caller gave us our handle */ 1183 if (KillByHandle) 1184 { 1185 /* Dereference the project */ 1186 ObDereferenceObject(Process); 1187 1188 /* Terminate ourselves */ 1189 PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE); 1190 } 1191 } 1192 else if (ExitStatus == DBG_TERMINATE_PROCESS) 1193 { 1194 /* Disable debugging on this process */ 1195 DbgkClearProcessDebugObject(Process, NULL); 1196 } 1197 1198 /* Check if there was nothing to terminate, or if we have a Debug Port */ 1199 if ((Status == STATUS_NOTHING_TO_TERMINATE) || 1200 ((Process->DebugPort) && (KillByHandle))) 1201 { 1202 /* Clear the handle table */ 1203 ObClearProcessHandleTable(Process); 1204 1205 /* Return status now */ 1206 Status = STATUS_SUCCESS; 1207 } 1208 1209 /* Decrease the reference count we added */ 1210 ObDereferenceObject(Process); 1211 1212 /* Return status */ 1213 return Status; 1214 } 1215 1216 NTSTATUS 1217 NTAPI 1218 NtTerminateThread(IN HANDLE ThreadHandle, 1219 IN NTSTATUS ExitStatus) 1220 { 1221 PETHREAD Thread; 1222 PETHREAD CurrentThread = PsGetCurrentThread(); 1223 NTSTATUS Status; 1224 PAGED_CODE(); 1225 PSTRACE(PS_KILL_DEBUG, 1226 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle, ExitStatus); 1227 1228 /* Handle the special NULL case */ 1229 if (!ThreadHandle) 1230 { 1231 /* Check if we're the only thread left */ 1232 if (PsGetCurrentProcess()->ActiveThreads == 1) 1233 { 1234 /* This is invalid */ 1235 return STATUS_CANT_TERMINATE_SELF; 1236 } 1237 1238 /* Terminate us directly */ 1239 goto TerminateSelf; 1240 } 1241 else if (ThreadHandle == NtCurrentThread()) 1242 { 1243 TerminateSelf: 1244 /* Terminate this thread */ 1245 return PspTerminateThreadByPointer(CurrentThread, 1246 ExitStatus, 1247 TRUE); 1248 } 1249 1250 /* We are terminating another thread, get the Thread Object */ 1251 Status = ObReferenceObjectByHandle(ThreadHandle, 1252 THREAD_TERMINATE, 1253 PsThreadType, 1254 KeGetPreviousMode(), 1255 (PVOID*)&Thread, 1256 NULL); 1257 if (!NT_SUCCESS(Status)) return Status; 1258 1259 /* Check to see if we're running in the same thread */ 1260 if (Thread != CurrentThread) 1261 { 1262 /* Terminate it */ 1263 Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 1264 1265 /* Dereference the Thread and return */ 1266 ObDereferenceObject(Thread); 1267 } 1268 else 1269 { 1270 /* Dereference the thread and terminate ourselves */ 1271 ObDereferenceObject(Thread); 1272 goto TerminateSelf; 1273 } 1274 1275 /* Return status */ 1276 return Status; 1277 } 1278 1279 NTSTATUS 1280 NTAPI 1281 NtRegisterThreadTerminatePort(IN HANDLE PortHandle) 1282 { 1283 NTSTATUS Status; 1284 PTERMINATION_PORT TerminationPort; 1285 PVOID TerminationLpcPort; 1286 PETHREAD Thread; 1287 PAGED_CODE(); 1288 PSTRACE(PS_KILL_DEBUG, "PortHandle: %p\n", PortHandle); 1289 1290 /* Get the Port */ 1291 Status = ObReferenceObjectByHandle(PortHandle, 1292 PORT_ALL_ACCESS, 1293 LpcPortObjectType, 1294 KeGetPreviousMode(), 1295 &TerminationLpcPort, 1296 NULL); 1297 if (!NT_SUCCESS(Status)) return(Status); 1298 1299 /* Allocate the Port and make sure it suceeded */ 1300 TerminationPort = ExAllocatePoolWithTag(NonPagedPool, 1301 sizeof(TERMINATION_PORT), 1302 TAG('P', 's', 'T', '=')); 1303 if(TerminationPort) 1304 { 1305 /* Associate the Port */ 1306 Thread = PsGetCurrentThread(); 1307 TerminationPort->Port = TerminationLpcPort; 1308 TerminationPort->Next = Thread->TerminationPort; 1309 Thread->TerminationPort = TerminationPort; 1310 1311 /* Return success */ 1312 return STATUS_SUCCESS; 1313 } 1314 1315 /* Dereference and Fail */ 1316 ObDereferenceObject(TerminationPort); 1317 return STATUS_INSUFFICIENT_RESOURCES; 1318 } 1319