[Python-ideas] Add subprocess.Popen suspend() and resume()

eryk sun eryksun at gmail.com
Sun Mar 24 11:39:16 EDT 2019

On 3/24/19, Giampaolo Rodola' <g.rodola at gmail.com> wrote:
> On Wed, Mar 20, 2019 at 11:19 PM eryk sun <eryksun at gmail.com> wrote:
>> This code repeatedly calls PsGetNextProcessThread to walk the
>> non-terminated threads of the process in creation order (based on a
>> linked list in the process object) and suspends each thread via
>> PsSuspendThread. In contrast, a Tool-Help thread snapshot is
>> unreliable since it won't include threads created after the snapshot
>> is created. The alternative is to use a different undocumented system
>> call, NtGetNextThread [2], which is implemented via
>> PsGetNextProcessThread. But that's slightly worse than calling
>> NtSuspendProcess.
>> [1]: https://stackoverflow.com/a/11010508
>> [2]: https://github.com/processhacker/processhacker/blob/v2.39/
>>      phnt/include/ntpsapi.h#L848
> FWIW older psutil versions relied on Thread32Next / OpenThread /
> SuspendThread / ResumeThread, which appear similar to these Ps*
> counterparts (and I assume have the same drawbacks).

This is the toolhelp snapshot I was talking about, which is an
unreliable way to pause a process since it doesn't include threads
created after the snapshot. For TH32CS_SNAPTHREAD, it's based on
calling NtQuerySystemInformation: SystemProcessInformation to take a
snapshot of all running processes and threads at the time. This buffer
gets written to a shared section, and the section handle is returned
as the snapshot handle. Thread32First and Thread32Next are called to
walk the buffer a record at a time by temporarily mapping the section
with NtMapViewOfSection and NtUnmapViewOfSection.

In contrast, NtSuspendProcess is based on PsGetNextProcessThread,
which walks a linked list of the non-terminated threads in the
process. Unlike a snapshot, this won't miss threads created after we
start, since new threads are appended to the list. To implement this
in user mode with SuspendThread would require the NtGetNextThread
system call that's implemented via PsGetNextProcessThread. But that's
just trading one undocumented system call for another at the expense
of a more complicated implementation.

More information about the Python-ideas mailing list