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