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>
This commit is contained in:
Denys Vlasenko
2017-07-31 04:32:06 +02:00
parent 035486c750
commit 32fdf2f9fc
2 changed files with 72 additions and 19 deletions

View File

@@ -5503,6 +5503,31 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
return 0; /* "we did not close fd" */
}
static int
internally_opened_fd(int fd, struct redirtab *sq)
{
int i;
#if JOBS
if (fd == ttyfd)
return 1;
#endif
/* If this one of script's fds? */
if (fd != 0) {
struct parsefile *pf = g_parsefile;
while (pf) {
if (fd == pf->pf_fd)
return 1;
pf = pf->prev;
}
}
if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
if (fd == sq->two_fd[i].moved_to)
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
@@ -5567,15 +5592,11 @@ redirect(union node *redir, int flags)
close(fd);
}
} else {
///TODO: if _newfd_ is a script fd or saved fd, then simulate EBADF!
//if (newfd == ttyfd) {
// errno = EBADF;
// ash_msg_and_raise_perror("A %d", newfd);
//}
//if (newfd == g_parsefile->pf_fd) {
// errno = EBADF;
// ash_msg_and_raise_perror("B %d", newfd);
//}
/* if newfd is a script fd or saved fd, simulate EBADF */
if (internally_opened_fd(newfd, sv)) {
errno = EBADF;
ash_msg_and_raise_perror("%d", newfd);
}
dup2_or_raise(newfd, fd);
if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
close(close_fd);