From 6a0ad2506116f4ddc3f9f617a90ba04a57eeef88 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 25 Jul 2008 13:34:05 +0000 Subject: ash: dont allow e.g. exec <&10 to attach to stript's fd! function old new delta is_hidden_fd - 61 +61 redirect 1135 1164 +29 popstring 134 140 +6 printf_main 635 637 +2 evalvar 1374 1376 +2 echo_main 294 296 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 5/0 up/down: 102/0) Total: 102 bytes --- coreutils/echo.c | 11 +++++++---- coreutils/printf.c | 7 +++++-- shell/ash.c | 47 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/coreutils/echo.c b/coreutils/echo.c index 36cb6b3af..decca095f 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -46,8 +46,11 @@ int echo_main(int argc UNUSED_PARAM, char **argv) * even if libc receives EBADF on write attempts, it feels determined * to output data no matter what. So it will try later, * and possibly will clobber future output. Not good. */ - if (dup2(1, 1) != 1) - return -1; +// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? + if (fcntl(1, F_GETFL) == -1) + return 1; /* match coreutils 6.10 (sans error msg to stderr) */ + //if (dup2(1, 1) != 1) - old way + // return 1; arg = *++argv; if (!arg) @@ -58,8 +61,8 @@ int echo_main(int argc UNUSED_PARAM, char **argv) char eflag = 0; /* We must check that stdout is not closed. */ - if (dup2(1, 1) != 1) - return -1; + if (fcntl(1, F_GETFL) == -1) + return 1; while (1) { arg = *++argv; diff --git a/coreutils/printf.c b/coreutils/printf.c index 72acbc751..76524f706 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -348,8 +348,11 @@ int printf_main(int argc UNUSED_PARAM, char **argv) * even if libc receives EBADF on write attempts, it feels determined * to output data no matter what. So it will try later, * and possibly will clobber future output. Not good. */ - if (dup2(1, 1) != 1) - return -1; +// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? + if (fcntl(1, F_GETFL) == -1) + return 1; /* match coreutils 6.10 (sans error msg to stderr) */ + //if (dup2(1, 1) != 1) - old way + // return 1; /* bash builtin errors out on "printf '-%s-\n' foo", * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo". diff --git a/shell/ash.c b/shell/ash.c index bd2433c88..11174683e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4889,7 +4889,7 @@ static int need_to_remember(struct redirtab *rp, int fd) { int i; - if (!rp) /* remebering was not requested */ + if (!rp) /* remembering was not requested */ return 0; for (i = 0; i < rp->pair_count; i++) { @@ -4901,6 +4901,28 @@ static int need_to_remember(struct redirtab *rp, int fd) return 1; } +/* "hidden" fd is a fd used to read scripts, or a copy of such */ +static int is_hidden_fd(struct redirtab *rp, int fd) +{ + int i; + struct parsefile *pf = g_parsefile; + while (pf) { + if (fd == pf->fd) { + return 1; + } + pf = pf->prev; + } + if (!rp) + return 0; + fd |= COPYFD_RESTORE; + for (i = 0; i < rp->pair_count; i++) { + if (rp->two_fd[i].copy == fd) { + return 1; + } + } + return 0; +} + /* * Process a list of redirection commands. If the REDIR_PUSH flag is set, * old file descriptors are stashed away so that the redirection can be @@ -4950,8 +4972,15 @@ redirect(union node *redir, int flags) do { fd = redir->nfile.fd; if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { - if (redir->ndup.dupfd == fd) - continue; /* redirect from/to same file descriptor */ + int right_fd = redir->ndup.dupfd; + /* redirect from/to same file descriptor? */ + if (right_fd == fd) + continue; + /* echo >&10 and 10 is a fd opened to the sh script? */ + if (is_hidden_fd(sv, right_fd)) { + errno = EBADF; /* as if it is closed */ + ash_msg_and_raise_error("%d: %m", right_fd); + } newfd = -1; } else { newfd = openredirect(redir); /* always >= 0 */ @@ -4988,14 +5017,8 @@ redirect(union node *redir, int flags) /* "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 (is_hidden_fd(sv, fd)) + i |= COPYFD_RESTORE; } if (fd == 2) copied_fd2 = i; @@ -9026,7 +9049,7 @@ static int preadfd(void) { int nr; - char *buf = g_parsefile->buf; + char *buf = g_parsefile->buf; parsenextc = buf; #if ENABLE_FEATURE_EDITING -- cgit v1.2.3