Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Apply *_CLOEXEC flags to system calls which can be used with

to avoid file descriptor leaks to the child process.
- Pass O_CLOEXEC to open(2) system call if it is defined.
- Use fcntl(2) and F_DUPFD_CLOEXEC instead of dup(2)
  if F_DUPFD_CLOEXEC is defined.
- Set FD_CLOEXEC with fcntl(2) if a file descriptor does not have.
  • Loading branch information...
commit 60141df1e89400928525f3c915be085f68c1ff1a 1 parent 864a2c1
@ggcueroad ggcueroad authored
View
1  CMakeLists.txt
@@ -904,6 +904,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
+CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD)
CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
View
3  build/cmake/config.h.in
@@ -390,6 +390,9 @@ typedef uint64_t uintmax_t;
*/
#cmakedefine HAVE_DIRENT_H 1
+/* Define to 1 if you have the `dirfd' function. */
+#cmakedefine HAVE_DIRFD 1
+
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
View
2  configure.ac
@@ -433,7 +433,7 @@ AC_FUNC_VPRINTF
# To avoid necessity for including windows.h or special forward declaration
# workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *'
AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *])
-AC_CHECK_FUNCS([chflags chown chroot ctime_r])
+AC_CHECK_FUNCS([chflags chown chroot ctime_r dirfd])
AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fork])
AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate])
AC_CHECK_FUNCS([futimens futimes futimesat])
View
1  libarchive/archive_private.h
@@ -134,6 +134,7 @@ int __archive_check_magic(struct archive *, unsigned int magic,
void __archive_errx(int retvalue, const char *msg) __LA_DEAD;
+void __archive_ensure_cloexec_flag(int fd);
int __archive_mktemp(const char *tmpdir);
int __archive_clean(struct archive *);
View
21 libarchive/archive_read_disk_entry_from_file.c
@@ -104,6 +104,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#include "archive_private.h"
#include "archive_read_disk_private.h"
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
/*
* Linux and FreeBSD plug this obvious hole in POSIX.1e in
* different ways.
@@ -193,9 +197,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (fd < 0) {
if (a->tree != NULL)
fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
+ O_RDONLY | O_NONBLOCK | O_CLOEXEC);
else
- fd = open(path, O_RDONLY | O_NONBLOCK);
+ fd = open(path, O_RDONLY | O_NONBLOCK |
+ O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
}
if (fd >= 0) {
int stflags;
@@ -335,13 +341,14 @@ setup_mac_metadata(struct archive_read_disk *a,
ret = ARCHIVE_WARN;
goto cleanup;
}
- tempfd = open(tempfile, O_RDONLY);
+ tempfd = open(tempfile, O_RDONLY | O_CLOEXEC);
if (tempfd < 0) {
archive_set_error(&a->archive, errno,
"Could not open extended attribute file");
ret = ARCHIVE_WARN;
goto cleanup;
}
+ __archive_ensure_cloexec_flag(tempfd);
if (fstat(tempfd, &copyfile_stat)) {
archive_set_error(&a->archive, errno,
"Could not check size of extended attributes");
@@ -1035,14 +1042,15 @@ setup_sparse(struct archive_read_disk *a,
path = archive_entry_pathname(entry);
if (a->tree != NULL)
*fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
+ O_RDONLY | O_NONBLOCK | O_CLOEXEC);
else
- *fd = open(path, O_RDONLY | O_NONBLOCK);
+ *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
}
+ __archive_ensure_cloexec_flag(*fd);
}
/* Initialize buffer to avoid the error valgrind complains about. */
@@ -1148,12 +1156,13 @@ setup_sparse(struct archive_read_disk *a,
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
- *fd = open(path, O_RDONLY | O_NONBLOCK);
+ *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
}
+ __archive_ensure_cloexec_flag(*fd);
initial_off = 0;
}
View
69 libarchive/archive_read_disk_posix.c
@@ -105,6 +105,9 @@ __FBSDID("$FreeBSD$");
#ifndef O_BINARY
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
/*-
* This is a new directory-walking system that addresses a number
@@ -361,6 +364,7 @@ static int setup_sparse(struct archive_read_disk *, struct archive_entry *);
static int close_and_restore_time(int fd, struct tree *,
struct restore_time *);
static int open_on_current_dir(struct tree *, const char *, int);
+static int tree_dup(int);
static struct archive_vtable *
@@ -717,7 +721,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
* Open the current file.
*/
if (t->entry_fd < 0) {
- int flags = O_RDONLY | O_BINARY;
+ int flags = O_RDONLY | O_BINARY | O_CLOEXEC;
/*
* Eliminate or reduce cache effects if we can.
@@ -740,6 +744,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
#endif
t->entry_fd = open_on_current_dir(t,
tree_current_access_path(t), flags);
+ __archive_ensure_cloexec_flag(t->entry_fd);
#if defined(O_NOATIME)
/*
* When we did open the file with O_NOATIME flag,
@@ -987,7 +992,9 @@ next_entry(struct archive_read_disk *a, struct tree *t,
int stflags;
t->entry_fd = open_on_current_dir(t,
- tree_current_access_path(t), O_RDONLY | O_NONBLOCK);
+ tree_current_access_path(t),
+ O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(t->entry_fd);
if (t->entry_fd >= 0) {
r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
&stflags);
@@ -1484,7 +1491,8 @@ setup_current_filesystem(struct archive_read_disk *a)
* where current is.
*/
int fd = openat(tree_current_dir_fd(t),
- tree_current_access_path(t), O_RDONLY);
+ tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
if (fd < 0) {
archive_set_error(&a->archive, errno,
"openat failed");
@@ -1662,7 +1670,8 @@ setup_current_filesystem(struct archive_read_disk *a)
* where current is.
*/
int fd = openat(tree_current_dir_fd(t),
- tree_current_access_path(t), O_RDONLY);
+ tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
if (fd < 0) {
archive_set_error(&a->archive, errno,
"openat failed");
@@ -1770,7 +1779,8 @@ setup_current_filesystem(struct archive_read_disk *a)
* where current is.
*/
int fd = openat(tree_current_dir_fd(t),
- tree_current_access_path(t), O_RDONLY);
+ tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
if (fd < 0) {
archive_set_error(&a->archive, errno,
"openat failed");
@@ -1954,6 +1964,28 @@ open_on_current_dir(struct tree *t, const char *path, int flags)
#endif
}
+static int
+tree_dup(int fd)
+{
+ int new_fd;
+#ifdef F_DUPFD_CLOEXEC
+ static volatile int can_dupfd_cloexec = 1;
+
+ if (can_dupfd_cloexec) {
+ new_fd = fcntl(fd, F_DUPFD_CLOEXEC);
+ if (new_fd != -1)
+ return (new_fd);
+ /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,
+ * but it cannot be used. So we have to try dup(). */
+ /* We won't try F_DUPFD_CLOEXEC. */
+ can_dupfd_cloexec = 0;
+ }
+#endif /* F_DUPFD_CLOEXEC */
+ new_fd = dup(fd);
+ __archive_ensure_cloexec_flag(new_fd);
+ return (new_fd);
+}
+
/*
* Add a directory path to the current stack.
*/
@@ -2054,8 +2086,9 @@ tree_reopen(struct tree *t, const char *path, int restore_time)
tree_push(t, path, 0, 0, 0, NULL);
t->stack->flags = needsFirstVisit;
t->maxOpenCount = t->openCount = 1;
- t->initial_dir_fd = open(".", O_RDONLY);
- t->working_dir_fd = dup(t->initial_dir_fd);
+ t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(t->initial_dir_fd);
+ t->working_dir_fd = tree_dup(t->initial_dir_fd);
return (t);
}
@@ -2065,11 +2098,12 @@ tree_descent(struct tree *t)
int flag, new_fd, r = 0;
t->dirname_length = archive_strlen(&t->path);
- flag = O_RDONLY;
+ flag = O_RDONLY | O_CLOEXEC;
#if defined(O_DIRECTORY)
flag |= O_DIRECTORY;
#endif
new_fd = open_on_current_dir(t, t->stack->name.s, flag);
+ __archive_ensure_cloexec_flag(new_fd);
if (new_fd < 0) {
t->tree_errno = errno;
r = TREE_ERROR_DIR;
@@ -2103,8 +2137,10 @@ tree_ascend(struct tree *t)
prev_dir_fd = t->working_dir_fd;
if (te->flags & isDirLink)
new_fd = te->symlink_parent_fd;
- else
- new_fd = open_on_current_dir(t, "..", O_RDONLY);
+ else {
+ new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(new_fd);
+ }
if (new_fd < 0) {
t->tree_errno = errno;
r = TREE_ERROR_FATAL;
@@ -2267,11 +2303,16 @@ tree_dir_next_posix(struct tree *t)
#endif
#if defined(HAVE_FDOPENDIR)
- if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
-#else
- if (tree_enter_working_dir(t) != 0 ||
- (t->d = opendir(".")) == NULL) {
+ t->d = fdopendir(tree_dup(t->working_dir_fd));
+#else /* HAVE_FDOPENDIR */
+ if (tree_enter_working_dir(t) == 0) {
+ t->d = opendir(".");
+#if HAVE_DIRFD || defined(dirfd)
+ __archive_ensure_cloexec_flag(dirfd(t->d));
#endif
+ }
+#endif /* HAVE_FDOPENDIR */
+ if (t->d == NULL) {
r = tree_ascend(t); /* Undo "chdir" */
tree_pop(t);
t->tree_errno = errno;
View
7 libarchive/archive_read_open_filename.c
@@ -60,11 +60,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_filename.c 201093 2009
#endif
#include "archive.h"
+#include "archive_private.h"
#include "archive_string.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
struct read_file_data {
int fd;
@@ -244,7 +248,8 @@ file_open(struct archive *a, void *client_data)
filename = "";
} else if (mine->filename_type == FNT_MBS) {
filename = mine->filename.m;
- fd = open(filename, O_RDONLY | O_BINARY);
+ fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
if (fd < 0) {
archive_set_error(a, errno,
"Failed to open '%s'", filename);
View
6 libarchive/archive_read_support_format_mtree.c
@@ -55,6 +55,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#ifndef O_BINARY
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
#define MTREE_HAS_DEVICE 0x0001
#define MTREE_HAS_FFLAGS 0x0002
@@ -1119,7 +1122,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
if (archive_entry_filetype(entry) == AE_IFREG ||
archive_entry_filetype(entry) == AE_IFDIR) {
- mtree->fd = open(path, O_RDONLY | O_BINARY);
+ mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(mtree->fd);
if (mtree->fd == -1 &&
(errno != ENOENT ||
archive_strlen(&mtree->contents_name) > 0)) {
View
40 libarchive/archive_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009,2010 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
@@ -50,6 +50,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#include "archive_private.h"
#include "archive_string.h"
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
/* Generic initialization of 'struct archive' objects. */
int
__archive_clean(struct archive *a)
@@ -385,6 +389,7 @@ __archive_mktemp(const char *tmpdir)
fd = mkstemp(temp_name.s);
if (fd < 0)
goto exit_tmpfile;
+ __archive_ensure_cloexec_flag(fd);
unlink(temp_name.s);
exit_tmpfile:
archive_string_free(&temp_name);
@@ -438,7 +443,8 @@ __archive_mktemp(const char *tmpdir)
archive_strcat(&temp_name, "XXXXXXXXXX");
ep = temp_name.s + archive_strlen(&temp_name);
- fd = open("/dev/random", O_RDONLY);
+ fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(fd);
if (fd < 0)
seed = time(NULL);
else {
@@ -452,10 +458,12 @@ __archive_mktemp(const char *tmpdir)
p = tp;
while (p < ep)
*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
- fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
+ fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
+ 0600);
} while (fd < 0 && errno == EEXIST);
if (fd < 0)
goto exit_tmpfile;
+ __archive_ensure_cloexec_flag(fd);
unlink(temp_name.s);
exit_tmpfile:
archive_string_free(&temp_name);
@@ -464,3 +472,29 @@ __archive_mktemp(const char *tmpdir)
#endif /* HAVE_MKSTEMP */
#endif /* !_WIN32 || __CYGWIN__ */
+
+/*
+ * Set FD_CLOEXEC flag to a file descriptor if it is not set.
+ * We have to set the flag if the platform does not provide O_CLOEXEC
+ * or F_DUPFD_CLOEXEC flags.
+ *
+ * Note: This function is absolutely called after creating a new file
+ * descriptor even if the platform seemingly provides O_CLOEXEC or
+ * F_DUPFD_CLOEXEC macros because it is possible that the platform
+ * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
+ */
+void
+__archive_ensure_cloexec_flag(int fd)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ (void)fd; /* UNSED */
+#else
+ int flags;
+
+ if (fd >= 0) {
+ flags = fcntl(fd, F_GETFD);
+ if (flags != -1 && (flags & FD_CLOEXEC) == 0)
+ fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ }
+#endif
+}
View
19 libarchive/archive_write_disk_posix.c
@@ -131,6 +131,9 @@ __FBSDID("$FreeBSD$");
#ifndef O_BINARY
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
struct fixup_entry {
struct fixup_entry *next;
@@ -1012,7 +1015,8 @@ edit_deep_directories(struct archive_write_disk *a)
return;
/* Try to record our starting dir. */
- a->restore_pwd = open(".", O_RDONLY | O_BINARY);
+ a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(a->restore_pwd);
if (a->restore_pwd < 0)
return;
@@ -1237,7 +1241,9 @@ create_filesystem_object(struct archive_write_disk *a)
a->todo = 0;
a->deferred = 0;
} else if (r == 0 && a->filesize > 0) {
- a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY);
+ a->fd = open(a->name,
+ O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(a->fd);
if (a->fd < 0)
r = errno;
}
@@ -1274,7 +1280,8 @@ create_filesystem_object(struct archive_write_disk *a)
/* FALLTHROUGH */
case AE_IFREG:
a->fd = open(a->name,
- O_WRONLY | O_CREAT | O_EXCL | O_BINARY, mode);
+ O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
+ __archive_ensure_cloexec_flag(a->fd);
r = (a->fd < 0);
break;
case AE_IFCHR:
@@ -2425,8 +2432,10 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
return (ARCHIVE_OK);
/* If we weren't given an fd, open it ourselves. */
- if (myfd < 0)
- myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY);
+ if (myfd < 0) {
+ myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(myfd);
+ }
if (myfd < 0)
return (ARCHIVE_OK);
View
7 libarchive/archive_write_open_filename.c
@@ -46,11 +46,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 200
#endif
#include "archive.h"
+#include "archive_private.h"
#include "archive_string.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
struct write_file_data {
int fd;
@@ -136,7 +140,7 @@ file_open(struct archive *a, void *client_data)
const char *mbs;
mine = (struct write_file_data *)client_data;
- flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+ flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC;
/*
* Open the file.
@@ -171,6 +175,7 @@ file_open(struct archive *a, void *client_data)
return (ARCHIVE_FATAL);
}
mine->fd = open(mbs, flags, 0666);
+ __archive_ensure_cloexec_flag(mine->fd);
#endif
if (mine->fd < 0) {
if (mbs != NULL)
Please sign in to comment.
Something went wrong with that request. Please try again.