NTSTATUS NTAPI PsSuspendProcess(IN PEPROCESS Process) { PETHREAD Thread; PAGED_CODE(); /* Lock the Process */ if (!ExAcquireRundownProtection(&Process->RundownProtect)) { /* Process is terminating */ return STATUS_PROCESS_IS_TERMINATING; } /* Get the first thread */ Thread = PsGetNextProcessThread(Process, NULL); while (Thread) { /* Resume it */ PsSuspendThread(Thread, NULL); /* Move to the next thread */ Thread = PsGetNextProcessThread(Process, Thread); } /* Unlock the process */ ExReleaseRundownProtection(&Process->RundownProtect); return STATUS_SUCCESS; }
VOID NTAPI ExSwapinWorkerThreads(IN BOOLEAN AllowSwap) { KEVENT Event; PETHREAD CurrentThread = PsGetCurrentThread(), Thread; PEPROCESS Process = PsInitialSystemProcess; KAPC Apc; PAGED_CODE(); /* Initialize an event so we know when we're done */ KeInitializeEvent(&Event, NotificationEvent, FALSE); /* Lock this routine */ ExAcquireFastMutex(&ExpWorkerSwapinMutex); /* New threads cannot swap anymore */ ExpWorkersCanSwap = AllowSwap; /* Loop all threads in the system process */ Thread = PsGetNextProcessThread(Process, NULL); while (Thread) { /* Skip threads with explicit permission to do this */ if (Thread->ExWorkerCanWaitUser) goto Next; /* Check if we reached ourselves */ if (Thread == CurrentThread) { /* Do it inline */ KeSetKernelStackSwapEnable(AllowSwap); } else { /* Queue an APC */ KeInitializeApc(&Apc, &Thread->Tcb, InsertApcEnvironment, ExpSetSwappingKernelApc, NULL, NULL, KernelMode, &AllowSwap); if (KeInsertQueueApc(&Apc, &Event, NULL, 3)) { /* Wait for the APC to run */ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); KeClearEvent(&Event); } } /* Next thread */ Next: Thread = PsGetNextProcessThread(Process, Thread); } /* Release the lock */ ExReleaseFastMutex(&ExpWorkerSwapinMutex); }
NTSTATUS NTAPI PspTerminateProcess(IN PEPROCESS Process, IN NTSTATUS ExitStatus) { PETHREAD Thread; NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE; PAGED_CODE(); PSTRACE(PS_KILL_DEBUG, "Process: %p ExitStatus: %d\n", Process, ExitStatus); PSREFTRACE(Process); /* Check if this is a Critical Process */ if (Process->BreakOnTermination) { /* Break to debugger */ PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", Process, Process->ImageFileName); } /* Set the delete flag */ InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT); /* Get the first thread */ Thread = PsGetNextProcessThread(Process, NULL); while (Thread) { /* Kill it */ PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); Thread = PsGetNextProcessThread(Process, Thread); /* We had at least one thread, so termination is OK */ Status = STATUS_SUCCESS; } /* Check if there was nothing to terminate or if we have a debug port */ if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort)) { /* Clear the handle table anyway */ ObClearProcessHandleTable(Process); } /* Return status */ return Status; }
/* * @implemented */ NTSTATUS NTAPI NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus) { NTSTATUS Status; PEPROCESS Process, CurrentProcess = PsGetCurrentProcess(); PETHREAD Thread, CurrentThread = PsGetCurrentThread(); BOOLEAN KillByHandle; PAGED_CODE(); PSTRACE(PS_KILL_DEBUG, "ProcessHandle: %p ExitStatus: %d\n", ProcessHandle, ExitStatus); /* Were we passed a process handle? */ if (ProcessHandle) { /* Yes we were, use it */ KillByHandle = TRUE; } else { /* We weren't... we assume this is suicide */ KillByHandle = FALSE; ProcessHandle = NtCurrentProcess(); } /* Get the Process Object */ Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_TERMINATE, PsProcessType, KeGetPreviousMode(), (PVOID*)&Process, NULL); if (!NT_SUCCESS(Status)) return(Status); /* Check if this is a Critical Process, and Bugcheck */ if (Process->BreakOnTermination) { /* Break to debugger */ PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", Process, Process->ImageFileName); } /* Lock the Process */ if (!ExAcquireRundownProtection(&Process->RundownProtect)) { /* Failed to lock, fail */ ObDereferenceObject(Process); return STATUS_PROCESS_IS_TERMINATING; } /* Set the delete flag, unless the process is comitting suicide */ if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT); /* Get the first thread */ Status = STATUS_NOTHING_TO_TERMINATE; Thread = PsGetNextProcessThread(Process, NULL); if (Thread) { /* We know we have at least a thread */ Status = STATUS_SUCCESS; /* Loop and kill the others */ do { /* Ensure it's not ours*/ if (Thread != CurrentThread) { /* Kill it */ PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); } /* Move to the next thread */ Thread = PsGetNextProcessThread(Process, Thread); } while (Thread); } /* Unlock the process */ ExReleaseRundownProtection(&Process->RundownProtect); /* Check if we are killing ourselves */ if (Process == CurrentProcess) { /* Also make sure the caller gave us our handle */ if (KillByHandle) { /* Dereference the process */ ObDereferenceObject(Process); /* Terminate ourselves */ PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE); } } else if (ExitStatus == DBG_TERMINATE_PROCESS) { /* Disable debugging on this process */ DbgkClearProcessDebugObject(Process, NULL); } /* Check if there was nothing to terminate, or if we have a Debug Port */ if ((Status == STATUS_NOTHING_TO_TERMINATE) || ((Process->DebugPort) && (KillByHandle))) { /* Clear the handle table */ ObClearProcessHandleTable(Process); /* Return status now */ Status = STATUS_SUCCESS; } /* Decrease the reference count we added */ ObDereferenceObject(Process); /* Return status */ return Status; }
VOID ExSwapinWorkerThreads ( IN BOOLEAN AllowSwap ) /*++ Routine Description: Sets the kernel stacks of the delayed worker threads to be swappable or pins them into memory. Arguments: AllowSwap - Supplies TRUE if worker kernel stacks should be swappable, FALSE if not. Return Value: None. --*/ { PETHREAD Thread; PETHREAD CurrentThread; PEPROCESS Process; KAPC Apc; KEVENT SwapSetEvent; PAGED_CODE(); CurrentThread = PsGetCurrentThread(); KeInitializeEvent (&SwapSetEvent, NotificationEvent, FALSE); Process = PsInitialSystemProcess; // // Serialize callers. // ExAcquireFastMutex (&ExpWorkerSwapinMutex); // // Stop new threads from swapping. // ExpWorkersCanSwap = AllowSwap; // // Stop existing worker threads from swapping. // for (Thread = PsGetNextProcessThread (Process, NULL); Thread != NULL; Thread = PsGetNextProcessThread (Process, Thread)) { // // Skip threads that are not worker threads or worker threads that // were permanently marked noswap at creation time. // if (Thread->ExWorkerCanWaitUser == 0) { continue; } if (Thread == CurrentThread) { // // No need to use an APC on the current thread. // KeSetKernelStackSwapEnable (AllowSwap); } else { // // Queue an APC to the thread, and wait for it to fire: // KeInitializeApc (&Apc, &Thread->Tcb, InsertApcEnvironment, ExpSetSwappingKernelApc, NULL, NULL, KernelMode, &AllowSwap); if (KeInsertQueueApc (&Apc, &SwapSetEvent, NULL, 3)) { KeWaitForSingleObject (&SwapSetEvent, Executive, KernelMode, FALSE, NULL); KeClearEvent(&SwapSetEvent); } } } ExReleaseFastMutex (&ExpWorkerSwapinMutex); }