klibc-bot for Herbert Xu
2020-Mar-28 21:49 UTC
[klibc] [klibc:update-dash] dash: expand: Fix buffer overflow in expandmeta
Commit-ID: e09252abe2baa4f033807c0c77ce273a804f041a Gitweb: http://git.kernel.org/?p=libs/klibc/klibc.git;a=commit;h=e09252abe2baa4f033807c0c77ce273a804f041a Author: Herbert Xu <herbert at gondor.apana.org.au> AuthorDate: Sun, 25 Mar 2018 16:38:00 +0800 Committer: Ben Hutchings <ben at decadent.org.uk> CommitDate: Sat, 28 Mar 2020 21:42:54 +0000 [klibc] dash: expand: Fix buffer overflow in expandmeta [ dash commit 0f3806dd899ace97d5909f195882697ef9dd1eaa ] The native version of expandmeta allocates a buffer that may be overrun for two reasons. First of all the size is 1 byte too small but this is normally hidden because the minimum size is rounded up to 2048 bytes. Secondly, if the directory level is deep enough, any buffer can be overrun. This patch fixes both problems by calling realloc when necessary. Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au> Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/dash/expand.c | 57 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/usr/dash/expand.c b/usr/dash/expand.c index 974a31de..f52f34c9 100644 --- a/usr/dash/expand.c +++ b/usr/dash/expand.c @@ -124,7 +124,7 @@ STATIC void expandmeta(struct strlist *, int); #ifdef HAVE_GLOB STATIC void addglob(const glob_t *); #else -STATIC void expmeta(char *, char *); +STATIC void expmeta(char *, unsigned, unsigned); STATIC struct strlist *expsort(struct strlist *); STATIC struct strlist *msort(struct strlist *, int); #endif @@ -1246,6 +1246,7 @@ addglob(pglob) #else /* HAVE_GLOB */ STATIC char *expdir; +STATIC unsigned expdir_max; STATIC void @@ -1260,6 +1261,7 @@ expandmeta(struct strlist *str, int flag) struct strlist **savelastp; struct strlist *sp; char *p; + unsigned len; if (fflag) goto nometa; @@ -1269,12 +1271,11 @@ expandmeta(struct strlist *str, int flag) INTOFF; p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); - { - int i = strlen(str->text); - expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ - } + len = strlen(p); + expdir_max = len + PATH_MAX; + expdir = ckmalloc(expdir_max); - expmeta(expdir, p); + expmeta(p, len, 0); ckfree(expdir); if (p != str->text) ckfree(p); @@ -1304,8 +1305,9 @@ nometa: */ STATIC void -expmeta(char *enddir, char *name) +expmeta(char *name, unsigned name_len, unsigned expdir_len) { + char *enddir = expdir + expdir_len; char *p; const char *cp; char *start; @@ -1348,15 +1350,15 @@ expmeta(char *enddir, char *name) } } if (metaflag == 0) { /* we've reached the end of the file name */ - if (enddir != expdir) - metaflag++; + if (!expdir_len) + return; p = name; do { if (*p == '\\') p++; *enddir++ = *p; } while (*p++); - if (metaflag == 0 || lstat64(expdir, &statb) >= 0) + if (lstat64(expdir, &statb) >= 0) addfname(expdir); return; } @@ -1369,18 +1371,13 @@ expmeta(char *enddir, char *name) *enddir++ = *p++; } while (p < start); } - if (enddir == expdir) { + *enddir = 0; + cp = expdir; + expdir_len = enddir - cp; + if (!expdir_len) cp = "."; - } else if (enddir == expdir + 1 && *expdir == '/') { - cp = "/"; - } else { - cp = expdir; - enddir[-1] = '\0'; - } if ((dirp = opendir(cp)) == NULL) return; - if (enddir != expdir) - enddir[-1] = '/'; if (*endname == 0) { atend = 1; } else { @@ -1388,6 +1385,7 @@ expmeta(char *enddir, char *name) *endname = '\0'; endname += esc + 1; } + name_len -= endname - name; matchdot = 0; p = start; if (*p == '\\') @@ -1402,11 +1400,22 @@ expmeta(char *enddir, char *name) scopy(dp->d_name, enddir); addfname(expdir); } else { - for (p = enddir, cp = dp->d_name; - (*p++ = *cp++) != '\0';) - continue; - p[-1] = '/'; - expmeta(p, endname); + unsigned offset; + unsigned len; + + p = stpcpy(enddir, dp->d_name); + *p = '/'; + + offset = p - expdir + 1; + len = offset + name_len + NAME_MAX; + if (len > expdir_max) { + len += PATH_MAX; + expdir = ckrealloc(expdir, len); + expdir_max = len; + } + + expmeta(endname, name_len, offset); + enddir = expdir + expdir_len; } } }
Reasonably Related Threads
- [klibc:update-dash] expand: Fix buffer overflow in expandmeta
- [klibc:update-dash] expand: Do not quote backslashes in unquoted parameter expansion
- [klibc:update-dash] dash: expand: Do not quote backslashes in unquoted parameter expansion
- [klibc:update-dash] [EXPAND] Split unquoted $@/$* correctly when IFS is set but empty
- [klibc:update-dash] dash: [EXPAND] Split unquoted $@/$* correctly when IFS is set but empty