From 037759bb4f57b0cb9b0daf6ffed43f90b62b8cb4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 4 Aug 2018 18:15:19 +0200 Subject: tar: handle the case when opened created tarball happens to have fd#0 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 --- archival/tar.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git archival/tar.c archival/tar.c index 9239d8e..120c77f 100644 --- archival/tar.c +++ archival/tar.c @@ -631,6 +631,7 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) if (gzipPid == 0) { /* child */ + int tfd; /* NB: close _first_, then move fds! */ close(gzipDataPipe.wr); # if WAIT_FOR_CHILD @@ -639,8 +640,23 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) * parent waits for this close to happen */ fcntl(gzipStatusPipe.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(gzipDataPipe.rd, 0) would destroy it. + * Reproducer: + * exec 0>&- + * exec 1>&- + * tar czf Z.tar.gz FILE + * Swapping move_fd's order wouldn't work: + * gzipDataPipe.rd is 1 and _it_ would be destroyed. + */ + xmove_fd(tfd, 3); + tfd = 3; + } xmove_fd(gzipDataPipe.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;