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