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:
parent
035486c750
commit
32fdf2f9fc
39
shell/ash.c
39
shell/ash.c
@ -5503,6 +5503,31 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
|
|||||||
return 0; /* "we did not close fd" */
|
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,
|
* 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
|
* old file descriptors are stashed away so that the redirection can be
|
||||||
@ -5567,15 +5592,11 @@ redirect(union node *redir, int flags)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
///TODO: if _newfd_ is a script fd or saved fd, then simulate EBADF!
|
/* if newfd is a script fd or saved fd, simulate EBADF */
|
||||||
//if (newfd == ttyfd) {
|
if (internally_opened_fd(newfd, sv)) {
|
||||||
// errno = EBADF;
|
errno = EBADF;
|
||||||
// ash_msg_and_raise_perror("A %d", newfd);
|
ash_msg_and_raise_perror("%d", newfd);
|
||||||
//}
|
}
|
||||||
//if (newfd == g_parsefile->pf_fd) {
|
|
||||||
// errno = EBADF;
|
|
||||||
// ash_msg_and_raise_perror("B %d", newfd);
|
|
||||||
//}
|
|
||||||
dup2_or_raise(newfd, fd);
|
dup2_or_raise(newfd, fd);
|
||||||
if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
|
if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
|
||||||
close(close_fd);
|
close(close_fd);
|
||||||
|
52
shell/hush.c
52
shell/hush.c
@ -1546,6 +1546,16 @@ static void close_all_FILE_list(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
static int fd_in_FILEs(int fd)
|
||||||
|
{
|
||||||
|
struct FILE_list *fl = G.FILE_list;
|
||||||
|
while (fl) {
|
||||||
|
if (fl->fd == fd)
|
||||||
|
return 1;
|
||||||
|
fl = fl->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helpers for setting new $n and restoring them back
|
/* 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
|
|||||||
static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
|
static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
|
||||||
{
|
{
|
||||||
int moved_to;
|
int moved_to;
|
||||||
int i = 0;
|
int i;
|
||||||
|
|
||||||
if (sq) while (sq[i].orig_fd >= 0) {
|
if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
|
||||||
/* If we collide with an already moved fd... */
|
/* If we collide with an already moved fd... */
|
||||||
if (fd == sq[i].moved_to) {
|
if (fd == sq[i].moved_to) {
|
||||||
sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd);
|
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)
|
|||||||
debug_printf_redir("redirect_fd %d: already moved\n", fd);
|
debug_printf_redir("redirect_fd %d: already moved\n", fd);
|
||||||
return sq;
|
return sq;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
|
/* 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)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = 0;
|
if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
|
||||||
if (sq) while (sq[i].orig_fd >= 0) {
|
|
||||||
/* If we collide with an already moved fd... */
|
/* If we collide with an already moved fd... */
|
||||||
if (fd == sq[i].orig_fd) {
|
if (fd == sq[i].orig_fd) {
|
||||||
/* Examples:
|
/* Examples:
|
||||||
@ -6730,7 +6738,6 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
|
|||||||
debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
|
debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
|
||||||
return sq;
|
return sq;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd);
|
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)
|
|||||||
avoid_fd = 9;
|
avoid_fd = 9;
|
||||||
|
|
||||||
#if ENABLE_HUSH_INTERACTIVE
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
if (fd != 0 && fd == G.interactive_fd) {
|
if (fd == G.interactive_fd) {
|
||||||
|
/* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
|
||||||
G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd);
|
G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd);
|
||||||
debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd);
|
debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd);
|
||||||
return 1; /* "we closed fd" */
|
return 1; /* "we closed fd" */
|
||||||
@ -6775,8 +6783,8 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
|
|||||||
static void restore_redirects(struct squirrel *sq)
|
static void restore_redirects(struct squirrel *sq)
|
||||||
{
|
{
|
||||||
if (sq) {
|
if (sq) {
|
||||||
int i = 0;
|
int i;
|
||||||
while (sq[i].orig_fd >= 0) {
|
for (i = 0; sq[i].orig_fd >= 0; i++) {
|
||||||
if (sq[i].moved_to >= 0) {
|
if (sq[i].moved_to >= 0) {
|
||||||
/* We simply die on error */
|
/* We simply die on error */
|
||||||
debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd);
|
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)
|
|||||||
debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
|
debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
|
||||||
close(sq[i].orig_fd);
|
close(sq[i].orig_fd);
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
free(sq);
|
free(sq);
|
||||||
}
|
}
|
||||||
@ -6796,6 +6803,25 @@ static void restore_redirects(struct squirrel *sq)
|
|||||||
restore_redirected_FILEs();
|
restore_redirected_FILEs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int internally_opened_fd(int fd, struct squirrel *sq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
|
if (fd == G.interactive_fd)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
/* If this one of script's fds? */
|
||||||
|
if (fd_in_FILEs(fd))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
|
||||||
|
if (fd == sq[i].moved_to)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* squirrel != NULL means we squirrel away copies of stdin, stdout,
|
/* squirrel != NULL means we squirrel away copies of stdin, stdout,
|
||||||
* and stderr if they are redirected. */
|
* and stderr if they are redirected. */
|
||||||
static int setup_redirects(struct command *prog, struct squirrel **sqp)
|
static int setup_redirects(struct command *prog, struct squirrel **sqp)
|
||||||
@ -6878,6 +6904,12 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
|
|||||||
* and second redirect closes 3! Restore code then closes 3 again.
|
* and second redirect closes 3! Restore code then closes 3 again.
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
|
/* if newfd is a script fd or saved fd, simulate EBADF */
|
||||||
|
if (internally_opened_fd(newfd, sqp ? *sqp : NULL)) {
|
||||||
|
//errno = EBADF;
|
||||||
|
//bb_perror_msg_and_die("can't duplicate file descriptor");
|
||||||
|
newfd = -1; /* same effect as code above */
|
||||||
|
}
|
||||||
xdup2(newfd, redir->rd_fd);
|
xdup2(newfd, redir->rd_fd);
|
||||||
if (redir->rd_dup == REDIRFD_TO_FILE)
|
if (redir->rd_dup == REDIRFD_TO_FILE)
|
||||||
/* "rd_fd > FILE" */
|
/* "rd_fd > FILE" */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user