> textutils only has a DoS in tac, trivial to fix (will do unless
> someone posts a patch earlier).

The attached patch against textutils-2.0.11 avoids the DoS attacks on
tac and sort.

I am using mkstemp(3), which is not available on all of the supported
platforms.  A configure check and a portable mkstemp substitute (such
as one found in libiberty included with binutils and gcc) should be
added when fixing this in the official textutils.  This patch, in its
current form, is for use in security updates the Linux distribution
vendors are planning.

-- 
/sd
--- textutils-2.0.11/src/tac.c.orig     Sat May 13 13:47:57 2000
+++ textutils-2.0.11/src/tac.c  Thu Jan  4 14:34:23 2001
@@ -38,6 +38,7 @@
 #include <config.h>
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <getopt.h>
 #include <sys/types.h>
 #include "system.h"
@@ -72,8 +73,6 @@
 /* The number of bytes per atomic write. */
 #define WRITESIZE 8192
 
-char *mktemp ();
-
 /* The name this program was run with. */
 char *program_name;
 
@@ -424,14 +423,10 @@
       tempdir = getenv ("TMPDIR");
       if (tempdir == NULL)
        tempdir = DEFAULT_TMPDIR;
-      template = xmalloc (strlen (tempdir) + 11);
+      template = xmalloc (strlen (tempdir) + 12);
     }
-  sprintf (template, "%s/tacXXXXXX", tempdir);
-  tempfile = mktemp (template);
-
-  /*  Open temporary file exclusively, to foil a common
-      denial-of-service attack.  */
-  fd = open (tempfile, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
+  sprintf (template, "%s/tac.XXXXXX", tempdir);
+  fd = mkstemp (tempfile = template);
   if (fd == -1)
     error (EXIT_FAILURE, errno, "%s", tempfile);
 
--- textutils-2.0.11/src/sort.c.orig    Tue Dec 19 12:21:35 2000
+++ textutils-2.0.11/src/sort.c Sat Jan  6 17:30:26 2001
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <assert.h>
 #include "system.h"
 #include "closeout.h"
@@ -355,14 +356,10 @@
 }
 
 static FILE *
-xtmpfopen (const char *file)
+xfdopen (const char *file, int fd)
 {
   FILE *fp;
-  int fd;
 
-  /*  Open temporary file exclusively, to foil a common
-      denial-of-service attack.  */
-  fd = open (file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
   if (fd < 0 || (fp = fdopen (fd, "w")) == NULL)
     {
       error (0, errno, "%s", file);
@@ -452,8 +449,8 @@
 
 /* Return a name for a temporary file. */
 
-static char *
-tempname (void)
+static FILE *
+tempfile (char **name)
 {
   static unsigned long sequence_number;
 
@@ -462,27 +459,41 @@
   char const *temp_dir = temp_dirs[seq % temp_dir_count];
   size_t len = strlen (temp_dir);
   char const *slash = "/" + (len == 0 || temp_dir[len - 1] == '/');
-  char *name = xmalloc (len + 1 + sizeof "sort" - 1
-                       + sizeof pid * CHAR_BIT / 3 + 1
-                       + sizeof seq * CHAR_BIT / 3 + 1);
   int long_file_names = NAME_MAX_IN_DIR (temp_dir) > 12;
   struct tempnode *node;
+  int fd;
+  FILE *fp;
 
   if (long_file_names)
-    sprintf (name, "%s%ssort%lu.%.5lu", temp_dir, slash, pid, seq);
+    {
+      *name = xmalloc (len + 1
+       + sizeof pid * CHAR_BIT / 3 + 1
+       + sizeof seq * CHAR_BIT / 3 + 1
+       + sizeof "sort...XXXXXX");
+      sprintf (*name, "%s%ssort.%lu.%.5lu.XXXXXX", temp_dir, slash, pid, seq);
+      fd = mkstemp(*name);
+    }
   else
     {
+      *name = xmalloc (len + 1 + 8 + 1 + 3 + 1);
       /* Make sure the file name is safe for an 8.3 filesystem.  */
-      sprintf (name, "%s%ss%.5d%.2d.%.3d", temp_dir, slash,
+      sprintf (*name, "%s%ss%.5d%.2d.%.3d", temp_dir, slash,
               (int) (pid % 100000), (int) (seq / 1000 % 100),
               (int) (seq % 1000));
+      /*  Open temporary file exclusively, to foil a number of attacks.
+         Note that this still allows for a denial-of-service attack on
+         sort itself.  */
+      fd = open (*name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
     }
 
+  /* This will check for the case of fd == -1 and exit on any error */
+  fp = xfdopen (*name, fd);
+
   node = (struct tempnode *) xmalloc (sizeof (struct tempnode));
-  node->name = name;
+  node->name = *name;
   node->next = temphead.next;
   temphead.next = node;
-  return name;
+  return fp;
 }
 
 /* Search through the list of temporary files for NAME;
@@ -1763,7 +1774,7 @@
        {
          for (j = 0; j < NMERGE; ++j)
            fps[j] = xfopen (files[i * NMERGE + j], "r");
-         tfp = xtmpfopen (temp = tempname ());
+         tfp = tempfile (&temp);
          mergefps (fps, NMERGE, tfp, temp);
          xfclose (tfp);
          for (j = 0; j < NMERGE; ++j)
@@ -1772,7 +1783,7 @@
        }
       for (j = 0; j < nfiles % NMERGE; ++j)
        fps[j] = xfopen (files[i * NMERGE + j], "r");
-      tfp = xtmpfopen (temp = tempname ());
+      tfp = tempfile (&temp);
       mergefps (fps, nfiles % NMERGE, tfp, temp);
       xfclose (tfp);
       for (j = 0; j < nfiles % NMERGE; ++j)
@@ -1846,7 +1857,7 @@
          else
            {
              ++n_temp_files;
-             tfp = xtmpfopen (temp_output = tempname ());
+             tfp = tempfile ((char **)&temp_output);
            }
          for (i = 0; i < lines.used; ++i)
            if (!unique || i == 0
@@ -2417,8 +2428,7 @@
                }
 
              in_fp = xfopen (files[i], "r");
-             tmp = tempname ();
-             out_fp = xtmpfopen (tmp);
+             out_fp = tempfile (&tmp);
              /* FIXME: maybe use copy.c(copy) here. */
              while ((cc = fread (buf, 1, sizeof buf, in_fp)) > 0)
                write_bytes (buf, cc, out_fp, tmp);

Reply via email to