Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001318 [1003.1(2016/18)/Issue7+TC2] System Interfaces Comment Enhancement Request 2020-01-12 10:50 2024-06-11 09:08
Reporter nate_karstens View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Closed  
Name Nate Karstens
Organization Garmin
User Reference
Section fcntl, open, socket
Page Number Unknown
Line Number Unknown
Interp Status ---
Final Accepted Text Note: 0004797
Summary 0001318: Define close-on-fork flag
Description Certain interfaces (like system(), popen(), etc.) are non-atomic in that their implementation first calls a fork() and then an exec(). This creates a race condition in certain scenarios. Please see https://www.mail-archive.com/austin-group-l@opengroup.org/msg05324.html [^] and resulting discussion for a description of one such condition.

Issue 1317 already requests enhancements to these interfaces, but this particular issue would also be solvable if there was a close-on-fork flag (similar to close-on-exec, but the file descriptor is closed in the child process after a fork).
Desired Action Add the following to fcntl()/F_DUPFD:

The FD_CLOFORK flag associated with the new file descriptor shall be cleared to keep the file open in the child process after a fork.

Add the following to fcntl()/F_SETFD

If the FD_CLOFORK flag in the third argument is 0, the file descriptor shall remain open in the child process after a fork(). Otherwise, the file descriptor shall be closed in the child process after a fork().

Add the following to fcntl():

F_DUPFD_CLOFORK
    Like F_DUPFD, but the FD_CLOFORK flag associated with the new file descriptor shall be set.

Additional changes to the RETURN VALUE and ERRORS sections may be necessary as well.

Add the following to open():

O_CLOFORK
    If set, the FD_CLOFORK flag for the new file descriptor shall be set.

POSIX does not currently specify SOCK_CLOEXEC, but this would be a useful addition. Add the following to socket():

SOCK_CLOEXEC
    If set, the close-on-exec (FD_CLOEXEC) flag for the new file descriptor shall be set.
SOCK_CLOFORK
    If set, the close-on-fork (FD_CLOFORK) flag for the new file descriptor shall be set.

In hindsight, it seems like it would have been preferable to have the default behavior be to close all file descriptors when the process forks, and have flags to override that behavior on an individual basis. Submitter cannot think of a way to do that and maintain backwards-compatibility, short of defining new system calls, but the idea seems like it would be worth considering.
Tags issue8
Attached Files

- Relationships
related to 0000411Closedajosey 1003.1(2008)/Issue 7 adding atomic FD_CLOEXEC support 
related to 0001337Closed 1003.1(2016/18)/Issue7+TC2 Clarify socket option values after accept() 
related to 0001317Closed 1003.1(2016/18)/Issue7+TC2 Require fork handlers to be called in certain conditions 
related to 0000768Closed 1003.1(2013)/Issue7+TC1 add "fd-private" POSIX locks to spec 
related to 0001851New 1003.1(2024)/Issue8 FD_CLOFORK should not be preserved across exec 

-  Notes
(0004725)
kre (reporter)
2020-01-13 07:28

The wording:

   If the FD_CLOFORK flag in the third argument is 0, the file descriptor
   shall remain open in the child process after a fork(). Otherwise, the
   file descriptor shall be closed in the child process after a fork().

is bizarre, and (I suspect) is influenced by the odd view of how fork()
and file descriptors should have been handled. The more common way to
write this would be

   If the FD_CLOFORK flag in the third argument is set, the file descriptor
   will be closed in the child process after a successful fork() operation,
   otherwise the file descriptor shall remain open in the child after a fork()

with appropriate xref tags added.

Then wrt:

    Add the following to fcntl():

    F_DUPFD_CLOFORK

please, no, we already have F_DUPFD_CLOEXEC which is bad enough, if
we add a new one like this, we'd also need

    F_DUPFD_CLOEXEC_CLOFORK

so that both flags can be set. F_SETFD is enough for all of this, but
to add a new flag to that is problematic, lots of (older) applications
assume that close-on-exec is its only possibility, as for decades that
has been trus (and there was no constant defined, so the result from
F_GETFD is often simply tested against 0, if not 0, close on exec is
assumed, and 1 is used for F_SETFD to set close-on-exec).

