From edd35de39a456c900054b66f8bbb0db6c0a25709 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 6 Jun 2015 19:44:29 -0700 Subject: [PATCH] sh - Sync to FreeBSD d038ee76 part 2/2 (d) Reapply 330497ceac - fix O_CLOEXEC race in open() and fhopen() * Fix an O_CLOEXEC race where a fork/exec can race an open(...O_CLOEXEC) and improperly inherit the descriptor. --- bin/sh/input.c | 7 +++++-- bin/sh/jobs.c | 15 +++++++++++---- bin/sh/main.c | 2 +- bin/sh/redir.c | 7 ++++++- bin/sh/shell.h | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/bin/sh/input.c b/bin/sh/input.c index 8117e755e4..80630980e0 100644 --- a/bin/sh/input.c +++ b/bin/sh/input.c @@ -368,10 +368,10 @@ setinputfile(const char *fname, int push) int fd2; INTOFF; - if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0) + if ((fd = open(fname, O_RDONLY | O_CLOEXEC_MAYBE)) < 0) error("cannot open %s: %s", fname, strerror(errno)); if (fd < 10) { - fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10); + fd2 = fcntl(fd, F_DUPFD_CLOEXEC_MAYBE, 10); close(fd); if (fd2 < 0) error("Out of file descriptors"); @@ -390,6 +390,9 @@ setinputfile(const char *fname, int push) void setinputfd(int fd, int push) { +#if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC) + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif if (push) { pushfile(); parsefile->buf = ckmalloc(BUFSIZ + 1); diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index 59dc0431f0..a5d97d955a 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -146,12 +146,12 @@ setjobctl(int on) if (on) { if (ttyfd != -1) close(ttyfd); - if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) < 0) { + if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC_MAYBE)) < 0) { i = 0; while (i <= 2 && !isatty(i)) i++; if (i > 2 || - (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) { + (ttyfd = fcntl(i, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) { jobctl_notty(); return; } @@ -161,17 +161,24 @@ setjobctl(int on) * Keep our TTY file descriptor out of the way of * the user's redirections. */ - if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) { + if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) { jobctl_notty(); return; } close(ttyfd); ttyfd = i; } +#if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC) + if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) { + close(ttyfd); + ttyfd = -1; + goto out; + } +#endif do { /* while we are in the background */ initialpgrp = tcgetpgrp(ttyfd); if (initialpgrp < 0) { - jobctl_notty(); +out: jobctl_notty(); return; } if (initialpgrp != getpgrp()) { diff --git a/bin/sh/main.c b/bin/sh/main.c index c483d19b41..7f01d2b331 100644 --- a/bin/sh/main.c +++ b/bin/sh/main.c @@ -257,7 +257,7 @@ read_profile(const char *name) if (expandedname == NULL) return; INTOFF; - if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0) + if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC_MAYBE)) >= 0) setinputfd(fd, 1); INTON; if (fd < 0) diff --git a/bin/sh/redir.c b/bin/sh/redir.c index 674c150eb2..a3327236d7 100644 --- a/bin/sh/redir.c +++ b/bin/sh/redir.c @@ -132,7 +132,7 @@ redirect(union node *redir, int flags) if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { INTOFF; - if ((i = fcntl(fd, F_DUPFD_CLOEXEC, 10)) == -1) { + if ((i = fcntl(fd, F_DUPFD_CLOEXEC_MAYBE, 10)) == -1) { switch (errno) { case EBADF: i = CLOSED; @@ -143,6 +143,11 @@ redirect(union node *redir, int flags) break; } } +#if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC) + else { + fcntl(i, F_SETFD, FD_CLOEXEC); + } +#endif sv->renamed[fd] = i; INTON; } diff --git a/bin/sh/shell.h b/bin/sh/shell.h index 74f11a33fd..a628d351d9 100644 --- a/bin/sh/shell.h +++ b/bin/sh/shell.h @@ -52,6 +52,22 @@ #define JOBS 1 /* #define DEBUG 1 */ +/* + * Allow compilation with older versions of DragonFly or on + * systems without these features. + */ +#ifdef F_DUPFD_CLOEXEC +#define F_DUPFD_CLOEXEC_MAYBE F_DUPFD_CLOEXEC +#else +#define F_DUPFD_CLOEXEC_MAYBE F_DUPFD +#endif + +#ifdef O_CLOEXEC +#define O_CLOEXEC_MAYBE O_CLOEXEC +#else +#define O_CLOEXEC_MAYBE 0 +#endif + /* * Type of used arithmetics. SUSv3 requires us to have at least signed long. */ -- 2.41.0