ash: fix open fds leaking in redirects. Closes 9561
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 7 Jan 2017 09:15:01 +0000 (10:15 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 10 Jan 2017 15:55:51 +0000 (16:55 +0100)
commit e19923f6652a638ac39c84012e97f52cf5a7568e deleted clearredir()
call in shellexec():

ash: [REDIR] Remove redundant CLOEXEC calls
Upstream commit:

Now that we're marking file descriptors as CLOEXEC in savefd, we no longer
need to close them on exec or in setinputfd.

but it missed one place where we don't set CLOEXEC. Fixing this.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-redir/redir_leak.right [new file with mode: 0644]
shell/ash_test/ash-redir/redir_leak.tests [new file with mode: 0755]
shell/hush_test/hush-redir/redir_leak.right [new file with mode: 0644]
shell/hush_test/hush-redir/redir_leak.tests [new file with mode: 0755]

index 7c53946cefb4c7afbd317f0af7700ac16961e7f0..e6d02f69cb2fe912b7a969655bd0f5715304b32c 100644 (file)
@@ -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 (file)
index 0000000..b1c4829
--- /dev/null
@@ -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 (executable)
index 0000000..c8a9c63
--- /dev/null
@@ -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 (file)
index 0000000..b1c4829
--- /dev/null
@@ -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 (executable)
index 0000000..c8a9c63
--- /dev/null
@@ -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