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