aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-31 04:32:06 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-31 04:35:18 +0200
commit32fdf2f9fc9a617918672d71579f4ad42eb9bde9 (patch)
treef73fbaa257aeb6810557fe7a36ae6b4b3dfb72e4 /shell
parent035486c7500c09616a6c1040d8e70923532a5c2d (diff)
downloadbusybox-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.c39
-rw-r--r--shell/hush.c52
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
5506static int
5507internally_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
1549static 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
6686static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) 6696static 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)
6775static void restore_redirects(struct squirrel *sq) 6783static 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
6806static 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. */
6801static int setup_redirects(struct command *prog, struct squirrel **sqp) 6827static 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" */