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