[Python-Dev] fork or exec?

Victor Stinner victor.stinner at gmail.com
Thu Jan 10 20:21:19 CET 2013


2013/1/10 Antoine Pitrou <solipsis at pitrou.net>:
>> I changed my mind, the PEP does not propose to change the *default*
>> behaviour (don't set close-on-exec by default).
>>
>> But the PEP proposes to *add a function* to change the default
>> behaviour. Application developers taking care of security can set
>> close-on-exec by default, but they will have maybe to fix bugs (add
>> cloexec=False argument, call os.set_cloexec(fd, True)) because
>> something may expect an inheried file descriptor.
>
> Do you have an example of what that "something" may be?
> Apart from standard streams, I can't think of any inherited file
> descriptor an external program would want to rely on.
>
> In other words, I think close-on-exec by default is probably a
> reasonable decision.

Network servers like inetd or apache MPM (prefork) uses a process
listening on a socket, and then fork to execute a request in a child
process. I don't know how it works exactly, but I guess that the child
process need a socket from the parent to send the answer to the
client. If the socket is closed on execute (ex: Apache with CGI), it
does not work :-)

Example with CGIHTTPRequestHandler.run_cgi(), self.connection is the
socket coming from accept():

    self.rfile = self.connection.makefile('rb', self.rbufsize)
    self.wfile = self.connection.makefile('wb', self.wbufsize)
    ...
    try:
        os.setuid(nobody)
    except OSError:
        pass
    os.dup2(self.rfile.fileno(), 0)
    os.dup2(self.wfile.fileno(), 1)
    os.execve(scriptfile, args, env)

We are talking about *one* specific socket. So if close-on-exec flag
is set on all file descriptors, it should be easy to only unset it on
one specific file descriptor. For example, the fix for
StreamRequestHandler.setup() would be simple, just add cloexec=True to
dup2:

    os.dup2(self.rfile.fileno(), 0, cloexec=False)
    os.dup2(self.wfile.fileno(), 1, cloexec=False)

Such servers is not the common case, but more the exception. So
setting close-on-exec by default makes sense.

I don't know if there are other use cases using fork()+exec() and
*inheriting* one or more file descriptors.

--

On Windows, the CGI server uses a classic PIPE to get the output of
the subprocess and then copy data from the pipe into the socket.

Victor


More information about the Python-Dev mailing list