summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-08-10 22:45:59 +0000
committerjilles <jilles@FreeBSD.org>2010-08-10 22:45:59 +0000
commit8824c5ab7690895c9f4c64dc73d5cbd0dd4d62e4 (patch)
tree7e2b11fc91b3dd1fd5d1dc48d4e2e40ebee05f55 /bin/sh/expand.c
parent243488333fe36a4095d1e102254a664ed1effc85 (diff)
downloadFreeBSD-src-8824c5ab7690895c9f4c64dc73d5cbd0dd4d62e4.zip
FreeBSD-src-8824c5ab7690895c9f4c64dc73d5cbd0dd4d62e4.tar.gz
sh: Fix heap-based buffer overflow in pathname generation.
The buffer for generated pathnames could be too small in some cases. It happened to be always at least PATH_MAX long, so there was never an overflow if the resulting pathnames would be usable. This bug may be abused if a script subjects input from an untrusted source to pathname generation, which a bad idea anyhow. Most shell scripts do not work on untrusted data. secteam@ says no advisory is necessary. PR: bin/148733 Reported by: Changming Sun snnn119 at gmail com MFC after: 10 days
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r--bin/sh/expand.c31
1 files changed, 15 insertions, 16 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index 6c81224..fded6da 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -1082,8 +1082,8 @@ ifsbreakup(char *string, struct arglist *arglist)
* should be escapes. The results are stored in the list exparg.
*/
-STATIC char *expdir;
-
+STATIC char expdir[PATH_MAX];
+#define expdir_end (expdir + sizeof(expdir))
STATIC void
expandmeta(struct strlist *str, int flag __unused)
@@ -1106,14 +1106,7 @@ expandmeta(struct strlist *str, int flag __unused)
}
savelastp = exparg.lastp;
INTOFF;
- if (expdir == NULL) {
- int i = strlen(str->text);
- expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
- }
-
expmeta(expdir, str->text);
- ckfree(expdir);
- expdir = NULL;
INTON;
if (exparg.lastp == savelastp) {
/*
@@ -1202,6 +1195,8 @@ expmeta(char *enddir, char *name)
*enddir++ = *p;
if (*p == '\0')
break;
+ if (enddir == expdir_end)
+ return;
}
if (metaflag == 0 || lstat(expdir, &statb) >= 0)
addfname(expdir);
@@ -1216,6 +1211,8 @@ expmeta(char *enddir, char *name)
if (*p == CTLESC)
p++;
*enddir++ = *p++;
+ if (enddir == expdir_end)
+ return;
}
}
if (enddir == expdir) {
@@ -1249,15 +1246,17 @@ expmeta(char *enddir, char *name)
if (dp->d_name[0] == '.' && ! matchdot)
continue;
if (patmatch(start, dp->d_name, 0)) {
- if (atend) {
- scopy(dp->d_name, enddir);
+ if (enddir + dp->d_namlen + 1 > expdir_end)
+ continue;
+ memcpy(enddir, dp->d_name, dp->d_namlen + 1);
+ if (atend)
addfname(expdir);
- } else {
- for (p = enddir, q = dp->d_name;
- (*p++ = *q++) != '\0';)
+ else {
+ if (enddir + dp->d_namlen + 2 > expdir_end)
continue;
- p[-1] = '/';
- expmeta(p, endname);
+ enddir[dp->d_namlen] = '/';
+ enddir[dp->d_namlen + 1] = '\0';
+ expmeta(enddir + dp->d_namlen + 1, endname);
}
}
}
OpenPOWER on IntegriCloud