Ensure fd 0 stdin </dev/null is always inheritable.

When gunicorn --daemon daemonizes the process, prior to this change it was
noted that in the general case (without -R / --enable-stdio-inheritance), when fd 0
was replaced with /dev/null, the dup2 copy is skipped, and per PEP 446
"Make newly created file descriptors non-inheritable", the result was a stdio
fd </dev/null which was non-inheritable.  As a result, any launched subprocess
did not have an open 0/stdin fd, which can cause problems in some applications.

This change retains the behaviour of opening /dev/null with fd 0, but adds a call
to os.set_inheritable(..) to ensure the fd is inheritable.

The -R branch had different logic but has now been standardised with the general
case.  It was previously opening /dev/null as fd 3 and the dup2() copy made it
inheritable as fd 0.  This branch now applies the same logic: open as fd 0
(i.e. after close(0)), then set_inheritable.  As a result, an extra fd 3 </dev/null
previously left open is no longer left open.

Signed-off-by: Brett Randall <javabrett@gmail.com>
This commit is contained in:
Brett Randall 2022-01-27 16:03:13 +11:00
parent e5a97150c9
commit 835a4fc420
No known key found for this signature in database
GPG Key ID: 50EF8B0B7C04B29D

View File

@ -486,7 +486,10 @@ def daemonize(enable_stdio_inheritance=False):
closerange(0, 3)
fd_null = os.open(REDIRECT_TO, os.O_RDWR)
# PEP 446, make fd for /dev/null inheritable
os.set_inheritable(fd_null, True)
# expect fd_null to be always 0 here, but in-case not ...
if fd_null != 0:
os.dup2(fd_null, 0)
@ -494,13 +497,17 @@ def daemonize(enable_stdio_inheritance=False):
os.dup2(fd_null, 2)
else:
fd_null = os.open(REDIRECT_TO, os.O_RDWR)
# Always redirect stdin to /dev/null as we would
# never expect to need to read interactive input.
os.close(0)
fd_null = os.open(REDIRECT_TO, os.O_RDWR)
# PEP 446, make fd for /dev/null inheritable
os.set_inheritable(fd_null, True)
# expect fd_null to be always 0 here, but in-case not ...
if fd_null != 0:
os.close(0)
os.dup2(fd_null, 0)
# If stdout and stderr are still connected to