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