Author: jilles
Date: Wed Aug  5 21:33:30 2015
New Revision: 286344
URL: https://svnweb.freebsd.org/changeset/base/286344

Log:
  find: Fix segfault with very long path in -exec/-ok ... {} \;.
  
  If the resulting argument is longer than MAXPATHLEN, realloc() was called to
  extend the space, but the new pointer was not correctly stored.
  
  Different from what OpenBSD has done, rewrite brace_subst() to calculate the
  necessary space first and realloc() at most once.
  
  As before, the e_len fields are not updated in case of a realloc.
  Therefore, a following long argument will do another realloc.
  
  PR:           201750
  MFC after:    1 week

Modified:
  head/usr.bin/find/extern.h
  head/usr.bin/find/misc.c

Modified: head/usr.bin/find/extern.h
==============================================================================
--- head/usr.bin/find/extern.h  Wed Aug  5 21:22:25 2015        (r286343)
+++ head/usr.bin/find/extern.h  Wed Aug  5 21:33:30 2015        (r286344)
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>
 
-void    brace_subst(char *, char **, char *, int);
+void    brace_subst(char *, char **, char *, size_t);
 PLAN   *find_create(char ***);
 int     find_execute(PLAN *, char **);
 PLAN   *find_formplan(char **);

Modified: head/usr.bin/find/misc.c
==============================================================================
--- head/usr.bin/find/misc.c    Wed Aug  5 21:22:25 2015        (r286343)
+++ head/usr.bin/find/misc.c    Wed Aug  5 21:33:30 2015        (r286344)
@@ -57,23 +57,33 @@ __FBSDID("$FreeBSD$");
  *     Replace occurrences of {} in s1 with s2 and return the result string.
  */
 void
-brace_subst(char *orig, char **store, char *path, int len)
+brace_subst(char *orig, char **store, char *path, size_t len)
 {
-       int plen;
-       char ch, *p;
+       const char *pastorigend, *p, *q;
+       char *dst;
+       size_t newlen, plen;
 
        plen = strlen(path);
-       for (p = *store; (ch = *orig) != '\0'; ++orig)
-               if (ch == '{' && orig[1] == '}') {
-                       while ((p - *store) + plen > len)
-                               if (!(*store = realloc(*store, len *= 2)))
-                                       err(1, NULL);
-                       memmove(p, path, plen);
-                       p += plen;
-                       ++orig;
-               } else
-                       *p++ = ch;
-       *p = '\0';
+       newlen = strlen(orig) + 1;
+       pastorigend = orig + newlen;
+       for (p = orig; (q = strstr(p, "{}")) != NULL; p = q + 2) {
+               if (plen > 2 && newlen + plen - 2 < newlen)
+                       errx(2, "brace_subst overflow");
+               newlen += plen - 2;
+       }
+       if (newlen > len) {
+               *store = reallocf(*store, newlen);
+               if (*store == NULL)
+                       err(2, NULL);
+       }
+       dst = *store;
+       for (p = orig; (q = strstr(p, "{}")) != NULL; p = q + 2) {
+               memcpy(dst, p, q - p);
+               dst += q - p;
+               memcpy(dst, path, plen);
+               dst += plen;
+       }
+       memcpy(dst, p, pastorigend - p);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to