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