[git commit branch/1_28_stable] ash, hush: fix "saved" redirected fds still visible in children

Denys Vlasenko vda.linux at googlemail.com
Sun Apr 1 11:04:11 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=b1aa377a3f23e5e547cd142bb82a81b811c788a2
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/1_28_stable

Based on a patch by Mark Marshall <mark.marshall at omicronenergy.com>

function                                             old     new   delta
dup_CLOEXEC                                            -      49     +49
fcntl_F_DUPFD                                         46       -     -46

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                                        | 16 ++++++++++-----
 .../redir_children_should_not_see_saved_fd_1.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_1.tests |  6 ++++++
 .../redir_children_should_not_see_saved_fd_2.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_2.tests |  6 ++++++
 .../redir_children_should_not_see_saved_fd_3.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_3.tests |  6 ++++++
 shell/hush.c                                       | 23 ++++++++++++++--------
 .../redir_children_should_not_see_saved_fd_1.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_1.tests |  6 ++++++
 .../redir_children_should_not_see_saved_fd_2.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_2.tests |  6 ++++++
 .../redir_children_should_not_see_saved_fd_3.right |  5 +++++
 .../redir_children_should_not_see_saved_fd_3.tests |  6 ++++++
 14 files changed, 92 insertions(+), 13 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index b73a79975..699b6c0ee 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -239,6 +239,9 @@ typedef long arith_t;
 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 #endif
 
+#ifndef F_DUPFD_CLOEXEC
+# define F_DUPFD_CLOEXEC F_DUPFD
+#endif
 #ifndef PIPE_BUF
 # define PIPE_BUF 4096           /* amount of buffering in a pipe */
 #endif
@@ -5392,12 +5395,15 @@ dup2_or_raise(int from, int to)
 	return newfd;
 }
 static int
-fcntl_F_DUPFD(int fd, int avoid_fd)
+dup_CLOEXEC(int fd, int avoid_fd)
 {
 	int newfd;
  repeat:
-	newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
-	if (newfd < 0) {
+	newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
+	if (newfd >= 0) {
+		if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
+			fcntl(newfd, F_SETFD, FD_CLOEXEC);
+	} else { /* newfd < 0 */
 		if (errno == EBUSY)
 			goto repeat;
 		if (errno == EINTR)
@@ -5513,7 +5519,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
 	for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
 		/* If we collide with an already moved fd... */
 		if (fd == sq->two_fd[i].moved_to) {
-			new_fd = fcntl_F_DUPFD(fd, avoid_fd);
+			new_fd = dup_CLOEXEC(fd, avoid_fd);
 			sq->two_fd[i].moved_to = new_fd;
 			TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
 			if (new_fd < 0) /* what? */
@@ -5528,7 +5534,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
 	}
 
 	/* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
-	new_fd = fcntl_F_DUPFD(fd, avoid_fd);
+	new_fd = dup_CLOEXEC(fd, avoid_fd);
 	TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
 	if (new_fd < 0) {
 		if (errno != EBADF)
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests
new file mode 100755
index 000000000..544c810e3
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+busybox find /proc/self/fd >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests
new file mode 100755
index 000000000..43777cade
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+{ busybox find /proc/self/fd; } >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests
new file mode 100755
index 000000000..0a21173bd
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+{ busybox find /proc/self/fd; true; } >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out
diff --git a/shell/hush.c b/shell/hush.c
index df1b046ab..b76b8fda4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1478,12 +1478,15 @@ static void free_strings(char **strings)
 	free(strings);
 }
 
-static int fcntl_F_DUPFD(int fd, int avoid_fd)
+static int dup_CLOEXEC(int fd, int avoid_fd)
 {
 	int newfd;
  repeat:
-	newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
-	if (newfd < 0) {
+	newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
+	if (newfd >= 0) {
+		if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
+			fcntl(newfd, F_SETFD, FD_CLOEXEC);
+	} else { /* newfd < 0 */
 		if (errno == EBUSY)
 			goto repeat;
 		if (errno == EINTR)
@@ -6766,7 +6769,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
 	if (sq) for (; sq[i].orig_fd >= 0; i++) {
 		/* If we collide with an already moved fd... */
 		if (fd == sq[i].moved_to) {
-			sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd);
+			sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
 			debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
 			if (sq[i].moved_to < 0) /* what? */
 				xfunc_die();
@@ -6780,7 +6783,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
 	}
 
 	/* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
-	moved_to = fcntl_F_DUPFD(fd, avoid_fd);
+	moved_to = dup_CLOEXEC(fd, avoid_fd);
 	debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
 	if (moved_to < 0 && errno != EBADF)
 		xfunc_die();
@@ -7429,6 +7432,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
 				 */
 				close_saved_fds_and_FILE_fds();
 //FIXME: should also close saved redir fds
+//This casuses test failures in
+//redir_children_should_not_see_saved_fd_2.tests
+//redir_children_should_not_see_saved_fd_3.tests
+//if you replace "busybox find" with just "find" in them
 				/* Without this, "rm -i FILE" can't be ^C'ed: */
 				switch_off_special_sigs(G.special_sig_mask);
 				debug_printf_exec("running applet '%s'\n", argv[0]);
@@ -9133,7 +9140,7 @@ int hush_main(int argc, char **argv)
 			G_saved_tty_pgrp = 0;
 
 		/* try to dup stdin to high fd#, >= 255 */
-		G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254);
+		G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
 		if (G_interactive_fd < 0) {
 			/* try to dup to any fd */
 			G_interactive_fd = dup(STDIN_FILENO);
@@ -9206,10 +9213,10 @@ int hush_main(int argc, char **argv)
 #elif ENABLE_HUSH_INTERACTIVE
 	/* No job control compiled in, only prompt/line editing */
 	if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
-		G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254);
+		G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
 		if (G_interactive_fd < 0) {
 			/* try to dup to any fd */
-			G_interactive_fd = dup(STDIN_FILENO);
+			G_interactive_fd = dup_CLOEXEC(STDIN_FILENO);
 			if (G_interactive_fd < 0)
 				/* give up */
 				G_interactive_fd = 0;
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests
new file mode 100755
index 000000000..544c810e3
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+busybox find /proc/self/fd >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests
new file mode 100755
index 000000000..43777cade
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+{ busybox find /proc/self/fd; } >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right
new file mode 100644
index 000000000..46ab7f5d1
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right
@@ -0,0 +1,5 @@
+/proc/self/fd
+/proc/self/fd/0
+/proc/self/fd/1
+/proc/self/fd/2
+/proc/self/fd/3
diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests
new file mode 100755
index 000000000..0a21173bd
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests
@@ -0,0 +1,6 @@
+# The "find" should not see "saved" (duplicated) fd #1
+# Explicitly use bbox find, since other implementations of "find"
+# may open other descriptors as well.
+{ busybox find /proc/self/fd; true; } >tmp_$$.out
+cat tmp_$$.out
+rm -f tmp_$$.out


More information about the busybox-cvs mailing list