diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-03-28 18:35:07 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-03-28 18:35:07 +0200 |
| commit | 9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d (patch) | |
| tree | 9bf53c82f5fccd4a5ed13915b8039080c563ce07 /shell | |
| parent | e4defe826be49b8ef19912ba4cb291bfe9166e0f (diff) | |
| download | busybox-w32-9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d.tar.gz busybox-w32-9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d.tar.bz2 busybox-w32-9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d.zip | |
ash,hush: fix "saved" redirected fds still visible in children
Based on a patch by Mark Marshall <mark.marshall@omicronenergy.com>
function old new delta
dup_CLOEXEC - 49 +49
fcntl_F_DUPFD 46 - -46
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
14 files changed, 92 insertions, 13 deletions
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; | |||
| 255 | # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ | 255 | # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ |
| 256 | #endif | 256 | #endif |
| 257 | 257 | ||
| 258 | #ifndef F_DUPFD_CLOEXEC | ||
| 259 | # define F_DUPFD_CLOEXEC F_DUPFD | ||
| 260 | #endif | ||
| 258 | #ifndef PIPE_BUF | 261 | #ifndef PIPE_BUF |
| 259 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 262 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
| 260 | #endif | 263 | #endif |
| @@ -5448,12 +5451,15 @@ dup2_or_raise(int from, int to) | |||
| 5448 | return newfd; | 5451 | return newfd; |
| 5449 | } | 5452 | } |
| 5450 | static int | 5453 | static int |
| 5451 | fcntl_F_DUPFD(int fd, int avoid_fd) | 5454 | dup_CLOEXEC(int fd, int avoid_fd) |
| 5452 | { | 5455 | { |
| 5453 | int newfd; | 5456 | int newfd; |
| 5454 | repeat: | 5457 | repeat: |
| 5455 | newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); | 5458 | newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); |
| 5456 | if (newfd < 0) { | 5459 | if (newfd >= 0) { |
| 5460 | if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ | ||
| 5461 | fcntl(newfd, F_SETFD, FD_CLOEXEC); | ||
| 5462 | } else { /* newfd < 0 */ | ||
| 5457 | if (errno == EBUSY) | 5463 | if (errno == EBUSY) |
| 5458 | goto repeat; | 5464 | goto repeat; |
| 5459 | if (errno == EINTR) | 5465 | if (errno == EINTR) |
| @@ -5569,7 +5575,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
| 5569 | for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) { | 5575 | for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) { |
| 5570 | /* If we collide with an already moved fd... */ | 5576 | /* If we collide with an already moved fd... */ |
| 5571 | if (fd == sq->two_fd[i].moved_to) { | 5577 | if (fd == sq->two_fd[i].moved_to) { |
| 5572 | new_fd = fcntl_F_DUPFD(fd, avoid_fd); | 5578 | new_fd = dup_CLOEXEC(fd, avoid_fd); |
| 5573 | sq->two_fd[i].moved_to = new_fd; | 5579 | sq->two_fd[i].moved_to = new_fd; |
| 5574 | TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); | 5580 | TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); |
| 5575 | if (new_fd < 0) /* what? */ | 5581 | if (new_fd < 0) /* what? */ |
| @@ -5584,7 +5590,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
| 5584 | } | 5590 | } |
| 5585 | 5591 | ||
| 5586 | /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */ | 5592 | /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */ |
| 5587 | new_fd = fcntl_F_DUPFD(fd, avoid_fd); | 5593 | new_fd = dup_CLOEXEC(fd, avoid_fd); |
| 5588 | TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); | 5594 | TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); |
| 5589 | if (new_fd < 0) { | 5595 | if (new_fd < 0) { |
| 5590 | if (errno != EBADF) | 5596 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | busybox find /proc/self/fd >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | { busybox find /proc/self/fd; } >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | { busybox find /proc/self/fd; true; } >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | 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) | |||
| 1501 | free(strings); | 1501 | free(strings); |
| 1502 | } | 1502 | } |
| 1503 | 1503 | ||
| 1504 | static int fcntl_F_DUPFD(int fd, int avoid_fd) | 1504 | static int dup_CLOEXEC(int fd, int avoid_fd) |
| 1505 | { | 1505 | { |
| 1506 | int newfd; | 1506 | int newfd; |
| 1507 | repeat: | 1507 | repeat: |
| 1508 | newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); | 1508 | newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); |
| 1509 | if (newfd < 0) { | 1509 | if (newfd >= 0) { |
| 1510 | if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ | ||
| 1511 | fcntl(newfd, F_SETFD, FD_CLOEXEC); | ||
| 1512 | } else { /* newfd < 0 */ | ||
| 1510 | if (errno == EBUSY) | 1513 | if (errno == EBUSY) |
| 1511 | goto repeat; | 1514 | goto repeat; |
| 1512 | if (errno == EINTR) | 1515 | if (errno == EINTR) |
| @@ -6890,7 +6893,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | |||
| 6890 | if (sq) for (; sq[i].orig_fd >= 0; i++) { | 6893 | if (sq) for (; sq[i].orig_fd >= 0; i++) { |
| 6891 | /* If we collide with an already moved fd... */ | 6894 | /* If we collide with an already moved fd... */ |
| 6892 | if (fd == sq[i].moved_to) { | 6895 | if (fd == sq[i].moved_to) { |
| 6893 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); | 6896 | sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd); |
| 6894 | debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); | 6897 | debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); |
| 6895 | if (sq[i].moved_to < 0) /* what? */ | 6898 | if (sq[i].moved_to < 0) /* what? */ |
| 6896 | xfunc_die(); | 6899 | xfunc_die(); |
| @@ -6904,7 +6907,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | |||
| 6904 | } | 6907 | } |
| 6905 | 6908 | ||
| 6906 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ | 6909 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ |
| 6907 | moved_to = fcntl_F_DUPFD(fd, avoid_fd); | 6910 | moved_to = dup_CLOEXEC(fd, avoid_fd); |
| 6908 | debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); | 6911 | debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); |
| 6909 | if (moved_to < 0 && errno != EBADF) | 6912 | if (moved_to < 0 && errno != EBADF) |
| 6910 | xfunc_die(); | 6913 | xfunc_die(); |
| @@ -7622,6 +7625,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
| 7622 | */ | 7625 | */ |
| 7623 | close_saved_fds_and_FILE_fds(); | 7626 | close_saved_fds_and_FILE_fds(); |
| 7624 | //FIXME: should also close saved redir fds | 7627 | //FIXME: should also close saved redir fds |
| 7628 | //This casuses test failures in | ||
| 7629 | //redir_children_should_not_see_saved_fd_2.tests | ||
| 7630 | //redir_children_should_not_see_saved_fd_3.tests | ||
| 7631 | //if you replace "busybox find" with just "find" in them | ||
| 7625 | /* Without this, "rm -i FILE" can't be ^C'ed: */ | 7632 | /* Without this, "rm -i FILE" can't be ^C'ed: */ |
| 7626 | switch_off_special_sigs(G.special_sig_mask); | 7633 | switch_off_special_sigs(G.special_sig_mask); |
| 7627 | debug_printf_exec("running applet '%s'\n", argv[0]); | 7634 | debug_printf_exec("running applet '%s'\n", argv[0]); |
| @@ -9347,7 +9354,7 @@ int hush_main(int argc, char **argv) | |||
| 9347 | G_saved_tty_pgrp = 0; | 9354 | G_saved_tty_pgrp = 0; |
| 9348 | 9355 | ||
| 9349 | /* try to dup stdin to high fd#, >= 255 */ | 9356 | /* try to dup stdin to high fd#, >= 255 */ |
| 9350 | G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); | 9357 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
| 9351 | if (G_interactive_fd < 0) { | 9358 | if (G_interactive_fd < 0) { |
| 9352 | /* try to dup to any fd */ | 9359 | /* try to dup to any fd */ |
| 9353 | G_interactive_fd = dup(STDIN_FILENO); | 9360 | G_interactive_fd = dup(STDIN_FILENO); |
| @@ -9420,10 +9427,10 @@ int hush_main(int argc, char **argv) | |||
| 9420 | #elif ENABLE_HUSH_INTERACTIVE | 9427 | #elif ENABLE_HUSH_INTERACTIVE |
| 9421 | /* No job control compiled in, only prompt/line editing */ | 9428 | /* No job control compiled in, only prompt/line editing */ |
| 9422 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 9429 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { |
| 9423 | G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); | 9430 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
| 9424 | if (G_interactive_fd < 0) { | 9431 | if (G_interactive_fd < 0) { |
| 9425 | /* try to dup to any fd */ | 9432 | /* try to dup to any fd */ |
| 9426 | G_interactive_fd = dup(STDIN_FILENO); | 9433 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO); |
| 9427 | if (G_interactive_fd < 0) | 9434 | if (G_interactive_fd < 0) |
| 9428 | /* give up */ | 9435 | /* give up */ |
| 9429 | G_interactive_fd = 0; | 9436 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | busybox find /proc/self/fd >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | { busybox find /proc/self/fd; } >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | 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 @@ | |||
| 1 | /proc/self/fd | ||
| 2 | /proc/self/fd/0 | ||
| 3 | /proc/self/fd/1 | ||
| 4 | /proc/self/fd/2 | ||
| 5 | /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 @@ | |||
| 1 | # The "find" should not see "saved" (duplicated) fd #1 | ||
| 2 | # Explicitly use bbox find, since other implementations of "find" | ||
| 3 | # may open other descriptors as well. | ||
| 4 | { busybox find /proc/self/fd; true; } >tmp_$$.out | ||
| 5 | cat tmp_$$.out | ||
| 6 | rm -f tmp_$$.out | ||
