diff options
author | Barton E. Schaefer <schaefer@zsh.org> | 2014-01-19 17:41:06 -0800 |
---|---|---|
committer | Barton E. Schaefer <schaefer@zsh.org> | 2014-01-19 19:39:31 -0800 |
commit | 3e06aeabd8a9e8384ebaa8b08996cd1f64737210 (patch) | |
tree | 698cb2e6ec17ae39426c90600aa597d7473767e8 | |
parent | 4777c07c8eadd49a51e4a719b969a0d2aa60906f (diff) | |
download | zsh-3e06aeabd8a9e8384ebaa8b08996cd1f64737210.tar.gz zsh-3e06aeabd8a9e8384ebaa8b08996cd1f64737210.tar.xz zsh-3e06aeabd8a9e8384ebaa8b08996cd1f64737210.zip |
32294: prevent buffer overflow when scanning very long directory paths for symbolic links
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | Src/utils.c | 31 |
2 files changed, 21 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog index 52b4fb7aa..4a134644d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2014-01-19 Barton E. Schaefer <schaefer@zsh.org> + * 32294 (plus typo fix): Src/utils.c: prevent buffer overflow when + scanning very long directory paths for symbolic links + * users/18335: Completion/Zsh/Command/_typeset: avoid passing to "functions" those typeset options that it does not accept diff --git a/Src/utils.c b/Src/utils.c index c6d178ce2..e1fd7a35b 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -725,32 +725,36 @@ xsymlinks(char *s) char **pp, **opp; char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; int t0, ret = 0; + zulong xbuflen = strlen(xbuf); opp = pp = slashsplit(s); - for (; *pp; pp++) { - if (!strcmp(*pp, ".")) { - zsfree(*pp); + for (; xbuflen < sizeof(xbuf) && *pp; pp++) { + if (!strcmp(*pp, ".")) continue; - } if (!strcmp(*pp, "..")) { char *p; - zsfree(*pp); if (!strcmp(xbuf, "/")) continue; if (!*xbuf) continue; - p = xbuf + strlen(xbuf); - while (*--p != '/'); + p = xbuf + xbuflen; + while (*--p != '/') + xbuflen--; *p = '\0'; continue; } sprintf(xbuf2, "%s/%s", xbuf, *pp); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); if (t0 == -1) { - strcat(xbuf, "/"); - strcat(xbuf, *pp); - zsfree(*pp); + zulong pplen = strlen(*pp) + 1; + if ((xbuflen += pplen) < sizeof(xbuf)) { + strcat(xbuf, "/"); + strcat(xbuf, *pp); + } else { + *xbuf = 0; + break; + } } else { ret = 1; metafy(xbuf3, t0, META_NOALLOC); @@ -759,10 +763,9 @@ xsymlinks(char *s) xsymlinks(xbuf3 + 1); } else xsymlinks(xbuf3); - zsfree(*pp); } } - free(opp); + freearray(opp); return ret; } @@ -779,8 +782,10 @@ xsymlink(char *s) return NULL; *xbuf = '\0'; xsymlinks(s + 1); - if (!*xbuf) + if (!*xbuf) { + zwarn("path expansion failed, using root directory"); return ztrdup("/"); + } return ztrdup(xbuf); } |