From 22f741484391c3b2fd94881fd41c8c0df9749e95 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 24 Jul 2008 22:34:43 +0000 Subject: ash: prevent exec NN>&- from closing fd used for script reading --- shell/ash.c | 33 ++++++++++++---- shell/ash_test/ash-redir/redir4.right | 1 + shell/ash_test/ash-redir/redir4.tests | 72 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 shell/ash_test/ash-redir/redir4.right create mode 100755 shell/ash_test/ash-redir/redir4.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index ec3bd09..bd2433c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4848,7 +4848,10 @@ openredirect(union node *redir) */ /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). * old code was doing close(to) prior to copyfd() to achieve the same */ -#define COPYFD_EXACT ((int)~INT_MAX) +enum { + COPYFD_EXACT = (int)~(INT_MAX), + COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1), +}; static int copyfd(int from, int to) { @@ -4981,7 +4984,19 @@ redirect(union node *redir, int flags) /* EBADF: it is not open - good, remember to close it */ remember_to_close: i = CLOSED; - } /* else: fd is open, save its copy */ + } else { /* fd is open, save its copy */ + /* "exec fd>&-" should not close fds + * which point to script file(s). + * Force them to be restored afterwards */ + struct parsefile *pf = g_parsefile; + while (pf) { + if (fd == pf->fd) { + i |= COPYFD_RESTORE; + break; + } + pf = pf->prev; + } + } if (fd == 2) copied_fd2 = i; sv->two_fd[sv_pos].orig = fd; @@ -4990,7 +5005,7 @@ redirect(union node *redir, int flags) } if (newfd < 0) { /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ - if (redir->ndup.dupfd < 0) { /* "NN>&-" */ + if (redir->ndup.dupfd < 0) { /* "fd>&-" */ close(fd); } else { copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); @@ -5021,17 +5036,19 @@ popredir(int drop) rp = redirlist; for (i = 0; i < rp->pair_count; i++) { int fd = rp->two_fd[i].orig; - if (rp->two_fd[i].copy == CLOSED) { + int copy = rp->two_fd[i].copy; + if (copy == CLOSED) { if (!drop) close(fd); continue; } - if (rp->two_fd[i].copy != EMPTY) { - if (!drop) { + if (copy != EMPTY) { + if (!drop || (copy & COPYFD_RESTORE)) { + copy &= ~COPYFD_RESTORE; /*close(fd);*/ - copyfd(rp->two_fd[i].copy, fd | COPYFD_EXACT); + copyfd(copy, fd | COPYFD_EXACT); } - close(rp->two_fd[i].copy); + close(copy); } } redirlist = rp->next; diff --git a/shell/ash_test/ash-redir/redir4.right b/shell/ash_test/ash-redir/redir4.right new file mode 100644 index 0000000..d86bac9 --- /dev/null +++ b/shell/ash_test/ash-redir/redir4.right @@ -0,0 +1 @@ +OK diff --git a/shell/ash_test/ash-redir/redir4.tests b/shell/ash_test/ash-redir/redir4.tests new file mode 100755 index 0000000..4bdf5ae --- /dev/null +++ b/shell/ash_test/ash-redir/redir4.tests @@ -0,0 +1,72 @@ +# ash uses fd 10 (usually) for reading the script +exec 13>&- +exec 12>&- +exec 11>&- +exec 10>&- +# some amount of input is prefetched. +# make sure final echo is far enough to not be prefetched. +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +echo "OK" -- cgit v1.1