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
This commit is contained in:
Jilles Tjoelker 2015-08-05 21:33:30 +00:00
parent 70c81b2077
commit a2925a5ae3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=286344
2 changed files with 25 additions and 15 deletions

View File

@ -32,7 +32,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
void brace_subst(char *, char **, char *, int); void brace_subst(char *, char **, char *, size_t);
PLAN *find_create(char ***); PLAN *find_create(char ***);
int find_execute(PLAN *, char **); int find_execute(PLAN *, char **);
PLAN *find_formplan(char **); PLAN *find_formplan(char **);

View File

@ -57,23 +57,33 @@ __FBSDID("$FreeBSD$");
* Replace occurrences of {} in s1 with s2 and return the result string. * Replace occurrences of {} in s1 with s2 and return the result string.
*/ */
void void
brace_subst(char *orig, char **store, char *path, int len) brace_subst(char *orig, char **store, char *path, size_t len)
{ {
int plen; const char *pastorigend, *p, *q;
char ch, *p; char *dst;
size_t newlen, plen;
plen = strlen(path); plen = strlen(path);
for (p = *store; (ch = *orig) != '\0'; ++orig) newlen = strlen(orig) + 1;
if (ch == '{' && orig[1] == '}') { pastorigend = orig + newlen;
while ((p - *store) + plen > len) for (p = orig; (q = strstr(p, "{}")) != NULL; p = q + 2) {
if (!(*store = realloc(*store, len *= 2))) if (plen > 2 && newlen + plen - 2 < newlen)
err(1, NULL); errx(2, "brace_subst overflow");
memmove(p, path, plen); newlen += plen - 2;
p += plen; }
++orig; if (newlen > len) {
} else *store = reallocf(*store, newlen);
*p++ = ch; if (*store == NULL)
*p = '\0'; 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);
} }
/* /*