Project

General

Profile

Actions

Feature #5041

closed

Set FD_CLOEXEC for all fds (except 0, 1, 2)

Added by akr (Akira Tanaka) almost 13 years ago. Updated over 12 years ago.

Status:
Closed
Target version:
-
[ruby-core:38140]

Description

I'd like to set FD_CLOEXEC for all file descriptors (except 0, 1, 2,
i.e. standard input/output/error).

I talked this issue with kosaki and matz at RubyKaigi 2011 and
matz said "do it" and see that someone will cry or not.

FD_CLOEXEC prevents fd leakage for command execution.
See the problem of fd leakage for
"FIO42-C. Ensure files are properly closed when they are no longer needed".
https://www.securecoding.cert.org/confluence/display/seccode/FIO42-C.+Ensure+files+are+properly+closed+when+they+are+no+longer+needed

This is an incompatible change for programs which use fd leakage intentionally.
For example, valgrind has options such as --log-fd=, --input-fd=, etc.
gpg has --status-fd, --logger-fd, etc.
openssl command has -passin fd:number and -passout fd:number.
xterm has -S option which takes a fd.
...

Currently, system() and exec() method leak fds.
But IO.popen() and spawn() doesn't leak fds.
Windows doesn't inherit fds for child processes.
So this issue is only affected to system() and exec() on Unix.

(spawn(), which is available since Ruby 1.9.1, doesn't leak fds because
:close_others option is true by default.
IO.popen() doesn't leak fds since [ruby-dev:457].
The behavior is preserved for Ruby 1.9 by :close_others is true by default
for IO.popen().)

If a program uses fd leakage, system() and exec() call should be changed.
For example,
system("valgrind", "--log-fd=#{N}", ...) should be changed to
system("valgrind", "--log-fd=#{N}", ..., N=>N).
See the document of spawn() for details of the option N=>N.
This option, N=>N, can be used since Ruby 1.9.1.

FD_CLOEXEC is set by fcntl(F_SETFD) on Unix.
However Ruby can use O_CLOEXEC, dup3 and other new mechanisms to avoid
race conditions if they are available.

The race condition is real problem because Ruby invokes open() system call in
a blocking region to open a named pipe without stucking.
So, new fd can be born at any point.
This means the new fd (without FD_CLOEXEC) may be born just before fork().
This race can be fixed by O_CLOEXEC (if available).
The semantics of "FD_CLOEXEC for all fds" makes us possible to use O_CLOEXEC
without harm.


Files

close-on-exec-by-default.patch (18.6 KB) close-on-exec-by-default.patch akr (Akira Tanaka), 08/11/2011 02:43 PM

Subtasks 1 (0 open1 closed)

Bug #5475: r33507以降SolarisでPTYが使えないClosed10/24/2011Actions

Related issues 2 (0 open2 closed)

Related to Ruby master - Feature #4512: [PATCH] ext/fcntl/fcntl.c: add F_DUPFD_CLOEXEC constantClosedkosaki (Motohiro KOSAKI)03/20/2011Actions
Has duplicate Ruby master - Feature #1291: O_CLOEXEC flag missing for Kernel::openClosedkosaki (Motohiro KOSAKI)03/15/2009Actions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0