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