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
PspCatchCriticalBreak(IN PCHAR Message,IN PVOID ProcessOrThread,IN PCHAR ImageName)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
PspTerminateProcess(IN PEPROCESS Process,IN NTSTATUS ExitStatus)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
PsTerminateProcess(IN PEPROCESS Process,IN NTSTATUS ExitStatus)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
PspShutdownProcessManager(VOID)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
PspExitApcRundown(IN PKAPC Apc)157 PspExitApcRundown(IN PKAPC Apc)
158 {
159 PAGED_CODE();
160
161 /* Free the APC */
162 ExFreePool(Apc);
163 }
164
165 VOID
166 NTAPI
PspReapRoutine(IN PVOID Context)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
PspCheckProcessList(VOID)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
PspDeleteProcess(IN PVOID ObjectBody)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
PspDeleteThread(IN PVOID ObjectBody)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
PspExitThread(IN NTSTATUS ExitStatus)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
PsExitSpecialApc(IN PKAPC Apc,IN OUT PKNORMAL_ROUTINE * NormalRoutine,IN OUT PVOID * NormalContext,IN OUT PVOID * SystemArgument1,IN OUT PVOID * SystemArgument2)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
PspExitNormalApc(IN PVOID NormalContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)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
PspTerminateThreadByPointer(IN PETHREAD Thread,IN NTSTATUS ExitStatus,IN BOOLEAN bSelf)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
PspIsProcessExiting(IN PEPROCESS Process)1068 PspIsProcessExiting(IN PEPROCESS Process)
1069 {
1070 return Process->Flags & PSF_PROCESS_EXITING_BIT;
1071 }
1072
1073 VOID
1074 NTAPI
PspExitProcess(IN BOOLEAN LastThread,IN PEPROCESS Process)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
PsTerminateSystemThread(IN NTSTATUS ExitStatus)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
NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,IN NTSTATUS ExitStatus)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
NtTerminateThread(IN HANDLE ThreadHandle,IN NTSTATUS ExitStatus)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
NtRegisterThreadTerminatePort(IN HANDLE PortHandle)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