bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ls.c patch to avoid generating way-too-long time stamps


From: Paul Eggert
Subject: ls.c patch to avoid generating way-too-long time stamps
Date: Fri, 11 Mar 2005 15:15:58 -0800
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.4 (gnu/linux)

I installed this:

2005-03-11  Paul Eggert  <address@hidden>

        * src/ls.c (TIME_STAMP_LEN_MAXIMUM): New constant.
        (long_time_expected_width, print_long_format): Use it, to avoid
        some possible denial-of-service attacks.
        * NEWS: Document this.
        * doc/coreutils.texi (Formatting file timestamps): Likewise.

Index: NEWS
===================================================================
RCS file: /fetish/cu/NEWS,v
retrieving revision 1.271
diff -p -u -r1.271 NEWS
--- NEWS        28 Feb 2005 10:18:32 -0000      1.271
+++ NEWS        11 Mar 2005 23:12:10 -0000
@@ -27,6 +27,9 @@ GNU coreutils NEWS                      
   expr now detects integer overflow when evaluating large integers,
   rather than silently wrapping around.
 
+  ls now refuses to generate time stamps containing more than 1000 bytes, to
+  foil remote denial-of-service attacks (e.g., --time-style='+%1000000000Y').
+
   test now detects integer overflow when evaluating large integers,
   rather than silently wrapping around.
 
Index: doc/coreutils.texi
===================================================================
RCS file: /fetish/cu/doc/coreutils.texi,v
retrieving revision 1.243
diff -p -u -r1.243 coreutils.texi
--- doc/coreutils.texi  8 Mar 2005 22:19:39 -0000       1.243
+++ doc/coreutils.texi  11 Mar 2005 23:12:12 -0000
@@ -6073,6 +6073,9 @@ later can parse @acronym{ISO} dates, but
 you are using an older version of Emacs and specify a address@hidden
 locale, you may need to set @samp{TIME_STYLE="locale"}.
 
+To avoid certain denial-of-service attacks, timestamps that would be
+longer than 1000 bytes may be treated as errors.
+
 
 @node Formatting the file names
 @subsection Formatting the file names
Index: src/ls.c
===================================================================
RCS file: /fetish/cu/src/ls.c,v
retrieving revision 1.376
diff -p -u -r1.376 ls.c
--- src/ls.c    10 Mar 2005 12:07:31 -0000      1.376
+++ src/ls.c    11 Mar 2005 23:12:12 -0000
@@ -643,6 +643,14 @@ static bool format_needs_stat;
 
 static bool format_needs_type;
 
+/* An arbitrary limit on the number of bytes in a printed time stamp.
+   This is set to a relatively small value to avoid the need to worry
+   about denial-of-service attacks on servers that run "ls" on behalf
+   of remote clients.  1000 bytes should be enough for any practical
+   time stamp format.  */
+
+enum { TIME_STAMP_LEN_MAXIMUM = MAX (1000, INT_STRLEN_BOUND (time_t)) };
+
 /* strftime formats for non-recent and recent files, respectively, in
    -l output.  */
 
@@ -3047,32 +3055,18 @@ long_time_expected_width (void)
     {
       time_t epoch = 0;
       struct tm const *tm = localtime (&epoch);
-      char const *fmt = long_time_format[0];
-      char initbuf[100];
-      char *buf = initbuf;
-      size_t bufsize = sizeof initbuf;
-      size_t len;
-
-      for (;;)
-       {
-         *buf = '\1';
-         len = nstrftime (buf, bufsize, fmt, tm, 0, 0);
-         if (len || ! *buf)
-           break;
-         if (buf == initbuf)
-           {
-             buf = NULL;
-             bufsize *= 2;
-           }
-         buf = x2nrealloc (buf, &bufsize, sizeof *buf);
+      char buf[TIME_STAMP_LEN_MAXIMUM + 1];
+
+      if (tm)
+       {
+         size_t len =
+           nstrftime (buf, sizeof buf, long_time_format[0], tm, 0, 0);
+         if (len != 0)
+           width = mbsnwidth (buf, len, 0);
        }
 
-      width = mbsnwidth (buf, len, 0);
       if (width < 0)
        width = 0;
-
-      if (buf != initbuf)
-       free (buf);
     }
 
   return width;
@@ -3200,17 +3194,15 @@ static void
 print_long_format (const struct fileinfo *f)
 {
   char modebuf[12];
-  char init_bigbuf
+  char buf
     [LONGEST_HUMAN_READABLE + 1                /* inode */
      + LONGEST_HUMAN_READABLE + 1      /* size in blocks */
      + sizeof (modebuf) - 1 + 1                /* mode string */
      + INT_BUFSIZE_BOUND (uintmax_t)   /* st_nlink */
      + LONGEST_HUMAN_READABLE + 2      /* major device number */
      + LONGEST_HUMAN_READABLE + 1      /* minor device number */
-     + 35 + 1  /* usual length of time/date -- may be longer; see below */
+     + TIME_STAMP_LEN_MAXIMUM + 1      /* max length of time/date */
      ];
-  char *buf = init_bigbuf;
-  size_t bufsize = sizeof (init_bigbuf);
   size_t s;
   char *p;
   time_t when;
@@ -3320,7 +3312,11 @@ print_long_format (const struct fileinfo
       p[-1] = ' ';
     }
 
-  if ((when_local = localtime (&when)))
+  when_local = localtime (&when);
+  s = 0;
+  *p = '\1';
+
+  if (when_local)
     {
       time_t six_months_ago;
       bool recent;
@@ -3349,28 +3345,12 @@ print_long_format (const struct fileinfo
                    || (when == current_time && when_ns <= current_time_ns)));
       fmt = long_time_format[recent];
 
-      for (;;)
-       {
-         char *newbuf;
-         *p = '\1';
-         s = nstrftime (p, buf + bufsize - p - 1, fmt,
-                        when_local, 0, when_ns);
-         if (s || ! *p)
-           break;
-         if (buf == init_bigbuf)
-           {
-             bufsize *= 2;
-             newbuf = xmalloc (bufsize);
-             memcpy (newbuf, buf, p - buf);
-           }
-         else
-           {
-             newbuf = x2nrealloc (buf, &bufsize, sizeof *buf);
-           }
-         p = newbuf + (p - buf);
-         buf = newbuf;
-       }
+      s = nstrftime (p, TIME_STAMP_LEN_MAXIMUM + 1, fmt,
+                    when_local, 0, when_ns);
+    }
 
+  if (s || !*p)
+    {
       p += s;
       *p++ = ' ';
 
@@ -3379,7 +3359,7 @@ print_long_format (const struct fileinfo
     }
   else
     {
-      /* The time cannot be represented as a local time;
+      /* The time cannot be converted using the desired format, so
         print it as a huge integer number of seconds.  */
       char hbuf[INT_BUFSIZE_BOUND (intmax_t)];
       sprintf (p, "%*s ", long_time_expected_width (),
@@ -3390,8 +3370,6 @@ print_long_format (const struct fileinfo
     }
 
   DIRED_FPUTS (buf, stdout, p - buf);
-  if (buf != init_bigbuf)
-    free (buf);
   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
                           &dired_obstack);
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]