From: Akira Tanaka Date: 2011-07-21T08:25:04+09:00 Subject: [ruby-core:38281] [Ruby 1.9 - Feature #5041] Set FD_CLOEXEC for all fds (except 0, 1, 2) Issue #5041 has been updated by Akira Tanaka. Assignee set to Akira Tanaka Eric Wong wrote: > I support this proposal for Ruby 2.0. Very few applications depend on > FD passing via exec() and they can easily be updated to set > close_on_exec=false. > > I've just updated git://bogomips.org/unicorn.git myself. Thank you for your support for this issue. My (and matz's) intent is for 1.9.4. I'm not sure the next version will be 1.9.4 or 2.0, though. I don't recommend io.close_on_exec = false for multithreaded programs. There is a race condition which cause fd leakage if another thread invokes system(). (I guess unicorn has no problem because it is not multithreaded.) So I may change the default of :close_others to true even for system() and exec(). ---------------------------------------- Feature #5041: Set FD_CLOEXEC for all fds (except 0, 1, 2) http://redmine.ruby-lang.org/issues/5041 Author: Akira Tanaka Status: Open Priority: Normal Assignee: Akira Tanaka Category: Target version: 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. -- http://redmine.ruby-lang.org