Upstream-Status: Backport

The patch to fix CVE-2009-1214
A security flaw was found in the screen utility in the way it used to create
one particular temporary file. An attacker could use this flaw to perform
a symlink attack. 
Fix race condition creating temporary file

Reference:
https://bugzilla.redhat.com/show_bug.cgi?id=492104

Signed-off-by: Chenyang Guo <chenyang.guo@windriver.com>
---
 fileio.c |   48 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 16 deletions(-)

--- a/fileio.c
+++ b/fileio.c
@@ -414,6 +414,14 @@ int dump;
 	}
       public = !strcmp(fn, DEFAULT_BUFFERFILE);
 # ifdef HAVE_LSTAT
+      /*
+       * Note: In the time between lstat() and open()/remove() below are
+       * called, the file can be created/removed/modified.  Therefore the
+       * information lstat() returns is taken into consideration, but not
+       * relied upon.  In particular, the open()/remove() calls can fail, and
+       * the code must account for that.  Symlink attack could be mounted if
+       * the code is changed carelessly.  --rdancer 2009-01-11
+       */
       exists = !lstat(fn, &stb);
       if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1))
 	{
@@ -432,28 +440,36 @@ int dump;
 #ifdef COPY_PASTE
       if (dump == DUMP_EXCHANGE && public)
 	{
+	  /*
+	   * Setting umask to zero is a bad idea -- the user surely doesn't
+	   * expect a publicly readable file in a publicly readable directory 
+	   * --rdancer 2009-01-11
+	   */
+	  /*
           old_umask = umask(0);
+	   */
 # ifdef HAVE_LSTAT
 	  if (exists)
-	    {
-	      if ((fd = open(fn, O_WRONLY, 0666)) >= 0)
-		{
-		  if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino == stb2.st_ino)
-		    ftruncate(fd, 0);
-		  else
-		    {
-		      close(fd);
-		      fd = -1;
-		    }
-		}
-	    }
-	  else
-	    fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666);
-	  f = fd >= 0 ? fdopen(fd, mode) : 0;
+	      if (remove(fn) == -1)
+	        {
+		  /* Error */
+		  debug2("WriteFile: File exists and remove(%s) failed: %s\n",
+			  fn, strerror(errno));
+		  UserReturn(0);
+	        }
 # else
-          f = fopen(fn, mode);
+	  (void) remove(fn);
 # endif
+	  /*
+	   * No r/w permissions for anybody but the user, as the file may be in
+	   * a public directory -- if the user chooses, they can chmod the file
+	   * afterwards. --rdancer 2008-01-11
+	   */
+	  fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0600);
+	  f = fd >= 0 ? fdopen(fd, mode) : 0;
+	  /*
           umask(old_umask);
+	   */
 	}
       else
 #endif /* COPY_PASTE */
