{"id":8873,"date":"2011-12-16T07:00:00","date_gmt":"2011-12-16T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/12\/16\/programmatically-controlling-which-handles-are-inherited-by-new-processes-in-win32\/"},"modified":"2011-12-16T07:00:00","modified_gmt":"2011-12-16T07:00:00","slug":"programmatically-controlling-which-handles-are-inherited-by-new-processes-in-win32","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20111216-00\/?p=8873","title":{"rendered":"Programmatically controlling which handles are inherited by new processes in Win32"},"content":{"rendered":"<p>\nIn unix, file descriptors are inherited by child processes by default.\nThis wasn&#8217;t so much an active decision as it was a consequence\nof the fork\/exec model.\nTo exclude a file descriptor from being inherited by children,\nyou set the <code>FD_CLO&shy;EXEC<\/code> flag on the file descriptor.\n<\/p>\n<p>\nWin32 sort of works like that, but backwards, and maybe a little\nupside-down.\n<a HREF=\"http:\/\/www.gingerrogers.com\/about\/quotes.html\">\nAnd in high heels<\/a>.\n<\/p>\n<p>\nIn Win32, handles default to <i>not inherited<\/i>.\nWays to make a handle inherited during\n<code>Create&shy;Process<\/code>\nhave grown during the evolution of Win32.\n<\/p>\n<p>\nAs far as I can tell, back in the old days,\ninheritability of handles was established at handle creation time.\nFor most handle creation functions, you do this by passing\na <code>SECURITY_ATTRIBUTES<\/code> structure\nwith <code>bInherit&shy;Handle<\/code> set\nto <code>TRUE<\/code>.\nFunctions which created handles from existing objects don&#8217;t have\na <code>SECURITY_ATTRIBUTES<\/code> parameter,\nso they instead have an explicit <code>bInherit&shy;Handle<\/code>\nparameter.\n(For examples, see\n<code>Open&shy;Event<\/code> and <code>Duplicate&shy;Handle<\/code>.)\n<\/p>\n<p>\nBut just marking a handle as inheritable isn&#8217;t good enough to get\nit inherited.\nYou also have to pass\n<code>TRUE<\/code>\nas the\n<code>bInherit&shy;Handles<\/code> parameter to <code>Create&shy;Process<\/code>.\nA handle will be inherited only if\nif the <code>bInherit&shy;Handles<\/code> parameter is\n<code>TRUE<\/code> <u>and<\/u> the handle is marked as inheritable.\nMiss either of those steps, and you don&#8217;t get your inheritance.\n(To make sure you get your inheritance IRL, be nice to your grandmother.)\n<\/p>\n<p>\nIn Windows&nbsp;2000,\nWin32 gained the ability to alter the inheritability of a handle\nafter it is created.\nThe\n<code>Set&shy;Handle&shy;Information<\/code> function\nlets you turn the <code>HANDLE_FLAG_INHERIT<\/code>\nflag on and off on a handle.\n<\/p>\n<p>\nBut all this inheritability fiddling still had a fatal flaw:\nWhat if two threads within the same process both call\n<code>Create&shy;Process<\/code> but disagree on which handles\nthey want to be inherited?\nFor example, suppose you have a function\n<code>Create&shy;Process&shy;With&shy;Shared&shy;Memory<\/code>\nwhose job it is to\nlaunch a process, passing it\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/12\/11\/56043.aspx\">\na custom-made shared memory block<\/a>.\nSuppose two threads run this function simultaneously.\n<\/p>\n<table CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<th>A<\/th>\n<td STYLE=\"border-left: .75pt solid black;width: .75pt\" ROWSPAN=\"5\">&nbsp;<\/td>\n<th>B<\/th>\n<\/tr>\n<tr>\n<td>CreateFileMapping(inheritable=TRUE)<\/td>\n<td>CreateFileMapping(inheritable=TRUE)<\/td>\n<\/tr>\n<tr>\n<td>returns handle H1<\/td>\n<td>returns handle H2<\/td>\n<\/tr>\n<tr>\n<td>CreateProcess(&#8220;A&#8221;, bInheritHandles=TRUE)<\/td>\n<td>CreateProcess(&#8220;B&#8221;, bInheritHandles=TRUE)<\/td>\n<\/tr>\n<tr>\n<td>CloseHandle(H1)<\/td>\n<td>CloseHandle(H2)<\/td>\n<\/tr>\n<\/table>\n<p>\nWhat just happened?\nSince inheritability is a property of the handle,\nprocesses A&nbsp;and&nbsp;B inherited <i>both<\/i> handles\nH1&nbsp;and&nbsp;H2, even though what we wanted was\nfor process&nbsp;A to inherit handle&nbsp;H1 and\nfor process&nbsp;B to inherit handle&nbsp;H2.\n<\/p>\n<p>\nFor a long time, the answer to this problem was the unsatisfactory\n&#8220;You&#8217;ll just have to serialize your calls to\n<code>Create&shy;Process&shy;With&shy;Shared&shy;Memory<\/code>\nso that thread&nbsp;B won&#8217;t accidentally cause a handle from\nthread&nbsp;A to be inherited by process&nbsp;B.&#8221;\nActually, the answer was even worse.\nYou had to serialize all functions that created inheritable\nhandles from the time the handle was created,\nthrough the call to\n<code>Create&shy;Process<\/code>,\nand waiting until after all those inheritable handles were made\nno longer inheritable.\n<\/p>\n<p>\nThis was a serious problem since who knows what other parts of\nyour program are going to call <code>Create&shy;Process<\/code>\nwith <code>bInherit&shy;Handles<\/code> set to <code>TRUE<\/code>?\nSure you can control the calls that your own code made,\nbut what about calls from plug-ins or other unknown components?\n(This is\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/05\/02\/2365433.aspx\">\nanother case<\/a> of\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/05\/12\/10163578.aspx\">\nkernel-colored glasses<\/a>.)\n<\/p>\n<p>\nWindows&nbsp;Vista addresses this problem by allowing you to\npass an explicit list of handles you want the\n<code>bInherit&shy;Handles<\/code> parameter to apply to.\n(If you pass an explicit list, then you must pass\n<code>TRUE<\/code> for <code>bInherit&shy;Handles<\/code>.)\nAnd as before, for a handle to be inherited, it must be\nalso be marked as inheritable.\n<\/p>\n<p>\nPassing the list of handles you want to inherit is a multi-step\naffair.\nLet&#8217;s walk through it:\n<\/p>\n<pre>\nBOOL CreateProcessWithExplicitHandles(\n  __in_opt     LPCTSTR lpApplicationName,\n  __inout_opt  LPTSTR lpCommandLine,\n  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,\n  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,\n  __in         BOOL bInheritHandles,\n  __in         DWORD dwCreationFlags,\n  __in_opt     LPVOID lpEnvironment,\n  __in_opt     LPCTSTR lpCurrentDirectory,\n  __in         LPSTARTUPINFO lpStartupInfo,\n  __out        LPPROCESS_INFORMATION lpProcessInformation,\n    \/\/ here is the new stuff\n  __in         DWORD cHandlesToInherit,\n  __in_ecount(cHandlesToInherit) HANDLE *rgHandlesToInherit)\n{\n BOOL fSuccess;\n BOOL fInitialized = FALSE;\n SIZE_T size = 0;\n LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;\n fSuccess = cHandlesToInherit &lt; 0xFFFFFFFF \/ sizeof(HANDLE) &amp;&amp;\n            lpStartupInfo-&gt;cb == sizeof(*lpStartupInfo);\n if (!fSuccess) {\n  SetLastError(ERROR_INVALID_PARAMETER);\n }\n if (fSuccess) {\n  fSuccess = InitializeProcThreadAttributeList(NULL, 1, 0, &amp;size) ||\n             GetLastError() == ERROR_INSUFFICIENT_BUFFER;\n }\n if (fSuccess) {\n  lpAttributeList = reinterpret_cast&lt;LPPROC_THREAD_ATTRIBUTE_LIST&gt;\n                                (HeapAlloc(GetProcessHeap(), 0, size));\n  fSuccess = lpAttributeList != NULL;\n }\n if (fSuccess) {\n  fSuccess = InitializeProcThreadAttributeList(lpAttributeList,\n                    1, 0, &amp;size);\n }\n if (fSuccess) {\n  fInitialized = TRUE;\n  fSuccess = UpdateProcThreadAttribute(lpAttributeList,\n                    0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,\n                    rgHandlesToInherit,\n                    cHandlesToInherit * sizeof(HANDLE), NULL, NULL);\n }\n if (fSuccess) {\n  STARTUPINFOEX info;\n  <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2005\/06\/28\/433341.aspx\">ZeroMemory<\/a>(&amp;info, sizeof(info));\n  info.StartupInfo = *lpStartupInfo;\n  info.StartupInfo.cb = sizeof(info);\n  info.lpAttributeList = lpAttributeList;\n  fSuccess = CreateProcess(lpApplicationName,\n                           lpCommandLine,\n                           lpProcessAttributes,\n                           lpThreadAttributes,\n                           bInheritHandles,\n                           dwCreationFlags | EXTENDED_STARTUPINFO_PRESENT,\n                           lpEnvironment,\n                           lpCurrentDirectory,\n                           &amp;info.StartupInfo,\n                           lpProcessInformation);\n }\n if (fInitialized) DeleteProcThreadAttributeList(lpAttributeList);\n if (lpAttributeList) HeapFree(GetProcessHeap(), 0, lpAttributeList);\n return fSuccess;\n}\n<\/pre>\n<p>\nAfter some initial sanity checks, we start doing real work.\n<\/p>\n<p>\nInitializing a <code>PROC_THREAD_ATTRIBUTE_LIST<\/code>\nis a two-step affair.\nFirst you call\n<code>Initialize&shy;Proc&shy;Thread&shy;Attribute&shy;List<\/code>\nwith a <code>NULL<\/code> attribute list in order to determine how\nmuch memory you need to allocate for a one-entry attribute list.\nAfter allocating the memory, you call\n<code>Initialize&shy;Proc&shy;Thread&shy;Attribute&shy;List<\/code>\na second time to do the actual initialization.\n<\/p>\n<p>\nAfter creating the attribute list, you set the one entry\nby calling\n<code>Update&shy;Proc&shy;Thread&shy;Attribute&shy;List<\/code>.\n<\/p>\n<p>\nAnd then it&#8217;s off to the races.\nPut that attribute list in a <code>STARTUP&shy;INFO&shy;EX<\/code>\nstructure, set the\n<code>EXTENDED_STARTUPINFO_PRESENT<\/code> flag,\nand hand everything off to <code>Create&shy;Process<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In unix, file descriptors are inherited by child processes by default. This wasn&#8217;t so much an active decision as it was a consequence of the fork\/exec model. To exclude a file descriptor from being inherited by children, you set the FD_CLO&shy;EXEC flag on the file descriptor. Win32 sort of works like that, but backwards, and [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-8873","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>In unix, file descriptors are inherited by child processes by default. This wasn&#8217;t so much an active decision as it was a consequence of the fork\/exec model. To exclude a file descriptor from being inherited by children, you set the FD_CLO&shy;EXEC flag on the file descriptor. Win32 sort of works like that, but backwards, and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/8873","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=8873"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/8873\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=8873"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=8873"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=8873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}