Additional notes on controlling which handles are inherited by Create­Process

The Old New Thing (Raymond Chen) Tools

Summary

Raymond Chen describes a technique using a helper process to precisely control which handles are inherited by a new process, avoiding accidental inheritance from other components in the same process.

<p>Some time ago, I wrote about <a title="Programmatically controlling which handles are inherited by new processes in Win32" href="https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873"> programmatically controlling which handles are inherited by new processes in Win32</a> by using the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> to limit exactly which handles are inherited. That way, when you create a new process, you have precise control over which handles get inherited and don&#8217;t accidentally inherit handles created by unrelated components in your process.</p> <p>A collegue of mine pointed out that you still have the reverse problem: Since handles must be marked as inheritable for them to participate in <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>, if another thread calls <code>Create­Process</code> with <code>bInheritHandles</code> = <code>TRUE</code> but without using <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>, then they will accidentally inherit all of <i>your</i> handles.</p> <p>This problem could have been avoided if the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> allowed you to include non-inheritable handles, in which case they would be non-inheritable by normal <code>Create­Process</code> but inheritable if explicitly opted back in. But alas, that&#8217;s not how it was designed.</p> <p>Instead, you can create a helper process. All this helper process does is wait for the main process to exit, and then exit itself.</p> <pre>WaitForSingleObject(hMainProcess, INFINITE); ExitProcess(0); </pre> <p>This process doesn&#8217;t sound like it&#8217;s doing anything useful, and it&#8217;s not. But what makes it useful is not what it&#8217;s doing but rather what is done <i>to</i> it.</p> <p>The components in the main process create their handles as non-inheritable. When they wants to create a process with specific inherited handles, they duplicate the desired handles into the helper process (as inheritable), and then build a <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> that lists those duplicates as handles to inherit. They also use the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />PARENT_<wbr />PROCESS</code> to specify that the <i>helper</i> process is the parent process that the handles should be inherited from. Then they pass those thread attributes to <code>Create­Process</code>, and the new process will inherit exactly those handles. Then they clean up by closing the handles in the helper process with the help of <code>Duplicate­Handle</code> and <code>DUPLICATE_<wbr />CLOSE_<wbr />SOURCE</code>.</p> <p>Notice that multiple threads can simultaneously be operating on the helper process in this way, so you need only one helper process to service all your handle-inheritance-control needs.</p> <p>This avoids the accidental inheritance problem because the handles that belong to the components in the main process are still marked non-inheritable, so any other code in the main process that does a <code>Create­Process</code> will not inherit them.</p> <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260511-00/?p=112313">Additional notes on controlling which handles are inherited by &lt;CODE&gt;Create&shy;Process&lt;/CODE&gt;</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
Original Article
View Cached Full Text

Cached at: 05/16/26, 03:31 AM

# Additional notes on controlling which handles are inherited by Create­Process - The Old New Thing Source: [https://devblogs.microsoft.com/oldnewthing/20260511-00?p=112313](https://devblogs.microsoft.com/oldnewthing/20260511-00?p=112313) Some time ago, I wrote about[programmatically controlling which handles are inherited by new processes in Win32](https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873)by using the`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`to limit exactly which handles are inherited\. That way, when you create a new process, you have precise control over which handles get inherited and don’t accidentally inherit handles created by unrelated components in your process\. A collegue of mine pointed out that you still have the reverse problem: Since handles must be marked as inheritable for them to participate in`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`, if another thread calls`Create­Process`with`bInheritHandles`=`TRUE`but without using`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`, then they will accidentally inherit all of*your*handles\. This problem could have been avoided if the`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`allowed you to include non\-inheritable handles, in which case they would be non\-inheritable by normal`Create­Process`but inheritable if explicitly opted back in\. But alas, that’s not how it was designed\. Instead, you can create a helper process\. All this helper process does is wait for the main process to exit, and then exit itself\. ``` WaitForSingleObject(hMainProcess, INFINITE); ExitProcess(0); ``` This process doesn’t sound like it’s doing anything useful, and it’s not\. But what makes it useful is not what it’s doing but rather what is done*to*it\. The components in the main process create their handles as non\-inheritable\. When they wants to create a process with specific inherited handles, they duplicate the desired handles into the helper process \(as inheritable\), and then build a`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`that lists those duplicates as handles to inherit\. They also use the`PROC\_THREAD\_ATTRIBUTE\_PARENT\_PROCESS`to specify that the*helper*process is the parent process that the handles should be inherited from\. Then they pass those thread attributes to`Create­Process`, and the new process will inherit exactly those handles\. Then they clean up by closing the handles in the helper process with the help of`Duplicate­Handle`and`DUPLICATE\_CLOSE\_SOURCE`\. Notice that multiple threads can simultaneously be operating on the helper process in this way, so you need only one helper process to service all your handle\-inheritance\-control needs\. This avoids the accidental inheritance problem because the handles that belong to the components in the main process are still marked non\-inheritable, so any other code in the main process that does a`Create­Process`will not inherit them\. ### Category ### Topics ## Author ![Raymond Chen](https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2019/02/RaymondChen_5in-150x150.jpg) Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.

Similar Articles

Understanding the rationale behind a rule when trying to circumvent it

The Old New Thing (Raymond Chen)

This article from Microsoft's Old New Thing blog explains the rationale behind best practices for Windows kernel callback functions, particularly why blocking or waiting on work items defeats their purpose, using a cautionary tale about drivers causing system hangs.

Why not have changes in API behavior depend on the SDK you link against?

The Old New Thing (Raymond Chen)

The article examines the pitfalls of altering API behavior depending on the linked SDK version, using Windows' CoInitializeSecurity as a case study. It discusses issues with DLL version mismatches and tail call optimization that complicate this approach.

Moving beyond fork() + exec()

Lobsters Hottest

A proposal to add spawn templates to the Linux kernel aims to optimize the fork+exec pattern by caching executable information, though the current patch set is unlikely to be accepted as-is.