From 9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 28 Mar 2018 18:35:07 +0200 Subject: ash,hush: fix "saved" redirected fds still visible in children Based on a patch by Mark Marshall function old new delta dup_CLOEXEC - 49 +49 fcntl_F_DUPFD 46 - -46 Signed-off-by: Denys Vlasenko --- 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(-) create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 5e281b5ce..85690e555 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -255,6 +255,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 @@ -5448,12 +5451,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) @@ -5569,7 +5575,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? */ @@ -5584,7 +5590,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 6e64efb70..012ec219f 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1501,12 +1501,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) @@ -6890,7 +6893,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(); @@ -6904,7 +6907,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(); @@ -7622,6 +7625,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]); @@ -9347,7 +9354,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); @@ -9420,10 +9427,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 -- cgit v1.2.3