Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Nov 2009 22:33:59 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r199953 - in head: bin/sh tools/regression/bin/sh/execution
Message-ID:  <200911292233.nATMXxIn011543@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Sun Nov 29 22:33:59 2009
New Revision: 199953
URL: http://svn.freebsd.org/changeset/base/199953

Log:
  Fix some cases where file descriptors from redirections leak to programs.
  
  - Redirecting fds that were not open before kept two copies of the
    redirected file.
      sh -c '{ :; } 7>/dev/null; fstat -p $$; true'
      (both fd 7 and 10 remained open)
  - File descriptors used to restore things after redirection were not
    set close-on-exec, instead they were explicitly closed before executing
    a program normally and before executing a shell procedure. The latter
    must remain but the former is replaced by close-on-exec.
      sh -c 'exec 7</; { exec fstat -p $$; } 7>/dev/null; true'
      (fd 10 remained open)
  
  The examples above are simpler than the testsuite because I do not want to
  use fstat or procstat in the testsuite.

Added:
  head/tools/regression/bin/sh/execution/redir1.0   (contents, props changed)
  head/tools/regression/bin/sh/execution/redir2.0   (contents, props changed)
Modified:
  head/bin/sh/eval.c
  head/bin/sh/redir.c

Modified: head/bin/sh/eval.c
==============================================================================
--- head/bin/sh/eval.c	Sun Nov 29 21:34:52 2009	(r199952)
+++ head/bin/sh/eval.c	Sun Nov 29 22:33:59 2009	(r199953)
@@ -883,7 +883,6 @@ cmddone:
 #ifdef DEBUG
 		trputs("normal command:  ");  trargs(argv);
 #endif
-		clearredir();
 		redirect(cmd->ncmd.redirect, 0);
 		for (sp = varlist.list ; sp ; sp = sp->next)
 			setvareq(sp->text, VEXPORT|VSTACK);

Modified: head/bin/sh/redir.c
==============================================================================
--- head/bin/sh/redir.c	Sun Nov 29 21:34:52 2009	(r199952)
+++ head/bin/sh/redir.c	Sun Nov 29 22:33:59 2009	(r199953)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 
 
 #define EMPTY -2		/* marks an unused slot in redirtab */
+#define CLOSED -1		/* fd was not open before redir */
 #define PIPESIZE 4096		/* amount of buffering in a pipe */
 
 
@@ -101,7 +102,6 @@ redirect(union node *redir, int flags)
 	struct redirtab *sv = NULL;
 	int i;
 	int fd;
-	int try;
 	char memory[10];	/* file descriptors to write to memory */
 
 	for (i = 10 ; --i >= 0 ; )
@@ -116,38 +116,30 @@ redirect(union node *redir, int flags)
 	}
 	for (n = redir ; n ; n = n->nfile.next) {
 		fd = n->nfile.fd;
-		try = 0;
 		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
 		    n->ndup.dupfd == fd)
 			continue; /* redirect from/to same file descriptor */
 
 		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
 			INTOFF;
-again:
 			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
 				switch (errno) {
 				case EBADF:
-					if (!try) {
-						openredirect(n, memory);
-						try++;
-						goto again;
-					}
-					/* FALLTHROUGH*/
+					i = CLOSED;
+					break;
 				default:
 					INTON;
 					error("%d: %s", fd, strerror(errno));
 					break;
 				}
-			}
-			if (!try) {
-				sv->renamed[fd] = i;
-			}
+			} else
+				(void)fcntl(i, F_SETFD, FD_CLOEXEC);
+			sv->renamed[fd] = i;
 			INTON;
 		}
 		if (fd == 0)
 			fd0_redirected++;
-		if (!try)
-			openredirect(n, memory);
+		openredirect(n, memory);
 	}
 	if (memory[1])
 		out1 = &memout;

Added: head/tools/regression/bin/sh/execution/redir1.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/execution/redir1.0	Sun Nov 29 22:33:59 2009	(r199953)
@@ -0,0 +1,27 @@
+# $FreeBSD$
+trap ': $((brokenpipe+=1))' pipe
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+read dummy >fifo2 <fifo1 &
+{
+	exec 4>fifo2
+} 3<fifo2 # Formerly, sh would keep fd 3 and a duplicate of it open.
+echo dummy >fifo1
+if [ $brokenpipe -ne 0 ]; then
+	rc=3
+fi
+wait
+echo dummy >&4
+if [ $brokenpipe -eq 1 ]; then
+	: ${rc:=0}
+fi
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}

Added: head/tools/regression/bin/sh/execution/redir2.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/execution/redir2.0	Sun Nov 29 22:33:59 2009	(r199953)
@@ -0,0 +1,29 @@
+# $FreeBSD$
+trap ': $((brokenpipe+=1))' pipe
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+{
+	{
+		exec sh -c 'exec <fifo1; read dummy'
+	} 7<&- # fifo2 should be kept open, but not passed to programs
+	true
+} 7<fifo2 &
+
+exec 4>fifo2
+exec 3>fifo1
+echo dummy >&4
+if [ $brokenpipe -eq 1 ]; then
+	: ${rc:=0}
+fi
+echo dummy >&3
+wait
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911292233.nATMXxIn011543>