Subject: bin/19722: fix for 3 uncompress(1) bugs that delete/truncate the wrong file
To: None <gnats-bugs@gnats.netbsd.org>
From: Giorgos Keramidas <keramida@freebsd.org>
List: netbsd-bugs
Date: 01/07/2003 12:20:37
>Number:         19722
>Category:       bin
>Synopsis:       fix for 3 uncompress(1) bugs that delete/truncate the wrong file
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Jan 07 02:21:00 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        NetBSD 1.6
>Organization:
>Environment:
System: NetBSD spe143.testdrive.compaq.com 1.6 NetBSD 1.6 (GENERIC) #0: Sun Sep 8 19:43:40 UTC 2002 autobuild@tgm.daemon.org:/autobuild/i386/OBJ/autobuild/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:

The attached diff fixes two bugs in uncompress(1) that are present in
both FreeBSD & NetBSD.  The output file of decompress() in compress.c
should not be unlinked in the following cases:
	- if the input file (the .Z one) cannot be opened for reading.
	- if the input file exists but fread() after zopen() fails.
The attached diff also fixes a minor bug that is caused by trying to
open the output file before checking if the input file exists.  The
output file shouldn't be opened first, because it will be truncated.
By moving the fopen() that truncates the output file further down, we
make sure that the output file isn't unnecessarily truncated if the
input file doesn't exist.

>How-To-Repeat:

The following two sample sessions from a NetBSD 1.6 installation at
Compaq's testdrive installations show the bugs in action:

	spe143-> rm lala.Z
	spe143-> ls -l lala*
	ls: No match.
	spe143-> touch lala
	spe143-> ls -l lala*
	-rw-r--r--  1 gk736  nis  0 Jan  6 23:22 lala
	spe143-> ln -s compress uncompress
	spe143-> ./uncompress -f lala
	uncompress: lala.Z: No such file or directory
	spe143-> ls -l lala*
	ls: No match.
	spe143->

	spe143-> cp /etc/rc.conf lala.Z
	spe143-> touch lala
	spe143-> ls -l lala*
	-rw-r--r--  1 gk736  nis    0 Jan  6 23:24 lala
	-rw-r--r--  1 gk736  nis  815 Jan  6 23:24 lala.Z
	spe143-> ./uncompress -f lala
	uncompress: lala.Z: Inappropriate file type or format
	spe143-> ls -l lala*
	-rw-r--r--  1 gk736  nis  815 Jan  6 23:24 lala.Z
	spe143->

>Fix:

%%%
Index: compress.c
===================================================================
RCS file: /cvsroot/src/usr.bin/compress/compress.c,v
retrieving revision 1.19
diff -u -r1.19 compress.c
--- compress.c	2002/05/26 22:21:22	1.19
+++ compress.c	2003/01/07 04:32:57
@@ -317,19 +317,15 @@
 		oreg = 0;
 
 	ifp = ofp = NULL;
-	if ((ofp = fopen(out, "w")) == NULL) {
-		cwarn("%s", out);
-		return;
-	}
-
 	if ((ifp = zopen(in, "r", bits)) == NULL) {
 		cwarn("%s", in);
-		goto err;
+		return;
 	}
 	if (!isstdin) {
 		if (stat(in, &sb)) {
 			cwarn("%s", in);
-			goto err;
+			(void)fclose(ifp);
+			return;
 		}
 		if (!S_ISREG(sb.st_mode))
 			isreg = 0;
@@ -337,6 +333,21 @@
 			isreg = 1;
 	} else
 		isreg = 0;
+
+	if ((nr = fread(buf, 1, sizeof(buf), ifp)) == 0) {
+		cwarn("%s", in);
+		(void)fclose(ifp);
+		return;
+	}
+	if ((ofp = fopen(out, "w")) == NULL) {
+		cwarn("%s", out);
+		(void)fclose(ifp);
+		return;
+	}
+	if (fwrite(buf, 1, nr, ofp) != nr) {
+		cwarn("%s", out);
+		goto err;
+	}
 
 	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
 		if (fwrite(buf, 1, nr, ofp) != nr) {
%%%
>Release-Note:
>Audit-Trail:
>Unformatted: