Source-Changes-HG archive

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

[src/netbsd-1-4]: src/lib/libc/gen Pull up revisions 1.16-1.25:



details:   https://anonhg.NetBSD.org/src/rev/5d82fe3f2746
branches:  netbsd-1-4
changeset: 469329:5d82fe3f2746
user:      he <he%NetBSD.org@localhost>
date:      Fri Sep 03 09:50:47 1999 +0000

description:
Pull up revisions 1.16-1.25:
  Fix various bug in fts(3), preventing a buffer overflow on a very
  deep tree, and a silent trucation of the path when fts_pathlen
  overflows.  Also, make this compile on Linux.  (bouyer)

diffstat:

 lib/libc/gen/__fts13.c |  124 +++++++++++++++++++++++++++++++++---------------
 1 files changed, 86 insertions(+), 38 deletions(-)

diffs (259 lines):

diff -r 3dd1dc0d15ae -r 5d82fe3f2746 lib/libc/gen/__fts13.c
--- a/lib/libc/gen/__fts13.c    Fri Sep 03 09:17:28 1999 +0000
+++ b/lib/libc/gen/__fts13.c    Fri Sep 03 09:50:47 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: __fts13.c,v 1.15 1999/03/16 18:13:44 christos Exp $    */
+/*     $NetBSD: __fts13.c,v 1.15.2.1 1999/09/03 09:50:47 he Exp $      */
 
 /*-
  * Copyright (c) 1990, 1993, 1994
@@ -38,7 +38,7 @@
 #if 0
 static char sccsid[] = "@(#)fts.c      8.6 (Berkeley) 8/14/94";
 #else
-__RCSID("$NetBSD: __fts13.c,v 1.15 1999/03/16 18:13:44 christos Exp $");
+__RCSID("$NetBSD: __fts13.c,v 1.15.2.1 1999/09/03 09:50:47 he Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -88,8 +88,9 @@
 static void     fts_lfree __P((FTSENT *));
 static void     fts_load __P((FTS *, FTSENT *));
 static size_t   fts_maxarglen __P((char * const *));
-static void     fts_padjust __P((FTS *, void *));
+static size_t   fts_pow2 __P((size_t));
 static int      fts_palloc __P((FTS *, size_t));
+static void     fts_padjust __P((FTS *, FTSENT *));
 static FTSENT  *fts_sort __P((FTS *, FTSENT *, size_t));
 static u_short  fts_stat __P((FTS *, FTSENT *, int));
 
@@ -601,8 +602,8 @@
        size_t nitems;
        FTSENT *cur, *tail;
        DIR *dirp;
-       void *adjaddr;
-       int cderrno, descend, len, level, maxlen, nlinks, saved_errno;
+       int adjust, cderrno, descend, len, level, nlinks, saved_errno, nostat;
+       size_t maxlen;
 #ifdef FTS_WHITEOUT
        int oflag;
 #endif
@@ -636,12 +637,16 @@
         * directory if we're cheating on stat calls, 0 if we're not doing
         * any stat calls at all, -1 if we're doing stats on everything.
         */
-       if (type == BNAMES)
+       if (type == BNAMES) {
                nlinks = 0;
-       else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL))
+               nostat = 1;
+       } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
                nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
