ash: dont allow e.g. exec <&10 to attach to stript's fd!
No binary (build failed)
—
(log yok)
| @@ -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; | |
| @@ -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". | |
| @@ -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 | |