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