diff --git a/shell/ash.c b/shell/ash.c index 7c53946ce..e6d02f69c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5426,11 +5426,11 @@ redirect(union node *redir, int flags) /* Careful to not accidentally "save" * to the same fd as right side fd in N>&M */ int minfd = right_fd < 10 ? 10 : right_fd + 1; +#if defined(F_DUPFD_CLOEXEC) + i = fcntl(fd, F_DUPFD_CLOEXEC, minfd); +#else i = fcntl(fd, F_DUPFD, minfd); -/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds - * are closed in popredir() in the child, preventing them from leaking - * into child. (popredir() also cleans up the mess in case of failures) - */ +#endif if (i == -1) { i = errno; if (i != EBADF) { @@ -5445,6 +5445,9 @@ redirect(union node *redir, int flags) remember_to_close: i = CLOSED; } else { /* fd is open, save its copy */ +#if !defined(F_DUPFD_CLOEXEC) + fcntl(i, F_SETFD, FD_CLOEXEC); +#endif /* "exec fd>&-" should not close fds * which point to script file(s). * Force them to be restored afterwards */ diff --git a/shell/ash_test/ash-redir/redir_leak.right b/shell/ash_test/ash-redir/redir_leak.right new file mode 100644 index 000000000..b1c48292b --- /dev/null +++ b/shell/ash_test/ash-redir/redir_leak.right @@ -0,0 +1,6 @@ +4 +4 +4 +4 +4 +4 diff --git a/shell/ash_test/ash-redir/redir_leak.tests b/shell/ash_test/ash-redir/redir_leak.tests new file mode 100755 index 000000000..c8a9c6343 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_leak.tests @@ -0,0 +1,10 @@ +# Each of these should show only four lines: +# fds 0,1,2 are stdio; fd 3 is open by opendir() in ls. +# This test detects bugs where redirects leave stray open fds. + +ls -1 /proc/self/fd | wc -l +ls -1 /proc/self/fd >/proc/self/fd/1 | wc -l +ls -1 /proc/self/fd >/proc/self/fd/1 2>&1 | wc -l +echo "`ls -1 /proc/self/fd `" | wc -l +echo "`ls -1 /proc/self/fd >/proc/self/fd/1 `" | wc -l +echo "`ls -1 /proc/self/fd >/proc/self/fd/1 2>&1 `" | wc -l diff --git a/shell/hush_test/hush-redir/redir_leak.right b/shell/hush_test/hush-redir/redir_leak.right new file mode 100644 index 000000000..b1c48292b --- /dev/null +++ b/shell/hush_test/hush-redir/redir_leak.right @@ -0,0 +1,6 @@ +4 +4 +4 +4 +4 +4 diff --git a/shell/hush_test/hush-redir/redir_leak.tests b/shell/hush_test/hush-redir/redir_leak.tests new file mode 100755 index 000000000..c8a9c6343 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_leak.tests @@ -0,0 +1,10 @@ +# Each of these should show only four lines: +# fds 0,1,2 are stdio; fd 3 is open by opendir() in ls. +# This test detects bugs where redirects leave stray open fds. + +ls -1 /proc/self/fd | wc -l +ls -1 /proc/self/fd >/proc/self/fd/1 | wc -l +ls -1 /proc/self/fd >/proc/self/fd/1 2>&1 | wc -l +echo "`ls -1 /proc/self/fd `" | wc -l +echo "`ls -1 /proc/self/fd >/proc/self/fd/1 `" | wc -l +echo "`ls -1 /proc/self/fd >/proc/self/fd/1 2>&1 `" | wc -l