bug-glibc
[Top][All Lists]
Advanced

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

heap-corrupting bug in ftw.c


From: Jim Meyering
Subject: heap-corrupting bug in ftw.c
Date: Wed, 05 Feb 2003 18:09:58 +0100

When compiling ftw.c on a system like solaris-2.7 (or 2.8 or 2.9, and probably
on the Hurd, too), it turns out that PATH_MAX is not defined here:

  #ifdef PATH_MAX
    data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
  #else
    data.dirbufsize = 2 * strlen (dir);
  #endif

So, when ftw is invoked e.g. with "/", dirbufsize gets a value of `2'.
Then, when process_entry is called, say with `lost+found', it tries
to append that string to `/' in a buffer of length 4.  Of course
that results in a buffer overrun.

FWIW, this problem could cause du (from coreutils-4.5.5) to segfault
on Solaris systems.

Here's one way to fix it:
[note that this change conflicts slightly with the one I
 sent twice regarding how ftw treats trailing slashes]

2003-02-05  Jim Meyering  <address@hidden>

        Fix a heap-corrupting bug.
        * io/ftw.c: Include <limits.h>.
        (PATH_MAX) [!defined PATH_MAX]: Define to 1024.
        (process_entry): Allocate enough space to hold the resulting
        file name.  Don't presume that 2*dirbufsize is enough.
        (ftw_startup): Always use PATH_MAX to compute buffer size, now that
        it is guaranteed to be defined.

Index: io/ftw.c
===================================================================
RCS file: /cvs/glibc/libc/io/ftw.c,v
retrieving revision 1.39
diff -u -p -r1.39 ftw.c
--- io/ftw.c    2 Feb 2003 21:50:48 -0000       1.39
+++ io/ftw.c    5 Feb 2003 17:01:38 -0000
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
 #if HAVE_SYS_PARAM_H || defined _LIBC
 # include <sys/param.h>
 #endif
@@ -41,6 +42,10 @@
 /* #define NDEBUG 1 */
 #include <assert.h>
 
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
 #ifndef _LIBC
 # undef __chdir
 # define __chdir chdir
@@ -282,18 +287,20 @@ process_entry (struct ftw_data *data, st
   struct STAT st;
   int result = 0;
   int flag = 0;
+  size_t new_buflen;
 
   if (name[0] == '.' && (name[1] == '\0'
                         || (name[1] == '.' && name[2] == '\0')))
     /* Don't process the "." and ".." entries.  */
     return 0;
 
-  if (data->dirbufsize < data->ftw.base + namlen + 2)
+  new_buflen = data->ftw.base + namlen + 2;
+  if (data->dirbufsize < new_buflen)
     {
       /* Enlarge the buffer.  */
       char *newp;
 
-      data->dirbufsize *= 2;
+      data->dirbufsize = 2 * new_buflen;
       newp = (char *) realloc (data->dirbuf, data->dirbufsize);
       if (newp == NULL)
        return -1;
@@ -518,11 +525,7 @@ ftw_startup (const char *dir, int is_nft
                                                 * sizeof (struct dir_data *));
   memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
 
-#ifdef PATH_MAX
   data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
-#else
-  data.dirbufsize = 2 * strlen (dir);
-#endif
   data.dirbuf = (char *) malloc (data.dirbufsize);
   if (data.dirbuf == NULL)
     return -1;

Attachment: pgpxiv2aMKSiV.pgp
Description: PGP signature


reply via email to

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