[Python-Dev] PEP 446: Add new parameters to configure the inherance of files and for non-blocking sockets (original) (raw)

Victor Stinner victor.stinner at gmail.com
Thu Jul 4 13:03:06 CEST 2013


HTML version: http://www.python.org/dev/peps/pep-0446/

PEP: 446 Title: Add new parameters to configure the inherance of files and for non-blocking sockets Version: RevisionRevisionRevision Last-Modified: DateDateDate Author: Victor Stinner <victor.stinner at gmail.com> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 3-July-2013 Python-Version: 3.4

Abstract

This PEP proposes new portable parameters and functions to configure the inherance of file descriptors and the non-blocking flag of sockets.

Rationale

Inherance of file descriptors

The inherance of file descriptors in child processes can be configured on each file descriptor using a close-on-exec flag. By default, the close-on-exec flag is not set.

On Windows, file descriptors are not inherited if the bInheritHandles parameter of the CreateProcess() function is FALSE, even if the close-on-exec flag is not set.

On UNIX, file descriptors with the close-and-exec flag set are closed at the execution of a new program (ex: when calling execv()). The flag has no effect on fork(), all file descriptors are inherited by the child process.

Issues of the inherance of file descriptors

Inherance of file descriptors causes issues. For example, closing a file descriptor in the parent process does not release the resource (file, socket, ...), because the file descriptor is still open in the child process.

Leaking file descriptors is also a major security vulnerability. An untrusted child process can read sensitive data like passwords and take control of the parent process though leaked file descriptors. It is for example a known vulnerability to escape from a chroot.

Non-blocking sockets

To handle multiple network clients in a single thread, a multiplexing function like select() can be used. For best performances, sockets must be configured as non-blocking. Operations like send() and recv() return an EAGAIN or EWOULDBLOCK error if the operation would block.

By default, newly created sockets are blocking. Setting the non-blocking mode requires additional system calls.

Setting flags at the creation of the file descriptor

Windows and recent versions of other operating systems like Linux support setting the close-on-exec flag directly at the creation of file descriptors, and close-on-exec and blocking flags at the creation of sockets.

Setting these flags at the creation is atomic and avoids additional system calls.

Proposal

New cloexec And blocking Parameters

Add a new optional cloexec on functions creating file descriptors:

Add new optional cloexec and blocking parameters to functions creating sockets:

The default value of cloexec is False and the default value of blocking is True.

The atomicity is not guaranteed. If the platform does not support setting close-on-exec and blocking flags at the creation of the file descriptor or socket, the flags are set using additional system calls.

New Functions

Add new functions the get and set the close-on-exec flag of a file descriptor:

Other Changes

The subprocess.Popen class must clear the close-on-exec flag of file descriptors of the pass_fds parameter.

The close-on-exec flag must also be set on private file descriptors and sockets in the Python standard library. For example, on UNIX, os.urandom() opens /dev/urandom to read some random bytes and the file descriptor is closed at function exit. The file descriptor is not expected to be inherited by child processes.

Rejected Alternatives

PEP 433

The PEP 433 entitled "Easier suppression of file descriptor inheritance" is a previous attempt proposing various other alternatives, but no consensus could be reached.

This PEP has a well defined behaviour (the default value of the new cloexec parameter is not configurable), is more conservative (no backward compatibility issue), and is much simpler.

Add blocking parameter for file descriptors and Windows overlapped I/O

Windows supports non-blocking operations on files using an extension of the Windows API called "Overlapped I/O". Using this extension requires to modify the Python standard library and applications to pass a OVERLAPPED structure and an event loop to wait for the completion of operations.

This PEP only tries to expose portable flags on file descriptors and sockets. Supporting overlapped I/O requires an abstraction providing a high-level and portable API for asynchronous operations on files and sockets. Overlapped I/O are out of the scope of this PEP.

UNIX supports non-blocking files, moreover recent versions of operating systems support setting the non-blocking flag at the creation of a file descriptor. It would be possible to add a new optional blocking parameter to Python functions creating file descriptors. On Windows, creating a file descriptor with blocking=False would raise a NotImplementedError. This behaviour is not acceptable for the os module which is designed as a thin wrapper on the C functions of the operating system. If a platform does not support a function, the function should not be available on the platform. For example, the os.fork() function is not available on Windows.

For all these reasons, this alternative was rejected. The PEP 3156 proposes an abstraction for asynchronous I/O supporting non-blocking files on Windows.

Links

Python issues:

Other links:

Copyright

This document has been placed into the public domain.



More information about the Python-Dev mailing list