python-peps/pep-0446/index.html

741 lines
55 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 446 Make newly created file descriptors non-inheritable | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0446/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 446 Make newly created file descriptors non-inheritable | peps.python.org'>
<meta property="og:description" content="Leaking file descriptors in child processes causes various annoying issues and is a known major security vulnerability. Using the subprocess module with the close_fds parameter set to True is not possible in all cases.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0446/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Leaking file descriptors in child processes causes various annoying issues and is a known major security vulnerability. Using the subprocess module with the close_fds parameter set to True is not possible in all cases.">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 446</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 446 Make newly created file descriptors non-inheritable</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Victor Stinner &lt;vstinner&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">05-Aug-2013</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.4</dd>
<dt class="field-even">Replaces<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../pep-0433/">433</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#inheritance-of-file-descriptors">Inheritance of File Descriptors</a></li>
<li><a class="reference internal" href="#inheritance-of-file-descriptors-on-windows">Inheritance of File Descriptors on Windows</a></li>
<li><a class="reference internal" href="#only-inherit-some-handles-on-windows">Only Inherit Some Handles on Windows</a></li>
<li><a class="reference internal" href="#inheritance-of-file-descriptors-on-unix">Inheritance of File Descriptors on UNIX</a></li>
<li><a class="reference internal" href="#issues-with-inheritable-file-descriptors">Issues with Inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#security-vulnerability">Security Vulnerability</a></li>
<li><a class="reference internal" href="#issues-fixed-in-the-subprocess-module">Issues fixed in the subprocess module</a></li>
<li><a class="reference internal" href="#atomic-creation-of-non-inheritable-file-descriptors">Atomic Creation of non-inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#status-of-python-3-3">Status of Python 3.3</a></li>
<li><a class="reference internal" href="#closing-all-open-file-descriptors">Closing All Open File Descriptors</a></li>
</ul>
</li>
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
<li><a class="reference internal" href="#non-inheritable-file-descriptors">Non-inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#new-functions-and-methods">New Functions And Methods</a></li>
<li><a class="reference internal" href="#other-changes">Other Changes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#related-work">Related Work</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul>
<li><a class="reference internal" href="#add-a-new-open-noinherit-function">Add a new open_noinherit() function</a></li>
<li><a class="reference internal" href="#pep-433">PEP 433</a></li>
</ul>
</li>
<li><a class="reference internal" href="#python-issues">Python Issues</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Leaking file descriptors in child processes causes various annoying
issues and is a known major security vulnerability. Using the
<code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module with the <em>close_fds</em> parameter set to <code class="docutils literal notranslate"><span class="pre">True</span></code> is
not possible in all cases.</p>
<p>This PEP proposes to make all file descriptors created by Python
non-inheritable by default to reduce the risk of these issues. This PEP
fixes also a race condition in multi-threaded applications on operating
systems supporting atomic flags to create non-inheritable file
descriptors.</p>
<p>We are aware of the code breakage this is likely to cause, and doing it
anyway for the good of mankind. (Details in the section “Backward
Compatibility” below.)</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<section id="inheritance-of-file-descriptors">
<h3><a class="toc-backref" href="#inheritance-of-file-descriptors" role="doc-backlink">Inheritance of File Descriptors</a></h3>
<p>Each operating system handles the inheritance of file descriptors
differently. Windows creates non-inheritable handles by default, whereas
UNIX and the POSIX API on Windows create inheritable file descriptors by
default. Python prefers the POSIX API over the native Windows API, to
have a single code base and to use the same type for file descriptors,
and so it creates inheritable file descriptors.</p>
<p>There is one exception: <code class="docutils literal notranslate"><span class="pre">os.pipe()</span></code> creates non-inheritable pipes on
Windows, whereas it creates inheritable pipes on UNIX. The reason is an
implementation artifact: <code class="docutils literal notranslate"><span class="pre">os.pipe()</span></code> calls <code class="docutils literal notranslate"><span class="pre">CreatePipe()</span></code> on Windows
(native API), whereas it calls <code class="docutils literal notranslate"><span class="pre">pipe()</span></code> on UNIX (POSIX API). The call
to <code class="docutils literal notranslate"><span class="pre">CreatePipe()</span></code> was added in Python in 1994, before the introduction
of <code class="docutils literal notranslate"><span class="pre">pipe()</span></code> in the POSIX API in Windows 98. The <a class="reference external" href="http://bugs.python.org/issue4708">issue #4708</a> proposes to change <code class="docutils literal notranslate"><span class="pre">os.pipe()</span></code> on
Windows to create inheritable pipes.</p>
</section>
<section id="inheritance-of-file-descriptors-on-windows">
<h3><a class="toc-backref" href="#inheritance-of-file-descriptors-on-windows" role="doc-backlink">Inheritance of File Descriptors on Windows</a></h3>
<p>On Windows, the native type of file objects is handles (C type
<code class="docutils literal notranslate"><span class="pre">HANDLE</span></code>). These handles have a <code class="docutils literal notranslate"><span class="pre">HANDLE_FLAG_INHERIT</span></code> flag which
defines if a handle can be inherited in a child process or not. For the
POSIX API, the C runtime (CRT) also provides file descriptors (C type
<code class="docutils literal notranslate"><span class="pre">int</span></code>). The handle of a file descriptor can be retrieve using the
function <code class="docutils literal notranslate"><span class="pre">_get_osfhandle(fd)</span></code>. A file descriptor can be created from a
handle using the function <code class="docutils literal notranslate"><span class="pre">_open_osfhandle(handle)</span></code>.</p>
<p>Using <a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx">CreateProcess()</a>,
handles are only inherited if their inheritable flag
(<code class="docutils literal notranslate"><span class="pre">HANDLE_FLAG_INHERIT</span></code>) is set <strong>and</strong> the <code class="docutils literal notranslate"><span class="pre">bInheritHandles</span></code>
parameter of <code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code> is <code class="docutils literal notranslate"><span class="pre">TRUE</span></code>; all file descriptors
except standard streams (0, 1, 2) are closed in the child process, even
if <code class="docutils literal notranslate"><span class="pre">bInheritHandles</span></code> is <code class="docutils literal notranslate"><span class="pre">TRUE</span></code>. Using the <code class="docutils literal notranslate"><span class="pre">spawnv()</span></code> function, all
inheritable handles and all inheritable file descriptors are inherited
in the child process. This function uses the undocumented fields
<em>cbReserved2</em> and <em>lpReserved2</em> of the <a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331%28v=vs.85%29.aspx">STARTUPINFO</a>
structure to pass an array of file descriptors.</p>
<p>To replace standard streams (stdin, stdout, stderr) using
<code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code>, the <code class="docutils literal notranslate"><span class="pre">STARTF_USESTDHANDLES</span></code> flag must be set in
the <em>dwFlags</em> field of the <code class="docutils literal notranslate"><span class="pre">STARTUPINFO</span></code> structure and the
<em>bInheritHandles</em> parameter of <code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code> must be set to
<code class="docutils literal notranslate"><span class="pre">TRUE</span></code>. So when at least one standard stream is replaced, all
inheritable handles are inherited by the child process.</p>
<p>The default value of the <em>close_fds</em> parameter of <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> process
is <code class="docutils literal notranslate"><span class="pre">True</span></code> (<code class="docutils literal notranslate"><span class="pre">bInheritHandles=FALSE</span></code>) if <em>stdin</em>, <em>stdout</em> and
<em>stderr</em> parameters are <code class="docutils literal notranslate"><span class="pre">None</span></code>, <code class="docutils literal notranslate"><span class="pre">False</span></code> (<code class="docutils literal notranslate"><span class="pre">bInheritHandles=TRUE</span></code>)
otherwise.</p>
<p>See also:</p>
<ul class="simple">
<li><a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms724466%28v=vs.85%29.aspx">Handle Inheritance</a></li>
<li><a class="reference external" href="http://stackoverflow.com/questions/12058911/can-tcp-socket-handles-be-set-not-inheritable">Stackoverflow: Can TCP SOCKET handles be set not inheritable?</a></li>
</ul>
</section>
<section id="only-inherit-some-handles-on-windows">
<h3><a class="toc-backref" href="#only-inherit-some-handles-on-windows" role="doc-backlink">Only Inherit Some Handles on Windows</a></h3>
<p>Since Windows Vista, <code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code> supports an extension of the
STARTUPINFO structure: the <a class="reference external" href="http://msdn.microsoft.com/en-us/library/ms686329%28v=vs.85%29.aspx">STARTUPINFOEX structure</a>.
Using this new structure, it is possible to specify a list of handles to
inherit: <code class="docutils literal notranslate"><span class="pre">PROC_THREAD_ATTRIBUTE_HANDLE_LIST</span></code>. Read <a class="reference external" href="http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx">Programmatically
controlling which handles are inherited by new processes in Win32</a>
(Raymond Chen, Dec 2011) for more information.</p>
<p>Before Windows Vista, it is possible to make handles inheritable and
call <code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code> with <code class="docutils literal notranslate"><span class="pre">bInheritHandles=TRUE</span></code>. This option
works if all other handles are non-inheritable. There is a race
condition: if another thread calls <code class="docutils literal notranslate"><span class="pre">CreateProcess()</span></code> with
<code class="docutils literal notranslate"><span class="pre">bInheritHandles=TRUE</span></code>, handles will also be inherited in the second
process.</p>
<p>Microsoft suggests to use a lock to avoid the race condition: read
<a class="reference external" href="http://support.microsoft.com/kb/315939/en-us">Q315939: PRB: Child Inherits Unintended Handles During CreateProcess
Call</a> (last review:
November 2006). The <a class="reference external" href="http://bugs.python.org/issue16500">Python issue #16500 “Add an atfork module”</a> proposes to add such lock, it can
be used to make handles non-inheritable without the race condition. Such
lock only protects against a race condition between Python threads; C
threads are not protected.</p>
<p>Another option is to duplicate handles that must be inherited, passing the
values of the duplicated handles to the child process, so the child
process can steal duplicated handles using <a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/apps/ms724251%28v=vs.85%29.aspx">DuplicateHandle()</a>
with <code class="docutils literal notranslate"><span class="pre">DUPLICATE_CLOSE_SOURCE</span></code>. Handle values change between the
parent and the child process because the handles are duplicated (twice);
the parent and/or the child process must be adapted to handle this
change. If the child program cannot be modified, an intermediate program
can be used to steal handles from the parent process before spawning the
final child program. The intermediate program has to pass the handle from the
child process to the parent process. The parent may have to close
duplicated handles if all handles were not stolen, for example if the
intermediate process fails. If the command line is used to pass the
handle values, the command line must be modified when handles are
duplicated, because their values are modified.</p>
<p>This PEP does not include a solution to this problem because there is no
perfect solution working on all Windows versions. This point is deferred
until use cases relying on handle or file descriptor inheritance on
Windows are well known, so we can choose the best solution and carefully
test its implementation.</p>
</section>
<section id="inheritance-of-file-descriptors-on-unix">
<h3><a class="toc-backref" href="#inheritance-of-file-descriptors-on-unix" role="doc-backlink">Inheritance of File Descriptors on UNIX</a></h3>
<p>POSIX provides a <em>close-on-exec</em> flag on file descriptors to automatically
close a file descriptor when the C function <code class="docutils literal notranslate"><span class="pre">execv()</span></code> is
called. File descriptors with the <em>close-on-exec</em> flag cleared are
inherited in the child process, file descriptors with the flag set are
closed in the child process.</p>
<p>The flag can be set in two syscalls (one to get current flags, a second
to set new flags) using <code class="docutils literal notranslate"><span class="pre">fcntl()</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">int</span> <span class="n">flags</span><span class="p">,</span> <span class="n">res</span><span class="p">;</span>
<span class="n">flags</span> <span class="o">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_GETFD</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="o">/*</span> <span class="n">handle</span> <span class="n">the</span> <span class="n">error</span> <span class="o">*/</span> <span class="p">}</span>
<span class="n">flags</span> <span class="o">|=</span> <span class="n">FD_CLOEXEC</span><span class="p">;</span>
<span class="o">/*</span> <span class="ow">or</span> <span class="s2">&quot;flags &amp;= ~FD_CLOEXEC;&quot;</span> <span class="n">to</span> <span class="n">clear</span> <span class="n">the</span> <span class="n">flag</span> <span class="o">*/</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_SETFD</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="o">/*</span> <span class="n">handle</span> <span class="n">the</span> <span class="n">error</span> <span class="o">*/</span> <span class="p">}</span>
</pre></div>
</div>
<p>FreeBSD, Linux, Mac OS X, NetBSD, OpenBSD and QNX also support setting
the flag in a single syscall using ioctl():</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>int res;
res = ioctl(fd, FIOCLEX, 0);
if (!res) { /* handle the error */ }
</pre></div>
</div>
<p>NOTE: The <em>close-on-exec</em> flag has no effect on <code class="docutils literal notranslate"><span class="pre">fork()</span></code>: all file
descriptors are inherited by the child process. The <a class="reference external" href="http://bugs.python.org/issue16500">Python issue #16500
“Add an atfork module”</a> proposes to
add a new <code class="docutils literal notranslate"><span class="pre">atfork</span></code> module to execute code at fork, which may be used to
automatically close file descriptors.</p>
</section>
<section id="issues-with-inheritable-file-descriptors">
<h3><a class="toc-backref" href="#issues-with-inheritable-file-descriptors" role="doc-backlink">Issues with Inheritable File Descriptors</a></h3>
<p>Most of the time, inheritable file descriptors “leaked” to child
processes are not noticed, because they dont cause major bugs. It does
not mean that these bugs must not be fixed.</p>
<p>Two common issues with inherited file descriptors:</p>
<ul class="simple">
<li>On Windows, a directory cannot be removed before all file handles open
in the directory are closed. The same issue can be seen with files,
except if the file was created with the <code class="docutils literal notranslate"><span class="pre">FILE_SHARE_DELETE</span></code> flag
(<code class="docutils literal notranslate"><span class="pre">O_TEMPORARY</span></code> mode for <code class="docutils literal notranslate"><span class="pre">open()</span></code>).</li>
<li>If a listening socket is leaked to a child process, the socket address
cannot be reused before the parent and child processes terminated. For
example, if a web server spawns a new program to handle a process, and
the server restarts while the program is not done, the server cannot
start because the TCP port is still in use.</li>
</ul>
<p>Example of issues in open source projects:</p>
<ul class="simple">
<li><a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=147659">Mozilla (Firefox)</a>:
open since 2002-05</li>
<li><a class="reference external" href="https://bugs.freedesktop.org/show_bug.cgi?id=15947">dbus library</a>:
fixed in 2008-05 (<a class="reference external" href="http://cgit.freedesktop.org/dbus/dbus/commit/?id=e2bc7232069b14b7299cb8b2eab436f60a232007">dbus commit</a>),
close file descriptors in the child process</li>
<li><a class="reference external" href="https://bugzilla.redhat.com/show_bug.cgi?id=390591">autofs</a>:
fixed in 2009-02, set the CLOEXEC flag</li>
<li><a class="reference external" href="https://bugzilla.redhat.com/show_bug.cgi?id=528134">qemu</a>:
fixed in 2009-12 (<a class="reference external" href="http://git.qemu.org/?p=qemu.git;a=commit;h=40ff6d7e8dceca227e7f8a3e8e0d58b2c66d19b4">qemu commit</a>),
set CLOEXEC flag</li>
<li><a class="reference external" href="https://trac.torproject.org/projects/tor/ticket/2029">Tor</a>:
fixed in 2010-12, set CLOEXEC flag</li>
<li><a class="reference external" href="http://caml.inria.fr/mantis/view.php?id=5256">OCaml</a>: open since
2011-04, “PR#5256: Processes opened using Unix.open_process* inherit
all opened file descriptors (including sockets)”</li>
<li><a class="reference external" href="https://zeromq.jira.com/browse/LIBZMQ-408">ØMQ</a>:
open since 2012-08</li>
<li><a class="reference external" href="https://bugzilla.redhat.com/show_bug.cgi?id=837033">Squid</a>:
open since 2012-07</li>
</ul>
<p>See also: <a class="reference external" href="http://danwalsh.livejournal.com/53603.html">Excuse me son, but your code is leaking !!!</a> (Dan Walsh, March 2012)
for SELinux issues with leaked file descriptors.</p>
</section>
<section id="security-vulnerability">
<h3><a class="toc-backref" href="#security-vulnerability" role="doc-backlink">Security Vulnerability</a></h3>
<p>Leaking sensitive file handles and file descriptors can lead to security
vulnerabilities. An untrusted child process might read sensitive data like
passwords or take control of the parent process though a leaked file
descriptor. With a leaked listening socket, a child process can accept
new connections to read sensitive data.</p>
<p>Example of vulnerabilities:</p>
<ul class="simple">
<li><a class="reference external" href="http://www.securityfocus.com/archive/1/348368">Hijacking Apache https by mod_php</a> (2003)<ul>
<li>Apache: <a class="reference external" href="https://issues.apache.org/bugzilla/show_bug.cgi?id=46425">Apr should set FD_CLOEXEC if APR_FOPEN_NOCLEANUP is not set</a>:
fixed in 2009</li>
<li>PHP: <a class="reference external" href="https://bugs.php.net/bug.php?id=38915">system() (and similar) dont cleanup opened handles of Apache</a>: open since 2006</li>
</ul>
</li>
<li><a class="reference external" href="http://cwe.mitre.org/data/definitions/403.html">CWE-403: Exposure of File Descriptor to Unintended Control Sphere</a> (2008)</li>
<li><a class="reference external" href="http://www.openssh.com/txt/portable-keysign-rand-helper.adv">OpenSSH Security Advisory: portable-keysign-rand-helper.adv</a>
(2011)</li>
</ul>
<p>Read also the CERT Secure Coding Standards:
<a class="reference external" href="https://www.securecoding.cert.org/confluence/display/seccode/FIO42-C.+Ensure+files+are+properly+closed+when+they+are+no+longer+needed">FIO42-C. Ensure files are properly closed when they are no longer
needed</a>.</p>
</section>
<section id="issues-fixed-in-the-subprocess-module">
<h3><a class="toc-backref" href="#issues-fixed-in-the-subprocess-module" role="doc-backlink">Issues fixed in the subprocess module</a></h3>
<p>Inherited file descriptors caused 4 issues in the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code>
module:</p>
<ul class="simple">
<li><a class="reference external" href="http://bugs.python.org/issue2320">Issue #2320: Race condition in subprocess using stdin</a> (opened in 2008)</li>
<li><a class="reference external" href="http://bugs.python.org/issue3006">Issue #3006: subprocess.Popen causes socket to remain open after
close</a> (opened in 2008)</li>
<li><a class="reference external" href="http://bugs.python.org/issue7213">Issue #7213: subprocess leaks open file descriptors between Popen
instances causing hangs</a>
(opened in 2009)</li>
<li><a class="reference external" href="http://bugs.python.org/issue12786">Issue #12786: subprocess wait() hangs when stdin is closed</a> (opened in 2011)</li>
</ul>
<p>These issues were fixed in Python 3.2 by 4 different changes in the
<code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module:</p>
<ul class="simple">
<li>Pipes are now non-inheritable;</li>
<li>The default value of the <em>close_fds</em> parameter is now <code class="docutils literal notranslate"><span class="pre">True</span></code>,
with one exception on Windows: the default value is <code class="docutils literal notranslate"><span class="pre">False</span></code> if
at least one standard stream is replaced;</li>
<li>A new <em>pass_fds</em> parameter has been added;</li>
<li>Creation of a <code class="docutils literal notranslate"><span class="pre">_posixsubprocess</span></code> module implemented in C.</li>
</ul>
</section>
<section id="atomic-creation-of-non-inheritable-file-descriptors">
<h3><a class="toc-backref" href="#atomic-creation-of-non-inheritable-file-descriptors" role="doc-backlink">Atomic Creation of non-inheritable File Descriptors</a></h3>
<p>In a multi-threaded application, an inheritable file descriptor may be
created just before a new program is spawned, before the file descriptor
is made non-inheritable. In this case, the file descriptor is leaked to
the child process. This race condition could be avoided if the file
descriptor is created directly non-inheritable.</p>
<p>FreeBSD, Linux, Mac OS X, Windows and many other operating systems
support creating non-inheritable file descriptors with the inheritable
flag cleared atomically at the creation of the file descriptor.</p>
<p>A new <code class="docutils literal notranslate"><span class="pre">WSA_FLAG_NO_HANDLE_INHERIT</span></code> flag for <code class="docutils literal notranslate"><span class="pre">WSASocket()</span></code> was added
in Windows 7 SP1 and Windows Server 2008 R2 SP1 to create
non-inheritable sockets. If this flag is used on an older Windows
version (ex: Windows XP SP3), <code class="docutils literal notranslate"><span class="pre">WSASocket()</span></code> fails with
<code class="docutils literal notranslate"><span class="pre">WSAEPROTOTYPE</span></code>.</p>
<p>On UNIX, new flags were added for files and sockets:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">O_CLOEXEC</span></code>: available on Linux (2.6.23), FreeBSD (8.3),
Mac OS 10.8, OpenBSD 5.0, Solaris 11, QNX, BeOS, next NetBSD release
(6.1?). This flag is part of POSIX.1-2008.</li>
<li><code class="docutils literal notranslate"><span class="pre">SOCK_CLOEXEC</span></code> flag for <code class="docutils literal notranslate"><span class="pre">socket()</span></code> and <code class="docutils literal notranslate"><span class="pre">socketpair()</span></code>,
available on Linux 2.6.27, OpenBSD 5.2, NetBSD 6.0.</li>
<li><code class="docutils literal notranslate"><span class="pre">fcntl()</span></code>: <code class="docutils literal notranslate"><span class="pre">F_DUPFD_CLOEXEC</span></code> flag, available on Linux 2.6.24,
OpenBSD 5.0, FreeBSD 9.1, NetBSD 6.0, Solaris 11. This flag is part
of POSIX.1-2008.</li>
<li><code class="docutils literal notranslate"><span class="pre">fcntl()</span></code>: <code class="docutils literal notranslate"><span class="pre">F_DUP2FD_CLOEXEC</span></code> flag, available on FreeBSD 9.1
and Solaris 11.</li>
<li><code class="docutils literal notranslate"><span class="pre">recvmsg()</span></code>: <code class="docutils literal notranslate"><span class="pre">MSG_CMSG_CLOEXEC</span></code>, available on Linux 2.6.23,
NetBSD 6.0.</li>
</ul>
<p>On Linux older than 2.6.23, <code class="docutils literal notranslate"><span class="pre">O_CLOEXEC</span></code> flag is simply ignored. So
<code class="docutils literal notranslate"><span class="pre">fcntl()</span></code> must be called to check if the file descriptor is
non-inheritable: <code class="docutils literal notranslate"><span class="pre">O_CLOEXEC</span></code> is not supported if the <code class="docutils literal notranslate"><span class="pre">FD_CLOEXEC</span></code>
flag is missing. On Linux older than 2.6.27, <code class="docutils literal notranslate"><span class="pre">socket()</span></code> or
<code class="docutils literal notranslate"><span class="pre">socketpair()</span></code> fail with <code class="docutils literal notranslate"><span class="pre">errno</span></code> set to <code class="docutils literal notranslate"><span class="pre">EINVAL</span></code> if the
<code class="docutils literal notranslate"><span class="pre">SOCK_CLOEXEC</span></code> flag is set in the socket type.</p>
<p>New functions:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">dup3()</span></code>: available on Linux 2.6.27 (and glibc 2.9)</li>
<li><code class="docutils literal notranslate"><span class="pre">pipe2()</span></code>: available on Linux 2.6.27 (and glibc 2.9)</li>
<li><code class="docutils literal notranslate"><span class="pre">accept4()</span></code>: available on Linux 2.6.28 (and glibc 2.10)</li>
</ul>
<p>On Linux older than 2.6.28, <code class="docutils literal notranslate"><span class="pre">accept4()</span></code> fails with <code class="docutils literal notranslate"><span class="pre">errno</span></code> set to
<code class="docutils literal notranslate"><span class="pre">ENOSYS</span></code>.</p>
<p>Summary:</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head">Operating System</th>
<th class="head">Atomic File</th>
<th class="head">Atomic Socket</th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td>FreeBSD</td>
<td>8.3 (2012)</td>
<td>X</td>
</tr>
<tr class="row-odd"><td>Linux</td>
<td>2.6.23 (2007)</td>
<td>2.6.27 (2008)</td>
</tr>
<tr class="row-even"><td>Mac OS X</td>
<td>10.8 (2012)</td>
<td>X</td>
</tr>
<tr class="row-odd"><td>NetBSD</td>
<td>6.1 (?)</td>
<td>6.0 (2012)</td>
</tr>
<tr class="row-even"><td>OpenBSD</td>
<td>5.0 (2011)</td>
<td>5.2 (2012)</td>
</tr>
<tr class="row-odd"><td>Solaris</td>
<td>11 (2011)</td>
<td>X</td>
</tr>
<tr class="row-even"><td>Windows</td>
<td>XP (2001)</td>
<td>Seven SP1 (2011), 2008 R2 SP1 (2011)</td>
</tr>
</tbody>
</table>
<p>Legend:</p>
<ul class="simple">
<li>“Atomic File”: first version of the operating system supporting
creating atomically a non-inheritable file descriptor using
<code class="docutils literal notranslate"><span class="pre">open()</span></code></li>
<li>“Atomic Socket”: first version of the operating system supporting
creating atomically a non-inheritable socket</li>
<li>“X”: not supported yet</li>
</ul>
<p>See also:</p>
<ul class="simple">
<li><a class="reference external" href="http://udrepper.livejournal.com/20407.html">Secure File Descriptor Handling</a> (Ulrich Drepper,
2008)</li>
<li><a class="reference external" href="http://lwn.net/Articles/412131/">Ghosts of Unix past, part 2: Conflated designs</a> (Neil Brown, 2010) explains the
history of <code class="docutils literal notranslate"><span class="pre">O_CLOEXEC</span></code> and <code class="docutils literal notranslate"><span class="pre">O_NONBLOCK</span></code> flags</li>
<li><a class="reference external" href="http://lwn.net/Articles/292843/">File descriptor handling changes in 2.6.27</a></li>
<li><a class="reference external" href="https://wiki.freebsd.org/AtomicCloseOnExec">FreeBSD: atomic close on exec</a></li>
</ul>
</section>
<section id="status-of-python-3-3">
<h3><a class="toc-backref" href="#status-of-python-3-3" role="doc-backlink">Status of Python 3.3</a></h3>
<p>Python 3.3 creates inheritable file descriptors on all platforms, except
<code class="docutils literal notranslate"><span class="pre">os.pipe()</span></code> which creates non-inheritable file descriptors on Windows.</p>
<p>New constants and functions related to the atomic creation of
non-inheritable file descriptors were added to Python 3.3:
<code class="docutils literal notranslate"><span class="pre">os.O_CLOEXEC</span></code>, <code class="docutils literal notranslate"><span class="pre">os.pipe2()</span></code> and <code class="docutils literal notranslate"><span class="pre">socket.SOCK_CLOEXEC</span></code>.</p>
<p>On UNIX, the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module closes all file descriptors in the
child process by default, except standard streams (0, 1, 2) and file
descriptors of the <em>pass_fds</em> parameter. If the <em>close_fds</em> parameter is
set to <code class="docutils literal notranslate"><span class="pre">False</span></code>, all inheritable file descriptors are inherited in the
child process.</p>
<p>On Windows, the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> closes all handles and file descriptors
in the child process by default. If at least one standard stream (stdin,
stdout or stderr) is replaced (ex: redirected into a pipe), all
inheritable handles and file descriptors 0, 1 and 2 are inherited in the
child process.</p>
<p>Using the functions of the <code class="docutils literal notranslate"><span class="pre">os.execv*()</span></code> and <code class="docutils literal notranslate"><span class="pre">os.spawn*()</span></code> families,
all inheritable handles and all inheritable file descriptors are
inherited by the child process.</p>
<p>On UNIX, the <code class="docutils literal notranslate"><span class="pre">multiprocessing</span></code> module uses <code class="docutils literal notranslate"><span class="pre">os.fork()</span></code> and so all
file descriptors are inherited by child processes.</p>
<p>On Windows, all inheritable handles and file descriptors 0, 1 and 2 are
inherited by the child process using the <code class="docutils literal notranslate"><span class="pre">multiprocessing</span></code> module, all
file descriptors except standard streams are closed.</p>
<p>Summary:</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head">Module</th>
<th class="head">FD on UNIX</th>
<th class="head">Handles on Windows</th>
<th class="head">FD on Windows</th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td>subprocess, default</td>
<td>STD, pass_fds</td>
<td>none</td>
<td>STD</td>
</tr>
<tr class="row-odd"><td>subprocess, replace stdout</td>
<td>STD, pass_fds</td>
<td>all</td>
<td>STD</td>
</tr>
<tr class="row-even"><td>subprocess, close_fds=False</td>
<td>all</td>
<td>all</td>
<td>STD</td>
</tr>
<tr class="row-odd"><td>multiprocessing</td>
<td>not applicable</td>
<td>all</td>
<td>STD</td>
</tr>
<tr class="row-even"><td>os.execv(), os.spawn()</td>
<td>all</td>
<td>all</td>
<td>all</td>
</tr>
</tbody>
</table>
<p>Legend:</p>
<ul class="simple">
<li>“all”: all <em>inheritable</em> file descriptors or handles are inherited in
the child process</li>
<li>“none”: all handles are closed in the child process</li>
<li>“STD”: only file descriptors 0 (stdin), 1 (stdout) and 2 (stderr) are
inherited in the child process</li>
<li>“pass_fds”: file descriptors of the <em>pass_fds</em> parameter of the
subprocess are inherited</li>
<li>“not applicable”: on UNIX, the multiprocessing uses <code class="docutils literal notranslate"><span class="pre">fork()</span></code>,
so this case is not affected by this PEP.</li>
</ul>
</section>
<section id="closing-all-open-file-descriptors">
<h3><a class="toc-backref" href="#closing-all-open-file-descriptors" role="doc-backlink">Closing All Open File Descriptors</a></h3>
<p>On UNIX, the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module closes almost all file descriptors in
the child process. This operation requires MAXFD system calls, where
MAXFD is the maximum number of file descriptors, even if there are only
few open file descriptors. This maximum can be read using:
<code class="docutils literal notranslate"><span class="pre">os.sysconf(&quot;SC_OPEN_MAX&quot;)</span></code>.</p>
<p>The operation can be slow if MAXFD is large. For example, on a FreeBSD
buildbot with <code class="docutils literal notranslate"><span class="pre">MAXFD=655,000</span></code>, the operation took 300 ms: see
<a class="reference external" href="http://bugs.python.org/issue11284#msg132668">issue #11284: slow close file descriptors</a>.</p>
<p>On Linux, Python 3.3 gets the list of all open file descriptors from
<code class="docutils literal notranslate"><span class="pre">/proc/&lt;PID&gt;/fd/</span></code>, and so performances depends on the number of open
file descriptors, not on MAXFD.</p>
<p>See also:</p>
<ul class="simple">
<li><a class="reference external" href="http://bugs.python.org/issue1663329">Python issue #1663329</a>:
subprocess close_fds perform poor if <code class="docutils literal notranslate"><span class="pre">SC_OPEN_MAX</span></code> is high</li>
<li><a class="reference external" href="https://bugzilla.redhat.com/show_bug.cgi?id=837033">Squid Bug #837033</a>:
Squid should set CLOEXEC on opened FDs. “32k+ close() calls in each
child process take a long time ([12-56] seconds) in Xen PV guests.”</li>
</ul>
</section>
</section>
<section id="proposal">
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
<section id="non-inheritable-file-descriptors">
<h3><a class="toc-backref" href="#non-inheritable-file-descriptors" role="doc-backlink">Non-inheritable File Descriptors</a></h3>
<p>The following functions are modified to make newly created file
descriptors non-inheritable by default:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">asyncore.dispatcher.create_socket()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">io.FileIO</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">io.open()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">open()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">os.dup()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">os.fdopen()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">os.open()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">os.openpty()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">os.pipe()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">select.devpoll()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">select.epoll()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">select.kqueue()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socket()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socket.accept()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socket.dup()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socket.fromfd()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socketpair()</span></code></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> still creates inheritable by default, see below.</p>
<p>When available, atomic flags are used to make file descriptors
non-inheritable. The atomicity is not guaranteed because a fallback is
required when atomic flags are not available.</p>
</section>
<section id="new-functions-and-methods">
<h3><a class="toc-backref" href="#new-functions-and-methods" role="doc-backlink">New Functions And Methods</a></h3>
<p>New functions available on all platforms:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">os.get_inheritable(fd:</span> <span class="pre">int)</span></code>: return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the file
descriptor can be inherited by child processes, <code class="docutils literal notranslate"><span class="pre">False</span></code> otherwise.</li>
<li><code class="docutils literal notranslate"><span class="pre">os.set_inheritable(fd:</span> <span class="pre">int,</span> <span class="pre">inheritable:</span> <span class="pre">bool)</span></code>: set the
inheritable flag of the specified file descriptor.</li>
</ul>
<p>New functions only available on Windows:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">os.get_handle_inheritable(handle:</span> <span class="pre">int)</span></code>: return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the
handle can be inherited by child processes, <code class="docutils literal notranslate"><span class="pre">False</span></code> otherwise.</li>
<li><code class="docutils literal notranslate"><span class="pre">os.set_handle_inheritable(handle:</span> <span class="pre">int,</span> <span class="pre">inheritable:</span> <span class="pre">bool)</span></code>:
set the inheritable flag of the specified handle.</li>
</ul>
<p>New methods:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">socket.socket.get_inheritable()</span></code>: return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the
socket can be inherited by child processes, <code class="docutils literal notranslate"><span class="pre">False</span></code> otherwise.</li>
<li><code class="docutils literal notranslate"><span class="pre">socket.socket.set_inheritable(inheritable:</span> <span class="pre">bool)</span></code>:
set the inheritable flag of the specified socket.</li>
</ul>
</section>
<section id="other-changes">
<h3><a class="toc-backref" href="#other-changes" role="doc-backlink">Other Changes</a></h3>
<p>On UNIX, subprocess makes file descriptors of the <em>pass_fds</em> parameter
inheritable. The file descriptor is made inheritable in the child
process after the <code class="docutils literal notranslate"><span class="pre">fork()</span></code> and before <code class="docutils literal notranslate"><span class="pre">execv()</span></code>, so the inheritable
flag of file descriptors is unchanged in the parent process.</p>
<p><code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> has a new optional <em>inheritable</em> parameter: <code class="docutils literal notranslate"><span class="pre">os.dup2(fd,</span>
<span class="pre">fd2,</span> <span class="pre">inheritable=True)</span></code>. <em>fd2</em> is created inheritable by default, but
non-inheritable if <em>inheritable</em> is <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> behaves differently than <code class="docutils literal notranslate"><span class="pre">os.dup()</span></code> because the most
common use case of <code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> is to replace the file descriptors of
the standard streams: <code class="docutils literal notranslate"><span class="pre">stdin</span></code> (<code class="docutils literal notranslate"><span class="pre">0</span></code>), <code class="docutils literal notranslate"><span class="pre">stdout</span></code> (<code class="docutils literal notranslate"><span class="pre">1</span></code>) and
<code class="docutils literal notranslate"><span class="pre">stderr</span></code> (<code class="docutils literal notranslate"><span class="pre">2</span></code>). Standard streams are expected to be inherited by
child processes.</p>
</section>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h2>
<p>This PEP break applications relying on inheritance of file descriptors.
Developers are encouraged to reuse the high-level Python module
<code class="docutils literal notranslate"><span class="pre">subprocess</span></code> which handles the inheritance of file descriptors in a
portable way.</p>
<p>Applications using the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module with the <em>pass_fds</em>
parameter or using only <code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> to redirect standard streams should
not be affected.</p>
<p>Python no longer conform to POSIX, since file descriptors are now
made non-inheritable by default. Python was not designed to conform to
POSIX, but was designed to develop portable applications.</p>
</section>
<section id="related-work">
<h2><a class="toc-backref" href="#related-work" role="doc-backlink">Related Work</a></h2>
<p>The programming languages Go, Perl and Ruby make newly created file
descriptors non-inheritable by default: since Go 1.0 (2009), Perl 1.0
(1987) and Ruby 2.0 (2013).</p>
<p>The SCons project, written in Python, overrides builtin functions
<code class="docutils literal notranslate"><span class="pre">file()</span></code> and <code class="docutils literal notranslate"><span class="pre">open()</span></code> to make files non-inheritable on Windows:
see <a class="reference external" href="https://bitbucket.org/scons/scons/src/c8dbbaa4598e7119ae80f72068386be105b5ad98/src/engine/SCons/Platform/win32.py?at=default#cl-68">win32.py</a>.</p>
</section>
<section id="rejected-alternatives">
<h2><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h2>
<section id="add-a-new-open-noinherit-function">
<h3><a class="toc-backref" href="#add-a-new-open-noinherit-function" role="doc-backlink">Add a new open_noinherit() function</a></h3>
<p>In June 2007, Henning von Bargen proposed on the python-dev mailing list
to add a new open_noinherit() function to fix issues of inherited file
descriptors in child processes. At this time, the default value of the
<em>close_fds</em> parameter of the subprocess module was <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p>
<p>Read the mail thread: <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2007-June/073688.html">[Python-Dev] Proposal for a new function
“open_noinherit” to avoid problems with subprocesses and security risks</a>.</p>
</section>
<section id="pep-433">
<h3><a class="toc-backref" href="#pep-433" role="doc-backlink">PEP 433</a></h3>
<p><a class="pep reference internal" href="../pep-0433/" title="PEP 433 Easier suppression of file descriptor inheritance">PEP 433</a>, “Easier suppression of file descriptor inheritance”,
was a previous attempt proposing various other alternatives, but no
consensus could be reached.</p>
</section>
</section>
<section id="python-issues">
<h2><a class="toc-backref" href="#python-issues" role="doc-backlink">Python Issues</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://bugs.python.org/issue10115">#10115: Support accept4() for atomic setting of flags at socket
creation</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue12105">#12105: open() does not able to set flags, such as O_CLOEXEC</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue12107">#12107: TCP listening sockets created without FD_CLOEXEC flag</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue16850">#16850: Add “e” mode to open(): close-and-exec
(O_CLOEXEC) / O_NOINHERIT</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue16860">#16860: Use O_CLOEXEC in the tempfile module</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue16946">#16946: subprocess: _close_open_fd_range_safe() does not set
close-on-exec flag on Linux &lt; 2.6.23 if O_CLOEXEC is defined</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue17070">#17070: Use the new cloexec to improve security and avoid bugs</a></li>
<li><a class="reference external" href="http://bugs.python.org/issue18571">#18571: Implementation of the PEP 446: non-inheritable file
descriptors</a></li>
</ul>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed into the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0446.rst">https://github.com/python/peps/blob/main/peps/pep-0446.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0446.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#inheritance-of-file-descriptors">Inheritance of File Descriptors</a></li>
<li><a class="reference internal" href="#inheritance-of-file-descriptors-on-windows">Inheritance of File Descriptors on Windows</a></li>
<li><a class="reference internal" href="#only-inherit-some-handles-on-windows">Only Inherit Some Handles on Windows</a></li>
<li><a class="reference internal" href="#inheritance-of-file-descriptors-on-unix">Inheritance of File Descriptors on UNIX</a></li>
<li><a class="reference internal" href="#issues-with-inheritable-file-descriptors">Issues with Inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#security-vulnerability">Security Vulnerability</a></li>
<li><a class="reference internal" href="#issues-fixed-in-the-subprocess-module">Issues fixed in the subprocess module</a></li>
<li><a class="reference internal" href="#atomic-creation-of-non-inheritable-file-descriptors">Atomic Creation of non-inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#status-of-python-3-3">Status of Python 3.3</a></li>
<li><a class="reference internal" href="#closing-all-open-file-descriptors">Closing All Open File Descriptors</a></li>
</ul>
</li>
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
<li><a class="reference internal" href="#non-inheritable-file-descriptors">Non-inheritable File Descriptors</a></li>
<li><a class="reference internal" href="#new-functions-and-methods">New Functions And Methods</a></li>
<li><a class="reference internal" href="#other-changes">Other Changes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#related-work">Related Work</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul>
<li><a class="reference internal" href="#add-a-new-open-noinherit-function">Add a new open_noinherit() function</a></li>
<li><a class="reference internal" href="#pep-433">PEP 433</a></li>
</ul>
</li>
<li><a class="reference internal" href="#python-issues">Python Issues</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0446.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>