diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-31 04:32:06 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-31 04:35:18 +0200 |
commit | 32fdf2f9fc9a617918672d71579f4ad42eb9bde9 (patch) | |
tree | f73fbaa257aeb6810557fe7a36ae6b4b3dfb72e4 /shell | |
parent | 035486c7500c09616a6c1040d8e70923532a5c2d (diff) | |
download | busybox-w32-32fdf2f9fc9a617918672d71579f4ad42eb9bde9.tar.gz busybox-w32-32fdf2f9fc9a617918672d71579f4ad42eb9bde9.tar.bz2 busybox-w32-32fdf2f9fc9a617918672d71579f4ad42eb9bde9.zip |
ash,hush: ">&10" redirects to script/tty fds should not work
The fact that shell has open fds to tty and/or scripts should be
unobservable, if possible. In particular, if redirect tries to dup
one of them via ">&script_fd", it's better to pretend that script_fd
is closed, and thus redirect fails with EBADF.
Fixes these two testcase failures:
ash-redir/redir_to_bad_fd.tests
hush-redir/redir_to_bad_fd3.tests
function old new delta
redirect 1018 1129 +111
setup_redirects 250 359 +109
readtoken1 2651 2655 +4
cmdloop 185 187 +2
changepath 194 195 +1
save_fd_on_redirect 203 194 -9
evaltree 501 484 -17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/2 up/down: 227/-26) Total: 201 bytes
text data bss dec hex filename
914553 485 6848 921886 e111e busybox_old
914754 485 6848 922087 e11e7 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 39 | ||||
-rw-r--r-- | shell/hush.c | 52 |
2 files changed, 72 insertions, 19 deletions
diff --git a/shell/ash.c b/shell/ash.c index ac676c2dc..5c2e06599 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -5503,6 +5503,31 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) | |||
5503 | return 0; /* "we did not close fd" */ | 5503 | return 0; /* "we did not close fd" */ |
5504 | } | 5504 | } |
5505 | 5505 | ||
5506 | static int | ||
5507 | internally_opened_fd(int fd, struct redirtab *sq) | ||
5508 | { | ||
5509 | int i; | ||
5510 | #if JOBS | ||
5511 | if (fd == ttyfd) | ||
5512 | return 1; | ||
5513 | #endif | ||
5514 | /* If this one of script's fds? */ | ||
5515 | if (fd != 0) { | ||
5516 | struct parsefile *pf = g_parsefile; | ||
5517 | while (pf) { | ||
5518 | if (fd == pf->pf_fd) | ||
5519 | return 1; | ||
5520 | pf = pf->prev; | ||
5521 | } | ||
5522 | } | ||
5523 | |||
5524 | if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) { | ||
5525 | if (fd == sq->two_fd[i].moved_to) | ||
5526 | return 1; | ||
5527 | } | ||
5528 | return 0; | ||
5529 | } | ||
5530 | |||
5506 | /* | 5531 | /* |
5507 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, | 5532 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, |
5508 | * old file descriptors are stashed away so that the redirection can be | 5533 | * old file descriptors are stashed away so that the redirection can be |
@@ -5567,15 +5592,11 @@ redirect(union node *redir, int flags) | |||
5567 | close(fd); | 5592 | close(fd); |
5568 | } | 5593 | } |
5569 | } else { | 5594 | } else { |
5570 | ///TODO: if _newfd_ is a script fd or saved fd, then simulate EBADF! | 5595 | /* if newfd is a script fd or saved fd, simulate EBADF */ |
5571 | //if (newfd == ttyfd) { | 5596 | if (internally_opened_fd(newfd, sv)) { |
5572 | // errno = EBADF; | 5597 | errno = EBADF; |
5573 | // ash_msg_and_raise_perror("A %d", newfd); | 5598 | ash_msg_and_raise_perror("%d", newfd); |
5574 | //} | 5599 | } |
5575 | //if (newfd == g_parsefile->pf_fd) { | ||
5576 | // errno = EBADF; | ||
5577 | // ash_msg_and_raise_perror("B %d", newfd); | ||
5578 | //} | ||
5579 | dup2_or_raise(newfd, fd); | 5600 | dup2_or_raise(newfd, fd); |
5580 | if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */ | 5601 | if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */ |
5581 | close(close_fd); | 5602 | close(close_fd); |
diff --git a/shell/hush.c b/shell/hush.c index d4101d66f..cc785d36b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1546,6 +1546,16 @@ static void close_all_FILE_list(void) | |||
1546 | } | 1546 | } |
1547 | } | 1547 | } |
1548 | #endif | 1548 | #endif |
1549 | static int fd_in_FILEs(int fd) | ||
1550 | { | ||
1551 | struct FILE_list *fl = G.FILE_list; | ||
1552 | while (fl) { | ||
1553 | if (fl->fd == fd) | ||
1554 | return 1; | ||
1555 | fl = fl->next; | ||
1556 | } | ||
1557 | return 0; | ||
1558 | } | ||
1549 | 1559 | ||
1550 | 1560 | ||
1551 | /* Helpers for setting new $n and restoring them back | 1561 | /* Helpers for setting new $n and restoring them back |
@@ -6686,9 +6696,9 @@ static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, in | |||
6686 | static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | 6696 | static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) |
6687 | { | 6697 | { |
6688 | int moved_to; | 6698 | int moved_to; |
6689 | int i = 0; | 6699 | int i; |
6690 | 6700 | ||
6691 | if (sq) while (sq[i].orig_fd >= 0) { | 6701 | if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { |
6692 | /* If we collide with an already moved fd... */ | 6702 | /* If we collide with an already moved fd... */ |
6693 | if (fd == sq[i].moved_to) { | 6703 | if (fd == sq[i].moved_to) { |
6694 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); | 6704 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); |
@@ -6702,7 +6712,6 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | |||
6702 | debug_printf_redir("redirect_fd %d: already moved\n", fd); | 6712 | debug_printf_redir("redirect_fd %d: already moved\n", fd); |
6703 | return sq; | 6713 | return sq; |
6704 | } | 6714 | } |
6705 | i++; | ||
6706 | } | 6715 | } |
6707 | 6716 | ||
6708 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ | 6717 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ |
@@ -6717,8 +6726,7 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd) | |||
6717 | { | 6726 | { |
6718 | int i; | 6727 | int i; |
6719 | 6728 | ||
6720 | i = 0; | 6729 | if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { |
6721 | if (sq) while (sq[i].orig_fd >= 0) { | ||
6722 | /* If we collide with an already moved fd... */ | 6730 | /* If we collide with an already moved fd... */ |
6723 | if (fd == sq[i].orig_fd) { | 6731 | if (fd == sq[i].orig_fd) { |
6724 | /* Examples: | 6732 | /* Examples: |
@@ -6730,7 +6738,6 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd) | |||
6730 | debug_printf_redir("redirect_fd %d: already moved or closed\n", fd); | 6738 | debug_printf_redir("redirect_fd %d: already moved or closed\n", fd); |
6731 | return sq; | 6739 | return sq; |
6732 | } | 6740 | } |
6733 | i++; | ||
6734 | } | 6741 | } |
6735 | 6742 | ||
6736 | debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd); | 6743 | debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd); |
@@ -6747,7 +6754,8 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
6747 | avoid_fd = 9; | 6754 | avoid_fd = 9; |
6748 | 6755 | ||
6749 | #if ENABLE_HUSH_INTERACTIVE | 6756 | #if ENABLE_HUSH_INTERACTIVE |
6750 | if (fd != 0 && fd == G.interactive_fd) { | 6757 | if (fd == G.interactive_fd) { |
6758 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ | ||
6751 | G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd); | 6759 | G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd); |
6752 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); | 6760 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); |
6753 | return 1; /* "we closed fd" */ | 6761 | return 1; /* "we closed fd" */ |
@@ -6775,8 +6783,8 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
6775 | static void restore_redirects(struct squirrel *sq) | 6783 | static void restore_redirects(struct squirrel *sq) |
6776 | { | 6784 | { |
6777 | if (sq) { | 6785 | if (sq) { |
6778 | int i = 0; | 6786 | int i; |
6779 | while (sq[i].orig_fd >= 0) { | 6787 | for (i = 0; sq[i].orig_fd >= 0; i++) { |
6780 | if (sq[i].moved_to >= 0) { | 6788 | if (sq[i].moved_to >= 0) { |
6781 | /* We simply die on error */ | 6789 | /* We simply die on error */ |
6782 | debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd); | 6790 | debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd); |
@@ -6786,7 +6794,6 @@ static void restore_redirects(struct squirrel *sq) | |||
6786 | debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd); | 6794 | debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd); |
6787 | close(sq[i].orig_fd); | 6795 | close(sq[i].orig_fd); |
6788 | } | 6796 | } |
6789 | i++; | ||
6790 | } | 6797 | } |
6791 | free(sq); | 6798 | free(sq); |
6792 | } | 6799 | } |
@@ -6796,6 +6803,25 @@ static void restore_redirects(struct squirrel *sq) | |||
6796 | restore_redirected_FILEs(); | 6803 | restore_redirected_FILEs(); |
6797 | } | 6804 | } |
6798 | 6805 | ||
6806 | static int internally_opened_fd(int fd, struct squirrel *sq) | ||
6807 | { | ||
6808 | int i; | ||
6809 | |||
6810 | #if ENABLE_HUSH_INTERACTIVE | ||
6811 | if (fd == G.interactive_fd) | ||
6812 | return 1; | ||
6813 | #endif | ||
6814 | /* If this one of script's fds? */ | ||
6815 | if (fd_in_FILEs(fd)) | ||
6816 | return 1; | ||
6817 | |||
6818 | if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { | ||
6819 | if (fd == sq[i].moved_to) | ||
6820 | return 1; | ||
6821 | } | ||
6822 | return 0; | ||
6823 | } | ||
6824 | |||
6799 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, | 6825 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, |
6800 | * and stderr if they are redirected. */ | 6826 | * and stderr if they are redirected. */ |
6801 | static int setup_redirects(struct command *prog, struct squirrel **sqp) | 6827 | static int setup_redirects(struct command *prog, struct squirrel **sqp) |
@@ -6878,6 +6904,12 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
6878 | * and second redirect closes 3! Restore code then closes 3 again. | 6904 | * and second redirect closes 3! Restore code then closes 3 again. |
6879 | */ | 6905 | */ |
6880 | } else { | 6906 | } else { |
6907 | /* if newfd is a script fd or saved fd, simulate EBADF */ | ||
6908 | if (internally_opened_fd(newfd, sqp ? *sqp : NULL)) { | ||
6909 | //errno = EBADF; | ||
6910 | //bb_perror_msg_and_die("can't duplicate file descriptor"); | ||
6911 | newfd = -1; /* same effect as code above */ | ||
6912 | } | ||
6881 | xdup2(newfd, redir->rd_fd); | 6913 | xdup2(newfd, redir->rd_fd); |
6882 | if (redir->rd_dup == REDIRFD_TO_FILE) | 6914 | if (redir->rd_dup == REDIRFD_TO_FILE) |
6883 | /* "rd_fd > FILE" */ | 6915 | /* "rd_fd > FILE" */ |