If something is needed for atomic operation, add a F_DUFPD variant where
the arg is the flags, rather than the lowest desired fd number, or simply
standardise dup3() which has a flags arg, and could easily be made to have
a "next available bigger than" flag as well as the close-on-exec (and
presumably a new close-on-fork) flag it already accepts (to make dup3()
be able to act as an alternative to fcntl(F_DUFPD) in a reasonable way,
without adding more args to fcntl().

Lastly (for now):

    In hindsight, it seems like it would have been preferable to have the
    default behavior be to close all file descriptors when the process forks

Nonsense. All of this is brought about by the horrid threading design that's
been thrust upon us (and yes, I know it came about based upon implementations
that were entirely in-process hacks initially, with no kernel support at all).

Without threads there's no reason for any of this. With a sane thread
design (which would largely be something like a sfork() call - fork but
share the text (as more or less always these days anyway) and the data
segments - but producing separate processes. All the synchronisation
mechanisms would still be needed, but none of this fd nonsense, as fd's
would only be shared by design, not by accident.

However we have what we have, so I am not objecting to the solution proposed
in principle (just some details) - also not promising that any of it will
ever get implemented in NetBSD (none of this is there now). (This is not
my area there, so someone else, with community input, would make that call.)
(0004728)
eblake (manager)
2020-01-13 16:38

Standardization of dup3() and SOCK_CLOEXEC is already the subject of 0000411
(0004797)
geoffclare (manager)
2020-03-16 16:24
edited on: 2020-03-26 15:30

On page 238 line 8018 section <fcntl.h>, change:
The <fcntl.h> header shall define the following symbolic constant used for the fcntl() file descriptor flags, which shall be suitable for use in #if preprocessing directives.

FD_CLOEXEC
Close the file descriptor upon execution of an exec family function.
to:
The <fcntl.h> header shall define the following symbolic constants used for the fcntl() file descriptor flags. The values shall be bitwise-distinct and shall be suitable for use in #if preprocessing directives.

FD_CLOEXEC
Close the file descriptor upon successful execution of an exec family function [SPN]and in the new process image created by posix_spawn() or posix_spawnp()[/SPN].


FD_CLOFORK
Close the file descriptor in any child process created from a process that has the file descriptor open; that is, the child shall not inherit the file descriptor.

On page 238 line 8032 section <fcntl.h>, change:
O_CLOEXEC
The FD_CLOEXEC flag associated with the new descriptor shall be set to close the file descriptor upon execution of an exec family function.
to:
O_CLOEXEC
Atomically set the FD_CLOEXEC flag on the new file descriptor.


O_CLOFORK
Atomically set the FD_CLOFORK flag on the new file descriptor.

On page 387 line 13167 section <sys/socket.h>, after the bug 411 text:
SOCK_CLOEXEC
Create a socket file descriptor with the FD_CLOEXEC flag atomically set on that file descriptor.
add:
SOCK_CLOFORK
Create a socket file descriptor with the FD_CLOFORK flag atomically set on that file descriptor.

On page 388 line 13195 section <sys/socket.h>, after the bug 411 text:
MSG_CMSG_CLOEXEC
Atomically set the FD_CLOEXEC flag on any file descriptors created via SCM_RIGHTS during recvmsg().
add:
MSG_CMSG_CLOFORK
Atomically set the FD_CLOFORK flag on any file descriptors created via SCM_RIGHTS during recvmsg().

On page 497 line 17263 section 2.5.1, change:
A file descriptor is closed by close(), _exit(), or the exec functions when FD_CLOEXEC is set on that file descriptor.
to:
Several functions close file descriptors, including close(), dup2(), _exit(), the exec functions when FD_CLOEXEC is set on a file descriptor, fork() when FD_CLOFORK is set on a file descriptor, and posix_spawn() when either FD_CLOEXEC or FD_CLOFORK is set.

On page 568 line 19882 section accept(), after applying bug 411 change:
If O_NONBLOCK is set on the file description for socket, it is unspecified whether O_NONBLOCK will be set on the file description created by accept().

The accept4() function shall be equivalent to the accept() function, except that the O_NONBLOCK flag shall not be set on the new file description if the flag argument is 0. Additionally, the flag argument can be constructed from a bitwise-inclusive OR of flags from the following list:

SOCK_CLOEXEC
Atomically set the FD_CLOEXEC flag on the new file descriptor.

SOCK_NONBLOCK
Set the O_NONBLOCK file status flag on the new file description.
to:
If O_NONBLOCK is set on the file description for socket, it is implementation-defined whether O_NONBLOCK will be set on the file description created by accept(). FD_CLOEXEC and FD_CLOFORK for the new file descriptor shall be clear, regardless of how they are currently set for socket.

The accept4() function shall be equivalent to the accept() function, except that the state of O_NONBLOCK on the new file description, and FD_CLOEXEC and FD_CLOFORK on the returned file descriptor shall be determined solely by the flag argument, which can be constructed from a bitwise-inclusive OR of flags from the following list:

SOCK_CLOEXEC
Atomically set the FD_CLOEXEC flag on the new file descriptor.

SOCK_CLOFORK
Atomically set the FD_CLOFORK flag on the new file descriptor.

SOCK_NONBLOCK
Set the O_NONBLOCK file status flag on the new file description.

On page 569 line 19914 section accept(), after applying bug 411 change:
The SOCK_CLOEXEC flag of accept4() is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with accept() and then using fcntl() to set the FD_CLOEXEC flag.
to:
The SOCK_CLOEXEC and SOCK_CLOFORK flags of accept4() are necessary to avoid a data race in multi-threaded applications. Without SOCK_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with accept() and then using fcntl() to set the FD_CLOFORK flag. Without SOCK_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

Two designs often used for network servers are multi-threaded servers with a pre-created pool of worker threads, where the thread that accepts the connection request hands over the new file desciptor to a worker thread for servicing, and pre-fork servers with a pre-created pool of worker processes, where the process that accepts the connection request passes the new file desciptor (for example via sendmsg()) to a worker process. In both of these designs, accept4() should be used with the SOCK_CLOFORK flag set. Simpler designs are also sometimes used that do not pre-create a pool. For a multi-threaded server that creates a thread to handle each request, SOCK_CLOFORK should still be used. For a forking server that creates a child to service each request, clearly SOCK_CLOFORK cannot be used if the child is to inherit the file descriptor to be serviced, and therefore this type of server needs to use an alternative method of indicating the end of communications, for example using shutdown(), to ensure the client sees end-of-file, rather than just closing the socket. Such child processes should set FD_CLOFORK on the inherited file descriptor before they attempt to start any additional child proceses to avoid leakage into those children.

On page 714 line 24432 section creat(), after applying bug 411 change:
In multi-threaded applications, the creat() function can leak file descriptors into child processes. Applications should instead use open() with the O_CLOEXEC flag to avoid the leak.
to:
In multi-threaded applications, the creat() function can leak file descriptors into child processes. Applications should instead use open() with the O_CLOEXEC and O_CLOFORK flags to avoid the leak.

On page 752 line 25609 section dup(), change:
Upon successful completion, if fildes is not equal to fildes2, the FD_CLOEXEC flag associated with fildes2 shall be cleared. If fildes is equal to fildes2, the FD_CLOEXEC flag associated with fildes2 shall not be changed.
to:
Upon successful completion, if fildes is not equal to fildes2, the FD_CLOEXEC and FD_CLOFORK flags associated with fildes2 shall be cleared. If fildes is equal to fildes2, the FD_CLOEXEC and FD_CLOFORK flags associated with fildes2 shall not be changed.

On page 752 line 25612 section dup(), after applying bug 411 change:
Additionally, the flag parameter can be set to O_CLOEXEC (from <fcntl.h>) to cause FD_CLOEXEC flag to be set on the new file descriptor.
to:
Additionally, the flag argument can be constructed from a bitwise-inclusive OR of flags (defined in <fcntl.h>) from the following list:

O_CLOEXEC
Atomically set the FD_CLOEXEC flag on fildes2.


O_CLOFORK
Atomically set the FD_CLOFORK flag on fildes2.

On page 753 line 25650 section dup(), change:
In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application should consider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec.
to:
In order to avoid a race condition of leaking an unintended file descriptor into a child process or executed program, an application should consider opening all file descriptors with the FD_CLOFORK or FD_CLOEXEC flag, or both flags, set unless the file descriptor is intended to be inherited by child processes or executed programs, respectively.

On page 753 line 25664 section dup(), after applying bug 411 change:
The dup3() function with the O_CLOEXEC flag is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with dup2() and then using fcntl() to set the FD_CLOEXEC flag. The safe counterpart for avoiding the same race in dup() is the use of the F_DUP_CLOEXEC action of the fcntl() function.
to:
The dup3() function with the O_CLOEXEC and O_CLOFORK flags is necessary to avoid a data race in multi-threaded applications. Without O_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with dup2() and then using fcntl() to set the FD_CLOFORK flag. Without O_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically. The safe counterpart for avoiding the same race with dup() is the use of the F_DUPFD_CLOFORK or F_DUPFD_CLOEXEC action of the fcntl() function.

On page 784 line 26576 section exec, change:
For those file descriptors that remain open, all attributes of the open file description remain unchanged.
to:
For those file descriptors that remain open, all attributes of the open file description shall remain unchanged and the FD_CLOFORK file descriptor flag, if set, shall remain set.

On page 820 line 27760 section fcntl(), change:
The FD_CLOEXEC flag associated with the new file descriptor shall be cleared to keep the file open across calls to one of the exec functions.
to:
The FD_CLOEXEC and FD_CLOFORK flags associated with the new file descriptor shall be cleared.

On page 820 line 27765 section fcntl(), add:
F_DUPFD_CLOFORK
Like F_DUPFD, but the FD_CLOFORK flag associated with the new file descriptor shall be set.

On page 820 line 27771 section fcntl(), change:
If the FD_CLOEXEC flag in the third argument is 0, the file descriptor shall remain open across the exec functions; otherwise, the file descriptor shall be closed upon successful execution of one of the exec functions.
to:
If the FD_CLOEXEC flag in the third argument is set, the file descriptor shall be closed upon successful execution of an exec family function [SPN]and in the new process image created by posix_spawn() or posix_spawnp()[/SPN]; otherwise, the file descriptor shall remain open. If the FD_CLOFORK flag in the third argument is set, the file descriptor shall not be inherited by any child process created from a process that has the file descriptor open; otherwise, the file descriptor shall be inherited.

On page 823 line 27898 section fcntl(), add to RETURN VALUE:
F_DUPFD_CLOFORK
A new file descriptor.

On page 823 line 27923, 27928 section fcntl(), change:
F_DUPFD or F_DUPFD_CLOEXEC
to:
F_DUPFD, F_DUPFD_CLOEXEC, or F_DUPFD_CLOFORK

On page 825 line 28010 section fcntl(), add to APPLICATION USAGE:
In order to set both FD_CLOEXEC and FD_CLOFORK when duplicating a file descriptor, applications should use F_DUPFD_CLOFORK to obtain the new file descriptor with FD_CLOFORK already set, and then use F_SETFD to set the FD_CLOEXEC flag on the new descriptor. (The alternative of first using F_DUPFD_CLOEXEC and then setting FD_CLOFORK with F_SETFD has a timing window where another thread could create a child process which inherits the new descriptor because FD_CLOFORK has not yet been set.)

The FD_CLOFORK flag takes effect for all child processes, not just those created using fork() or _Fork().

On page 897 line 30290 section fork(), change:
The child process shall have its own copy of the parent’s file descriptors.
to:
The child process shall have its own copy of the parent’s file descriptors, except for those whose FD_CLOFORK flag is set (see fcntl()).

On page 1319 line 43930 section mkdtemp(), after the bug 411 text:
O_CLOEXEC Set the FD_CLOEXEC file descriptor flag.
add:
O_CLOFORK Set the FD_CLOFORK file descriptor flag.

On page 1320 line 43980 section mkdtemp(), after applying bug 411 change:
The function mkostemp() with the O_CLOEXEC flag is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a temporary file descriptor with mkstemp() and then using fcntl() to set the FD_CLOEXEC flag.
to:
The O_CLOEXEC and O_CLOFORK flags of mkostemp() are necessary to avoid a data race in multi-threaded applications. Without O_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a temporary file descriptor with mkstemp() and then using fcntl() to set the FD_CLOFORK flag. Without O_CLOEXEC, a temporary file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

On page 1408 line 46762 section open(), add:
The FD_CLOFORK file descriptor flag associated with the new file descriptor shall be cleared unless the O_CLOFORK flag is set in oflag.

On page 1408 line 46780 section open(), add:
O_CLOFORK
If set, the FD_CLOFORK flag for the new file descriptor shall be set.

On page 1408 line 47033 section open(), add:
The O_CLOEXEC and O_CLOFORK flags of open() are necessary to avoid a data race in multi-threaded applications. Without O_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with open() and then using fcntl() to set the FD_CLOFORK flag. Without O_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

On page 1430 line 47470 section pipe(), change:
The O_NONBLOCK and FD_CLOEXEC flags shall be clear on both file descriptors. (The fcntl() function can be used to set both these flags.)
to:
The FD_CLOEXEC and FD_CLOFORK flags shall be clear on both file descriptors. The O_NONBLOCK flag shall be clear on both open file descriptions. (The fcntl() function can be used to set this flag.)

On page 1430 line 47481 section pipe(), after the bug 411 text:
O_CLOEXEC
Atomically set the FD_CLOEXEC flag on both new file descriptors.
add:
O_CLOFORK
Atomically set the FD_CLOFORK flag on both new file descriptors.

On page 1431 line 47530 section pipe(), after applying bug 411 change:
The O_CLOEXEC flag of pipe2() is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with pipe() and then using fcntl() to set the FD_CLOEXEC flag. The O_NONBLOCK flag is for convenience in avoiding additional fcntl() calls.
to:
The O_CLOEXEC and O_CLOFORK flags of pipe2() are necessary to avoid a data race in multi-threaded applications. Without O_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with pipe() and then using fcntl() to set the FD_CLOFORK flag. Without O_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

Since pipes are often used for communication between a parent and child process, O_CLOFORK has to be used with care in order for the pipe to be usable. If the parent will be writing and the child will be reading, O_CLOFORK should be used when creating the pipe, and then fcntl() should be used to clear FD_CLOFORK for the read side of the pipe. This prevents the write side from leaking into other children, ensuring the child will get end-of-file when the parent closes the write side (although the read side can still be leaked). If the parent will be reading and the child will be writing, there is no way to prevent the write side being leaked (short of preventing other threads from creating child processes) in order to ensure the parent gets end-of-file when the child closes the write side, and so the two processes should use an alternative method of indicating the end of communications.

Arranging for FD_CLOEXEC to be set appropriately is more straightforward. The parent should use O_CLOEXEC when creating the pipe and the child should clear FD_CLOEXEC on the side to be passed to the new program before calling an exec family function to execute it.

The O_NONBLOCK flag is for convenience in avoiding additional fcntl() calls.

On page 1437 line 47733 section popen(), after applying bug 411 change:
The popen() function shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process, regardless of the FD_CLOEXEC status of the file descriptor underlying those streams.
to:
The popen() function shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process, regardless of the FD_CLOEXEC or FD_CLOFORK status of the file descriptor underlying those streams.

On page 1437 line 47738 section popen(), after:
... shall be the readable end of the pipe.
add:
The FD_CLOFORK flag shall be cleared on both the STDOUT_FILENO file descriptor passed to the child process and the file descriptor underlying the returned stream.

On page 1437 line 47742 section popen(), after:
... shall be the writable end of the pipe.
add:
The FD_CLOFORK flag shall be cleared on both the STDIN_FILENO file descriptor passed to the child process and the file descriptor underlying the returned stream.

On page 1439 line 47807 section popen(), after the bug 411 text:
... any application worried about the potential file descriptor leak will already be using the e modifier.
add a new paragraph:
Implementations are encouraged to add support for a "wf" mode which creates the pipe as if by calling pipe2() with the O_CLOFORK flag and then clearing FD_CLOFORK for the read side of the pipe. This prevents the write side from leaking into child processes created by other threads, ensuring the child created by popen() will get end-of-file when the parent closes the write side (although the read side can still be leaked). Unfortunately there is no way (short of temporarily preventing other threads from creating child processes, or implementing an atomic create-pipe-and-fork system call) to implement an "rf" mode with the equivalent guarantee that the child created by popen() will be the only writer. Therefore multi-threaded applications that do not have complete control over process creation cannot rely on getting end-of-file on the stream and need to use an alternative method of indicating the end of communications.

On page 1450 line 48133 section posix_openpt(), after the bug 411 text:
O_CLOEXEC
Atomically set the FD_CLOEXEC flag on the file descriptor.
add:
O_CLOFORK
Atomically set the FD_CLOFORK flag on the file descriptor.

On page 1451 line 48179 section posix_openpt(), after applying bug 411 change:
The function posix_openpt() with the O_CLOEXEC flag is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with posix_openpt() and then using fcntl() to set the FD_CLOEXEC flag.
to:
The O_CLOEXEC and O_CLOFORK flags are necessary to avoid a data race in multi-threaded applications. Without O_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread creating a file descriptor with posix_openpt() and then using fcntl() to set the FD_CLOFORK flag. Without O_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

On page 1452 line 48235 section posix_spawn(), change:
If file_actions is a null pointer, then file descriptors open in the calling process shall remain open in the child process, except for those whose close-on-exec flag FD_CLOEXEC is set (see fcntl()).
to:
If file_actions is a null pointer, then file descriptors open in the calling process shall remain open in the child process, except for those whose FD_CLOEXEC or FD_CLOFORK flag is set (see fcntl()), and except for file descriptors that are closed by a fork handler (if fork handlers are called).

On page 1452 line 48240 section posix_spawn(), change:
If file_actions is not NULL, then the file descriptors open in the child process shall be those open in the calling process as modified by the spawn file actions object pointed to by file_actions and the FD_CLOEXEC flag of each remaining open file descriptor after the spawn file actions have been processed. The effective order of processing the spawn file actions shall be:
  1. The set of open file descriptors for the child process shall initially be the same set as is open for the calling process. The child process shall not inherit any file locks, but all remaining attributes of the corresponding open file descriptions (see fcntl()), shall remain unchanged.

  2. The signal mask, signal default actions, and the effective user and group IDs for the child process shall be changed as specified in the attributes object referenced by attrp.

  3. The file actions specified by the spawn file actions object shall be performed in the order in which they were added to the spawn file actions object.

  4. Any file descriptor that has its FD_CLOEXEC flag set (see fcntl()) shall be closed.

to:
If file_actions is not a null pointer, then the file descriptors open in the child process shall be those open in the calling process as modified by FD_CLOFORK file descriptor flags, fork handlers (if they are called), the spawn file actions object pointed to by file_actions, and the FD_CLOEXEC of each remaining open file descriptor after the spawn file actions have been processed. The effective order of processing the spawn file actions shall be:
  1. The set of open file descriptors for the child process shall initially be the same set as is open for the calling process, except for those that have the FD_CLOFORK flag set and any that are closed by fork handlers (if they are called).

  2. The child process shall not inherit any file locks, but all remaining attributes of the corresponding file descriptions (see fcntl()) still open, shall remain unchanged.

  3. The signal mask, signal default actions, and the effective user and group IDs for the child process shall be changed as specified in the attributes object referenced by attrp.

  4. The file actions specified by the spawn file actions object shall be performed in the order in which they were added to the spawn file actions object.

  5. Any file descriptor that has its FD_CLOEXEC flag set shall be closed.


On page 1456 line 48397 section posix_spawn(), change:
... expressed as the set of open file descriptors and their FD_CLOEXEC flags at the time of the call and the spawn file actions object specified in the call.
to:
... expressed as the set of open file descriptors and their FD_CLOEXEC and FD_CLOFORK flags at the time of the call, the actions of fork handlers (if they are called), and the spawn file actions object specified in the call.

On page 1461 line 48592 section posix_spawn_file_actions_addclose(), and
On page 1463 line 48702 section posix_spawn_file_actions_adddup2(), change:
In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application should consider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec.
to:
In order to avoid a race condition of leaking an unintended file descriptor into a child process or executed program, an application should consider opening all file descriptors with the FD_CLOFORK or FD_CLOEXEC flag, or both flags, set unless the file descriptor is intended to be inherited by child processes or executed programs, respectively.

On page 1546 line 50637 section posix_typed_mem_open(), after the bug 411 text:
The FD_CLOEXEC file descriptor flag associated with the new file descriptor shall be cleared unless oflag includes O_CLOEXEC.
add:
The FD_CLOFORK file descriptor flag associated with the new file descriptor shall be cleared unless oflag includes O_CLOFORK.

On page 1546 line 50647 section posix_typed_mem_open(), after applying bug 411 change:
Additionally, the value of oflag may include the following flag:

O_CLOEXEC Set the FD_CLOEXEC file descriptor flag.
to:
Additionally, the value of oflag may include the following flags:

O_CLOEXEC Set the FD_CLOEXEC file descriptor flag.

O_CLOFORK Set the FD_CLOFORK file descriptor flag.

On page 1547 line 50678 section posix_typed_mem_open(), after applying bug 411 change:
The use of the O_CLOEXEC flag to posix_typed_mem_open() is necessary to avoid leaking typed memory file descriptors to child processes, since fcntl() has unspecified results on typed memory objects and therefore cannot be used to set FD_CLOEXEC after the fact.
to:
The use of the O_CLOEXEC and O_CLOFORK flags to posix_typed_mem_open() is necessary to avoid leaking typed memory file descriptors to child processes, since fcntl() has unspecified results on typed memory objects and therefore cannot be used to set FD_CLOEXEC or FD_CLOFORK after the file descriptor has been opened.

On page 1799 line 58230 section recvmsg(), after the bug 411 text:
MSG_CMSG_CLOEXEC
On sockets that permit a cmsg_type of SCM_RIGHTS in the msg_control ancillary data as a means of copying file descriptors into the process, the file descriptors shall be created with the FD_CLOEXEC flag atomically set.
add:
MSG_CMSG_CLOFORK
On sockets that permit a cmsg_type of SCM_RIGHTS in the msg_control ancillary data as a means of copying file descriptors into the process, the file descriptors shall be created with the FD_CLOFORK flag atomically set.

On page 1801 line 58306 section recvmsg(), after applying bug 411 change:
The use of the MSG_CMSG_CLOEXEC flag to recvmsg() when using SCM_RIGHTS to receive file descriptors via ancillary data is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread calling recvmsg() and using fcntl() to set the FD_CLOEXEC flag.
to:
The use of the MSG_CMSG_CLOEXEC and MSG_CMSG_CLOFORK flags to recvmsg() when using SCM_RIGHTS to receive file descriptors via ancillary data is necessary to avoid a data race in multi-threaded applications. Without MSG_CMSG_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread calling recvmsg() and using fcntl() to set the FD_CLOFORK flag. Without MSG_CMSG_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

On page 2004 line 64479 section socket(), after the bug 411 text:
SOCK_CLOEXEC
Atomically set the FD_CLOEXEC flag on the new file descriptor.
add:
SOCK_CLOFORK
Atomically set the FD_CLOFORK flag on the new file descriptor.

On page 2005 line 64511 section socket(), after applying bug 411 change:
The use of the SOCK_CLOEXEC flag in the type argument of socket() is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread calling socket() and using fcntl() to set the FD_CLOEXEC flag.
to:
The use of the SOCK_CLOEXEC and SOCK_CLOFORK flags in the type argument of socket() is necessary to avoid a data race in multi-threaded applications. Without SOCK_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another thread calling socket() and using fcntl() to set the FD_CLOFORK flag. Without SOCK_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

On page 2006 line 64553 section socketpair(), after the bug 411 text:
SOCK_CLOEXEC
Atomically set the FD_CLOEXEC flag on the new file descriptors.
add:
SOCK_CLOFORK
Atomically set the FD_CLOFORK flag on the new file descriptors.

On page 2007 line 64588 section socketpair(), after applying bug 411 change:
The use of the SOCK_CLOEXEC flag in the type argument of socketpair() is necessary to avoid a data race in multi-threaded applications. Without it, a file descriptor is leaked into a child process created by one thread in the window between another thread using socketpair() and using fcntl() to set the FD_CLOEXEC flag. The SOCK_NONBLOCK flag is for convenience in avoiding additional fcntl() calls.
to:
The use of the SOCK_CLOEXEC and SOCK_CLOFORK flags in the type argument of socketpair() is necessary to avoid a data race in multi-threaded applications. Without SOCK_CLOFORK, a file descriptor is leaked into a child process created by one thread in the window between another using socketpair() and using using fcntl() to set the FD_CLOFORK flag. Without SOCK_CLOEXEC, a file descriptor intentionally inherited by child processes is similarly leaked into an executed program if FD_CLOEXEC is not set atomically.

Since socket pairs are often used for communication between a parent and child process, SOCK_CLOFORK has to be used with care in order for the pair to be usable. If the parent will be writing and the child will be reading, SOCK_CLOFORK should be used when creating the pair, and then fcntl() should be used to clear FD_CLOFORK for the read side of the pair. This prevents the write side from leaking into other children, ensuring the child will get end-of-file when the parent closes the write side (although the read side can still be leaked). If the parent will be reading and the child will be writing, or if the socket pair will be used bidirectionally, there is no way to prevent the write side(s) being leaked (short of preventing other threads from creating child processes) in order to ensure the parent gets end-of-file when the child closes its side, and so the two processes should use an alternative method of indicating the end of communications, for example using shutdown().

Arranging for FD_CLOEXEC to be set appropriately is more straightforward. The parent should use SOCK_CLOEXEC when creating the socket pair and the child should clear FD_CLOEXEC on the side to be passed to the new program before calling an exec family function to execute it.

The SOCK_NONBLOCK flag is for convenience in avoiding additional fcntl() calls.

On page 2108 line 67621 section system(), change:
For example, file descriptors that have the FD_CLOEXEC flag set are closed, and ...
to:
For example, file descriptors that have the FD_CLOEXEC or FD_CLOFORK flag set are closed, and ...

On page 2163 line 69329 section tmpfile(), after applying bug 411 change:
Applications should instead use mkostemp() with the O_CLOEXEC flag, followed by fdopen(), to avoid the leak.
to:
Applications should instead use mkostemp() with the O_CLOEXEC or O_CLOFORK flag, or both, followed by fdopen(), to avoid the leak.


(0004802)
geoffclare (manager)
2020-03-26 15:32

In the March 26, 2020 teleconference Note: 0004797 was updated with further changes for accept().

- Issue History
Date Modified Username Field Change
2020-01-12 10:50 nate_karstens New Issue
2020-01-12 10:50 nate_karstens Name => Nate Karstens
2020-01-12 10:50 nate_karstens Organization => Garmin
2020-01-12 10:50 nate_karstens Section => fcntl, open, socket
2020-01-12 10:50 nate_karstens Page Number => Unknown
2020-01-12 10:50 nate_karstens Line Number => Unknown
2020-01-13 07:28 kre Note Added: 0004725
2020-01-13 16:37 eblake Relationship added related to 0000411
2020-01-13 16:38 eblake Note Added: 0004728
2020-03-05 17:30 eblake Relationship added related to 0001317
2020-03-16 16:24 geoffclare Note Added: 0004797
2020-03-16 16:31 geoffclare Note Edited: 0004797
2020-03-16 16:33 geoffclare Interp Status => ---
2020-03-16 16:33 geoffclare Final Accepted Text => Note: 0004797
2020-03-16 16:33 geoffclare Status New => Resolved
2020-03-16 16:33 geoffclare Resolution Open => Accepted As Marked
2020-03-16 16:33 geoffclare Tag Attached: issue8
2020-03-19 15:21 geoffclare Note Edited: 0004797
2020-03-26 15:29 geoffclare Note Edited: 0004797
2020-03-26 15:30 geoffclare Note Edited: 0004797
2020-03-26 15:32 geoffclare Note Added: 0004802
2020-04-29 17:43 eblake Relationship added related to 0001337
2020-05-13 15:31 geoffclare Status Resolved => Applied
2023-02-23 15:32 eblake Relationship added related to 0000768
2024-06-11 09:08 agadmin Status Applied => Closed
2024-08-15 15:39 geoffclare Relationship added related to 0001851


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker