[git commit] tar: handle the case when opened created tarball happens to have fd#0

Denys Vlasenko vda.linux at googlemail.com
Sat Aug 4 16:15:19 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=037759bb4f57b0cb9b0daf6ffed43f90b62b8cb4
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Reproducer:
    exec 0>&-
    exec 1>&-
    tar czf z.tar.gz FILE

function                                             old     new   delta
vfork_compressor                                     229     257     +28

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 archival/tar.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/archival/tar.c b/archival/tar.c
index 9239d8ee4..120c77f3b 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -611,6 +611,7 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
 
 	if (xvfork() == 0) {
 		/* child */
+		int tfd;
 		/* NB: close _first_, then move fds! */
 		close(data.wr);
 #  if WAIT_FOR_CHILD
@@ -619,8 +620,23 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
 		 * parent waits for this close to happen */
 		fcntl(status.wr, F_SETFD, FD_CLOEXEC);
 #  endif
+		/* copy it: parent's tar_fd variable must not change */
+		tfd = tar_fd;
+		if (tfd == 0) {
+			/* Output tar fd may be zero.
+			 * xmove_fd(data.rd, 0) would destroy it.
+			 * Reproducer:
+			 *  exec 0>&-
+			 *  exec 1>&-
+			 *  tar czf Z.tar.gz FILE
+			 * Swapping move_fd's order wouldn't work:
+			 * data.rd is 1 and _it_ would be destroyed.
+			 */
+			xmove_fd(tfd, 3);
+			tfd = 3;
+		}
 		xmove_fd(data.rd, 0);
-		xmove_fd(tar_fd, 1);
+		xmove_fd(tfd, 1);
 		/* exec gzip/bzip2 program/applet */
 		BB_EXECLP(gzip, gzip, "-f", (char *)0);
 		vfork_exec_errno = errno;
@@ -715,11 +731,7 @@ static NOINLINE int writeTarFile(
 	return errorFlag;
 }
 
-#else /* !FEATURE_TAR_CREATE */
-
-# define writeTarFile(...) 0
-
-#endif
+#endif /* FEATURE_TAR_CREATE */
 
 #if ENABLE_FEATURE_TAR_FROM
 static llist_t *append_file_list_to_list(llist_t *list)


More information about the busybox-cvs mailing list