This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
gold patch committed: Set close-on-exec flag
- From: Ian Lance Taylor <iant at google dot com>
- To: binutils at sourceware dot org
- Date: Tue, 17 Mar 2009 10:11:55 -0700
- Subject: gold patch committed: Set close-on-exec flag
A gold plugin may exec another program. In fact, this happens when LTO.
In that case we do not want gold's file descriptors to leak to the other
program. It's not a security hole, but since gold is file descriptor
hungry it can mean that the other program can't open very many
descriptors of its own. I committed this patch to set the close-on-exec
flag for every file descriptor opened by gold. The patch uses O_CLOEXEC
if available. If it is not available, then we only set FD_CLOEXEC if we
have any plugins, as without any plugins there is no point to making the
extra system call.
Ian
2009-03-17 Ian Lance Taylor <iant@google.com>
* descriptors.cc: Include "options.h".
(FD_CLOEXEC, O_CLOEXEC): Define if not defined.
(Descriptors::open): Always use O_CLOEXEC when opening a new
descriptor. If we have a plugin, and O_CLOEXEC was not defined,
then set FD_CLOEXEC.
Index: descriptors.cc
===================================================================
RCS file: /cvs/src/src/gold/descriptors.cc,v
retrieving revision 1.4
diff -p -u -r1.4 descriptors.cc
--- descriptors.cc 28 Feb 2009 03:05:08 -0000 1.4
+++ descriptors.cc 17 Mar 2009 17:08:14 -0000
@@ -28,9 +28,20 @@
#include <unistd.h>
#include "parameters.h"
+#include "options.h"
#include "gold-threads.h"
#include "descriptors.h"
+// Very old systems may not define FD_CLOEXEC.
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+// O_CLOEXEC is only available on newer systems.
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
namespace gold
{
@@ -87,6 +98,10 @@ Descriptors::open(int descriptor, const
while (true)
{
+ // We always want to set the close-on-exec flag; we don't
+ // require callers to pass it.
+ flags |= O_CLOEXEC;
+
int new_descriptor = ::open(name, flags, mode);
if (new_descriptor < 0
&& errno != ENFILE
@@ -109,24 +124,35 @@ Descriptors::open(int descriptor, const
if (new_descriptor >= 0)
{
- Hold_optional_lock hl(this->lock_);
-
- if (static_cast<size_t>(new_descriptor)
- >= this->open_descriptors_.size())
- this->open_descriptors_.resize(new_descriptor + 64);
+ // If we have any plugins, we really do need to set the
+ // close-on-exec flag, even if O_CLOEXEC is not defined.
+ // FIXME: In some cases O_CLOEXEC may be defined in the
+ // header file but not supported by the kernel.
+ // Unfortunately there doesn't seem to be any obvious way to
+ // detect that, as unknown flags passed to open are ignored.
+ if (O_CLOEXEC == 0 && parameters->options().has_plugins())
+ fcntl(new_descriptor, F_SETFD, FD_CLOEXEC);
+
+ {
+ Hold_optional_lock hl(this->lock_);
+
+ if (static_cast<size_t>(new_descriptor)
+ >= this->open_descriptors_.size())
+ this->open_descriptors_.resize(new_descriptor + 64);
+
+ Open_descriptor* pod = &this->open_descriptors_[new_descriptor];
+ pod->name = name;
+ pod->stack_next = -1;
+ pod->inuse = true;
+ pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
+ pod->is_on_stack = false;
+
+ ++this->current_;
+ if (this->current_ >= this->limit_)
+ this->close_some_descriptor();
- Open_descriptor* pod = &this->open_descriptors_[new_descriptor];
- pod->name = name;
- pod->stack_next = -1;
- pod->inuse = true;
- pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
- pod->is_on_stack = false;
-
- ++this->current_;
- if (this->current_ >= this->limit_)
- this->close_some_descriptor();
-
- return new_descriptor;
+ return new_descriptor;
+ }
}
// We ran out of file descriptors.