[git commit] ash: [REDIR] Fix popredir on abnormal exit from built-in

Denys Vlasenko vda.linux at googlemail.com
Sat Jul 29 20:51:52 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=1c79aeb6a8cae4cd4013926b97f39305b689d74c
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Upstream commit:

    Date: Thu, 27 May 2010 15:03:46 +0800
    [REDIR] Fix popredir on abnormal exit from built-in

    Just like the poplocalvar problem recently fixed, redirections
    can also be leaked in case of an abnormal exit.  This patch fixes
    it using the same method as poplocalvar, by storing the previous
    redirection state and restoring to that point.

    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c | 70 ++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 3184249..e2b4eee 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5435,33 +5435,13 @@ redirect(union node *redir, int flags)
 	int newfd;
 	int copied_fd2 = -1;
 
-	if (!redir) {
+	if (!redir)
 		return;
-	}
-
 	sv = NULL;
-	sv_pos = 0;
 	INT_OFF;
-	if (flags & REDIR_PUSH) {
-		union node *tmp = redir;
-		do {
-			sv_pos++;
-#if BASH_REDIR_OUTPUT
-			if (tmp->nfile.type == NTO2)
-				sv_pos++;
-#endif
-			tmp = tmp->nfile.next;
-		} while (tmp);
-		sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
-		sv->next = redirlist;
-		sv->pair_count = sv_pos;
-		redirlist = sv;
-		while (sv_pos > 0) {
-			sv_pos--;
-			sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
-		}
-	}
-
+	if (flags & REDIR_PUSH)
+		sv = redirlist;
+	sv_pos = 0;
 	do {
 		int right_fd = -1;
 		fd = redir->nfile.fd;
@@ -5583,6 +5563,34 @@ redirectsafe(union node *redir, int flags)
 	return err;
 }
 
+static struct redirtab*
+pushredir(union node *redir)
+{
+	struct redirtab *sv;
+	int i;
+
+	if (!redir)
+		return redirlist;
+
+	i = 0;
+	do {
+		i++;
+#if BASH_REDIR_OUTPUT
+		if (redir->nfile.type == NTO2)
+			i++;
+#endif
+		redir = redir->nfile.next;
+	} while (redir);
+
+	sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
+	sv->pair_count = i;
+	while (--i >= 0)
+		sv->two_fd[i].orig = sv->two_fd[i].copy = EMPTY;
+	sv->next = redirlist;
+	redirlist = sv;
+	return sv->next;
+}
+
 /*
  * Undo the effects of the last redirection.
  */
@@ -5618,6 +5626,13 @@ popredir(int drop, int restore)
 	INT_ON;
 }
 
+static void
+unwindredir(struct redirtab *stop)
+{
+	while (redirlist != stop)
+		popredir(/*drop:*/ 0, /*restore:*/ 0);
+}
+
 
 /* ============ Routines to expand arguments to commands
  *
@@ -8727,6 +8742,7 @@ evaltree(union node *n, int flags)
 		goto setstatus;
 	case NREDIR:
 		expredir(n->nredir.redirect);
+		pushredir(n->nredir.redirect);
 		status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
 		if (!status) {
 			status = evaltree(n->nredir.n, flags & EV_TESTED);
@@ -9622,6 +9638,7 @@ evalcommand(union node *cmd, int flags)
 		"\0\0", bltincmd /* why three NULs? */
 	};
 	struct localvar_list *localvar_stop;
+	struct redirtab *redir_stop;
 	struct stackmark smark;
 	union node *argp;
 	struct arglist arglist;
@@ -9687,6 +9704,7 @@ evalcommand(union node *cmd, int flags)
 
 	preverrout_fd = 2;
 	expredir(cmd->ncmd.redirect);
+	redir_stop = pushredir(cmd->ncmd.redirect);
 	status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
 
 	path = vpath.var_text;
@@ -9878,6 +9896,7 @@ evalcommand(union node *cmd, int flags)
  out:
 	if (cmd->ncmd.redirect)
 		popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
+	unwindredir(redir_stop);
 	unwindlocalvars(localvar_stop);
 	if (lastarg) {
 		/* dsl: I think this is intended to be used to support
@@ -13584,8 +13603,7 @@ reset(void)
 	popallfiles();
 
 	/* from redir.c: */
-	while (redirlist)
-		popredir(/*drop:*/ 0, /*restore:*/ 0);
+	unwindredir(NULL);
 
 	/* from var.c: */
 	unwindlocalvars(NULL);


More information about the busybox-cvs mailing list