-       else
+               nostat = 1;
+       } else {
                nlinks = -1;
+               nostat = 0;
+       }
 
 #ifdef notdef
        (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
@@ -686,32 +691,33 @@
         * If not changing directories set a pointer so that can just append
         * each new name into the path.
         */
-       maxlen = sp->fts_pathlen - cur->fts_pathlen - 1;
        len = NAPPEND(cur);
        if (ISSET(FTS_NOCHDIR)) {
                cp = sp->fts_path + len;
                *cp++ = '/';
        }
+       len++;
+       maxlen = sp->fts_pathlen - len;
 
        level = cur->fts_level + 1;
 
        /* Read the directory, attaching each entry to the `link' pointer. */
-       adjaddr = NULL;
+       adjust = 0;
        for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) {
                size_t dlen;
 
                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
                        continue;
 
-#if defined(__svr4__) || defined(__SVR4)
+#if defined(__svr4__) || defined(__SVR4) || defined(__linux__)
                dlen = strlen(dp->d_name);
 #else
                dlen = dp->d_namlen;
 #endif
                if ((p = fts_alloc(sp, dp->d_name, dlen)) == NULL)
                        goto mem1;
-               if (dlen > maxlen) {
-                       if (fts_palloc(sp, dlen)) {
+               if (dlen >= maxlen) {   /* include space for NUL */
+                       if (fts_palloc(sp, len + dlen + 1)) {
                                /*
                                 * No more memory for path or structures.  Save
                                 * errno, free up the current structure and the
@@ -727,11 +733,13 @@
                                SET(FTS_STOP);
                                return (NULL);
                        }
-                       adjaddr = sp->fts_path;
-                       maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1;
+                       adjust = 1;
+                       if (ISSET(FTS_NOCHDIR))
+                               cp = sp->fts_path + len;
+                       maxlen = sp->fts_pathlen - len;
                }
 
-               p->fts_pathlen = len + dlen + 1;
+               p->fts_pathlen = len + dlen;
                p->fts_parent = sp->fts_cur;
                p->fts_level = level;
 
@@ -749,7 +757,7 @@
                        p->fts_accpath = cur->fts_accpath;
                } else if (nlinks == 0
 #ifdef DT_DIR
-                   || (nlinks > 0 && 
+                   || (nostat && 
                    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
 #endif
                    ) {
@@ -789,8 +797,8 @@
         * If had to realloc the path, adjust the addresses for the rest
         * of the tree.
         */
-       if (adjaddr)
-               fts_padjust(sp, adjaddr);
+       if (adjust)
+               fts_padjust(sp, head);
 
        /*
         * If not changing directories, reset the path back to original
@@ -929,12 +937,13 @@
         * 40 so don't realloc one entry at a time.
         */
        if (nitems > sp->fts_nitems) {
+               FTSENT **new;
+
+               new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40));
+               if (new == 0)
+                       return (head);
+               sp->fts_array = new;
                sp->fts_nitems = nitems + 40;
-               if ((sp->fts_array = realloc(sp->fts_array,
-                   (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
-                       sp->fts_nitems = 0;
-                       return (head);
-               }
        }
        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
                *ap++ = p;
@@ -997,20 +1006,54 @@
        }
 }
 
+static size_t
+fts_pow2(x)
+       size_t x;
+{
+
+       x--;
+       x |= x>>1;
+       x |= x>>2;
+       x |= x>>4;
+       x |= x>>8;
+       x |= x>>16;
+#if LONG_BIT > 32
+       x |= x>>32;
+#endif
+#if LONG_BIT > 64
+       x |= x>>64;
+#endif
+       x++;
+       return (x);
+}
+
 /*
  * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
  * Most systems will allow creation of paths much longer than MAXPATHLEN, even
- * though the kernel won't resolve them.  Add the size (not just what's needed)
- * plus 256 bytes so don't realloc the path 2 bytes at a time. 
+ * though the kernel won't resolve them.  Round up the new size to a power of 2,
+ * so we don't realloc the path 2 bytes at a time. 
  */
 static int
-fts_palloc(sp, more)
+fts_palloc(sp, size)
        FTS *sp;
-       size_t more;
+       size_t size;
 {
-       sp->fts_pathlen += more + 256;
-       sp->fts_path = realloc(sp->fts_path, (size_t)sp->fts_pathlen);
-       return (sp->fts_path == NULL);
+       char *new;
+
+#if 1
+       /* Protect against fts_pathlen overflow. */
+       if (size > USHRT_MAX + 1) {
+               errno = ENOMEM;
+               return (1);
+       }
+#endif
+       size = fts_pow2(size);
+       new = realloc(sp->fts_path, size);
+       if (new == 0)
+               return (1);
+       sp->fts_path = new;
+       sp->fts_pathlen = size;
+       return (0);
 }
 
 /*
@@ -1018,23 +1061,28 @@
  * already returned.
  */
 static void
-fts_padjust(sp, addr)
+fts_padjust(sp, head)
        FTS *sp;
-       void *addr;
+       FTSENT *head;
 {
        FTSENT *p;
+       char *addr;
 
 #define        ADJUST(p) {                                                     \
-       (p)->fts_accpath =                                              \
-           (char *)addr + ((p)->fts_accpath - (p)->fts_path);          \
+       if ((p)->fts_accpath != (p)->fts_name)                          \
+               (p)->fts_accpath =                                      \
+                   addr + ((p)->fts_accpath - (p)->fts_path);          \
        (p)->fts_path = addr;                                           \
 }
+
+       addr = sp->fts_path;
+
        /* Adjust the current set of children. */
        for (p = sp->fts_child; p; p = p->fts_link)
                ADJUST(p);
 
-       /* Adjust the rest of the tree. */
-       for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+       /* Adjust the rest of the tree, including the current level. */
+       for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
                ADJUST(p);
                p = p->fts_link ? p->fts_link : p->fts_parent;
        }
@@ -1049,5 +1097,5 @@
        for (max = 0; *argv; ++argv)
                if ((len = strlen(*argv)) > max)
                        max = len;
-       return (max);
+       return (max + 1);
 }



Home | Main Index | Thread Index | Old Index