Hi,

The people at Immunix recently scanned all of RedHat 7.0 for
temp file problems and found some in CVS (among many others).

I'm currently testing a patch for this problem; the current
patch is attached.

What the patch does is

 -      define CVS_SAFE_FOPEN and safe_fopen to create
        temp files safely (i.e. using O_EXCL). This is still
        subject to denial of service, but at least it's safe :)
 -      Checked all calls to cvs_temp_name(), and made sure
        that the resulting file is opened using safe_fopen()
        In most cases this was straightforward, but on several
        occasions RCS_checkout is called, and I went through
        RCS_checkout to make sure the file is created safely
        (this part of the patch may need special attention
        to make sure it's okay)

Cheers
Olaf
-- 
Olaf Kirch         |  --- o --- Nous sommes du soleil we love when we play
[EMAIL PROTECTED]  |    / | \   sol.dhoop.naytheet.ah kin.ir.samse.qurax
[EMAIL PROTECTED]    +-------------------- Why Not?! -----------------------
         UNIX, n.: Spanish manufacturer of fire extinguishers.            
diff -ur --new-file cvs-1.11.orig/lib/Makefile.in cvs-1.11/lib/Makefile.in
--- cvs-1.11.orig/lib/Makefile.in	Thu Dec 30 03:44:54 1999
+++ cvs-1.11/lib/Makefile.in	Fri Jan  5 11:06:21 2001
@@ -39,6 +39,7 @@
 	mkdir.c \
 	regex.c \
 	rename.c \
+	safe_fopen.c \
 	savecwd.c \
 	sighandle.c \
 	strstr.c \
@@ -50,7 +51,8 @@
 	xgetwd.c \
 	yesno.c
 
-HEADERS = getline.h getopt.h fnmatch.h regex.h system.h wait.h md5.h savecwd.h
+HEADERS = getline.h getopt.h fnmatch.h regex.h system.h wait.h md5.h savecwd.h \
+        safe_fopen.h
 
 # Always use CVS's regular expression matcher regex.o, because of
 # variations in regular expression syntax - we want to be the same
@@ -70,6 +72,7 @@
     getopt1.o \
     md5.o \
     regex.o \
+    safe_fopen.o \
     savecwd.o \
     sighandle.o \
     stripslash.o \
diff -ur --new-file cvs-1.11.orig/lib/safe_fopen.c cvs-1.11/lib/safe_fopen.c
--- cvs-1.11.orig/lib/safe_fopen.c	Thu Jan  1 01:00:00 1970
+++ cvs-1.11/lib/safe_fopen.c	Fri Jan  5 11:06:36 2001
@@ -0,0 +1,24 @@
+/*
+ * Safely open a temp file
+ *
+ */
+
+#include <stdio.h>
+#include "system.h"
+
+FILE *
+safe_fopen(const char *name, const char *mode)
+{
+	int	fd;
+
+	/* Accept modes w w+ wb etc */
+	if (mode[0] != 'w' && mode[0] != 'a') {
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0)
+		return NULL;
+	
+	return fdopen(fd, mode);
+}
diff -ur --new-file cvs-1.11.orig/lib/safe_fopen.h cvs-1.11/lib/safe_fopen.h
--- cvs-1.11.orig/lib/safe_fopen.h	Thu Jan  1 01:00:00 1970
+++ cvs-1.11/lib/safe_fopen.h	Fri Jan  5 11:06:36 2001
@@ -0,0 +1,14 @@
+#ifndef SAFE_FOPEN_H
+#define SAFE_FOPEN_H
+
+#include <stdio.h>
+
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __PROTO(args) args
+#else
+#define __PROTO(args) ()
+#endif  /* GCC.  */
+
+extern FILE *	safe_fopen __PROTO((const char *, const char *));
+
+#endif /* SAFE_FOPEN_H */
Binary files cvs-1.11.orig/lib/safe_fopen.o and cvs-1.11/lib/safe_fopen.o differ
diff -ur --new-file cvs-1.11.orig/lib/system.h cvs-1.11/lib/system.h
--- cvs-1.11.orig/lib/system.h	Mon Feb 16 19:55:18 1998
+++ cvs-1.11/lib/system.h	Fri Jan  5 11:06:21 2001
@@ -429,6 +429,11 @@
 #define CVS_FOPEN fopen
 #endif
 
+#include "safe_fopen.h"
+#ifndef CVS_SAFE_FOPEN
+#define CVS_SAFE_FOPEN safe_fopen
+#endif
+
 #ifndef CVS_MKDIR
 #define CVS_MKDIR mkdir
 #endif
diff -ur --new-file cvs-1.11.orig/src/commit.c cvs-1.11/src/commit.c
--- cvs-1.11.orig/src/commit.c	Wed Jul 26 21:29:01 2000
+++ cvs-1.11/src/commit.c	Fri Jan  5 11:06:21 2001
@@ -592,7 +592,7 @@
 	    FILE *fp;
 
 	    fname = cvs_temp_name ();
-	    fp = CVS_FOPEN (fname, "w+");
+	    fp = CVS_SAFE_FOPEN (fname, "w+");
 	    if (fp == NULL)
 		error (1, 0, "cannot create temporary file %s", fname);
 	    if (fwrite (saved_message, 1, strlen (saved_message), fp)
diff -ur --new-file cvs-1.11.orig/src/import.c cvs-1.11/src/import.c
--- cvs-1.11.orig/src/import.c	Tue Jul 11 22:32:02 2000
+++ cvs-1.11/src/import.c	Fri Jan  5 11:06:21 2001
@@ -291,7 +291,7 @@
 
     /* Create the logfile that will be logged upon completion */
     tmpfile = cvs_temp_name ();
-    if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL)
+    if ((logfp = CVS_SAFE_FOPEN (tmpfile, "w+")) == NULL)
 	error (1, errno, "cannot create temporary file `%s'", tmpfile);
     /* On systems where we can unlink an open file, do so, so it will go
        away no matter how we exit.  FIXME-maybe: Should be checking for
diff -ur --new-file cvs-1.11.orig/src/login.c cvs-1.11/src/login.c
--- cvs-1.11.orig/src/login.c	Tue Aug  1 18:17:50 2000
+++ cvs-1.11/src/login.c	Fri Jan  5 11:06:21 2001
@@ -215,7 +215,7 @@
 	    FILE *tmp_fp;
 
 	    tmp_name = cvs_temp_name ();
-	    if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL)
+	    if ((tmp_fp = CVS_SAFE_FOPEN (tmp_name, "w")) == NULL)
             {
 		error (1, errno, "unable to open temp file %s", tmp_name);
 		return 1;
@@ -450,7 +450,7 @@
     /* FIXME: This should not be in /tmp; that is almost surely a security
        hole.  Probably should just keep it in memory.  */
     tmp_name = cvs_temp_name ();
-    if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL)
+    if ((tmp_fp = CVS_SAFE_FOPEN (tmp_name, "w")) == NULL)
     {
 	error (1, errno, "unable to open temp file %s", tmp_name);
 	return 1;
diff -ur --new-file cvs-1.11.orig/src/logmsg.c cvs-1.11/src/logmsg.c
--- cvs-1.11.orig/src/logmsg.c	Wed Mar  1 17:33:39 2000
+++ cvs-1.11/src/logmsg.c	Fri Jan  5 11:06:21 2001
@@ -194,7 +194,11 @@
     /* Create a temporary file */
     fname = cvs_temp_name ();
   again:
-    if ((fp = CVS_FOPEN (fname, "w+")) == NULL)
+    /* need to remove file in case we jumped here after getting
+     * an error */
+    unlink(fname);
+ 
+    if ((fp = CVS_SAFE_FOPEN (fname, "w+")) == NULL)
 	error (1, 0, "cannot create temporary file %s", fname);
 
     if (*messagep)
@@ -419,7 +423,7 @@
 
     fname = cvs_temp_name ();
 
-    fp = fopen (fname, "w");
+    fp = CVS_SAFE_FOPEN (fname, "w");
     if (fp == NULL)
 	error (1, errno, "cannot create temporary file %s", fname);
     else
diff -ur --new-file cvs-1.11.orig/src/patch.c cvs-1.11/src/patch.c
--- cvs-1.11.orig/src/patch.c	Thu Jul  6 19:30:42 2000
+++ cvs-1.11/src/patch.c	Fri Jan  5 11:06:21 2001
@@ -504,7 +504,7 @@
     /* Create 3 empty files.  I'm not really sure there is any advantage
        to doing so now rather than just waiting until later.  */
     tmpfile1 = cvs_temp_name ();
-    fp1 = CVS_FOPEN (tmpfile1, "w+");
+    fp1 = CVS_SAFE_FOPEN (tmpfile1, "w+");
     if (fp1 == NULL)
     {
 	error (0, errno, "cannot create temporary file %s", tmpfile1);
@@ -515,7 +515,7 @@
 	if (fclose (fp1) < 0)
 	    error (0, errno, "warning: cannot close %s", tmpfile1);
     tmpfile2 = cvs_temp_name ();
-    fp2 = CVS_FOPEN (tmpfile2, "w+");
+    fp2 = CVS_SAFE_FOPEN (tmpfile2, "w+");
     if (fp2 == NULL)
     {
 	error (0, errno, "cannot create temporary file %s", tmpfile2);
@@ -526,7 +526,7 @@
 	if (fclose (fp2) < 0)
 	    error (0, errno, "warning: cannot close %s", tmpfile2);
     tmpfile3 = cvs_temp_name ();
-    fp3 = CVS_FOPEN (tmpfile3, "w+");
+    fp3 = CVS_SAFE_FOPEN (tmpfile3, "w+");
     if (fp3 == NULL)
     {
 	error (0, errno, "cannot create temporary file %s", tmpfile3);
diff -ur --new-file cvs-1.11.orig/src/rcs.c cvs-1.11/src/rcs.c
--- cvs-1.11.orig/src/rcs.c	Mon Aug 21 23:16:38 2000
+++ cvs-1.11/src/rcs.c	Fri Jan  5 11:06:21 2001
@@ -4338,12 +4338,11 @@
 		ofp = stdout;
 	    else
 	    {
-		/* Symbolic links should be removed before replacement, so that
-		   `fopen' doesn't follow the link and open the wrong file. */
-		if (islink (sout))
-		    if (unlink_file (sout) < 0)
-			error (1, errno, "cannot remove %s", sout);
-		ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
+		/* Unconditionally remove the old file, so that safe_fopen
+		 * can succeed */
+		if (unlink_file (sout) < 0)
+		    error (1, errno, "cannot remove %s", sout);
+		ofp = CVS_SAFE_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
 		if (ofp == NULL)
 		    error (1, errno, "cannot open %s", sout);
 	    }
diff -ur --new-file cvs-1.11.orig/src/rcscmds.c cvs-1.11/src/rcscmds.c
--- cvs-1.11.orig/src/rcscmds.c	Sat Aug 15 22:47:46 1998
+++ cvs-1.11/src/rcscmds.c	Fri Jan  5 11:06:21 2001
@@ -223,9 +223,17 @@
     if (out == RUN_TTY)
 	return diff3_run (call_diff_argc, call_diff_argv, NULL,
 			  &call_diff_stdout_callbacks);
-    else
+    else {
+	FILE	*fp;
+
+	/* Make sure the file is created safely */
+	if (!(fp = CVS_SAFE_FOPEN(out, "w")))
+	    return 2;
+	fclose(fp);
+
 	return diff3_run (call_diff_argc, call_diff_argv, out,
 			  &call_diff_file_callbacks);
+    }
 }
 
 
diff -ur --new-file cvs-1.11.orig/src/wrapper.c cvs-1.11/src/wrapper.c
--- cvs-1.11.orig/src/wrapper.c	Wed Dec 23 16:15:01 1998
+++ cvs-1.11/src/wrapper.c	Fri Jan  5 11:06:21 2001
@@ -566,6 +566,15 @@
 	free (buf);
     buf = cvs_temp_name ();
 
+    /* Create temp file safely */
+    {
+    	FILE	*fp;
+
+	if (!(fp = CVS_SAFE_FOPEN(buf, "w")))
+	    return NULL;
+	fclose(fp);
+    }
+
     args = xmalloc (strlen (e->tocvsFilter)
 		    + strlen (fileName)
 		    + strlen (buf));

Reply via email to