From: John Marino Date: Wed, 12 Jun 2013 23:42:14 +0000 (+0200) Subject: rtld: Sync 5/7 - Fix fd leak with parallel dlopen and fork X-Git-Tag: v3.6.0rc~973 X-Git-Url: https://gitweb.dragonflybsd.org/~nant/dragonfly.git/commitdiff_plain/042953d8e3173add9848fe8ddbedc413a77cccc4 rtld: Sync 5/7 - Fix fd leak with parallel dlopen and fork Rtld did not set FD_CLOEXEC on its internal file descriptors; therefore, such a file descriptor may be passed to a process created by another thread running in parallel to dlopen() or fdlopen(). No other threads are expected to be running during parsing of the hints and libmap files but the file descriptors need not be passed to child processes so add O_CLOEXEC there as well. As the F_DUPFD_CLOEXEC support was added in the kernel today, rtld will temporarily fall back to separate dup/cloexec commands if F_DUPFD_CLOEXEC fails. This fallback should be removed before 3.6 branches. Taken from: FreeBSD SVN 242587 (04 NOV 2012) --- diff --git a/libexec/rtld-elf/libmap.c b/libexec/rtld-elf/libmap.c index ce9c261611..96d305a8a8 100644 --- a/libexec/rtld-elf/libmap.c +++ b/libexec/rtld-elf/libmap.c @@ -116,7 +116,7 @@ lmc_parse_file(char *path) } } - fd = open(rpath, O_RDONLY); + fd = open(rpath, O_RDONLY | O_CLOEXEC); if (fd == -1) { dbg("lm_parse_file: open(\"%s\") failed, %s", rpath, rtld_strerror(errno)); diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 67da21c7a5..2c213d1a40 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1677,7 +1677,7 @@ gethints(bool nostdlib) /* Keep from trying again in case the hints file is bad. */ hints = ""; - if ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1) + if ((fd = open(ld_elf_hints_path, O_RDONLY | O_CLOEXEC)) == -1) return (NULL); if (read(fd, &hdr, sizeof hdr) != sizeof hdr || hdr.magic != ELFHINTS_MAGIC || hdr.version != 1) { @@ -2122,17 +2122,25 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) */ fd = -1; if (fd_u == -1) { - if ((fd = open(path, O_RDONLY)) == -1) { + if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) { _rtld_error("Cannot open \"%s\"", path); free(path); return (NULL); } } else { - fd = dup(fd_u); + fd = fcntl(fd_u, F_DUPFD_CLOEXEC, 0); if (fd == -1) { - _rtld_error("Cannot dup fd"); - free(path); - return (NULL); + /* + * Temporary, remove at 3.6 branch + * User might not have latest kernel installed + * so fall back to old command for a while + */ + fd = dup(fd_u); + if (fd == -1 || (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)) { + _rtld_error("Cannot dup fd"); + free(path); + return (NULL); + } } } if (fstat(fd, &sb) == -1) {