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
2 changed files with 25 additions and 15 deletions

View File

@ -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 **);

View File

@ -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);
}
/*