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
This commit is contained in:
parent
f5113df97d
commit
c8a3d81f34
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=211155
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
tools/regression/bin/sh/expansion/pathname3.0
Normal file
29
tools/regression/bin/sh/expansion/pathname3.0
Normal file
@ -0,0 +1,29 @@
|
||||
# $FreeBSD$
|
||||
|
||||
v=12345678
|
||||
v=$v$v$v$v
|
||||
v=$v$v$v$v
|
||||
v=$v$v$v$v
|
||||
v=$v$v$v$v
|
||||
v=$v$v$v$v
|
||||
# 8192 bytes
|
||||
v=${v##???}
|
||||
[ /*/$v = "/*/$v" ] || exit 1
|
||||
|
||||
s=////
|
||||
s=$s$s$s$s
|
||||
s=$s$s$s$s
|
||||
s=$s$s$s$s
|
||||
s=$s$s$s$s
|
||||
# 1024 bytes
|
||||
s=${s##??????????}
|
||||
[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
|
||||
while [ ${#s} -lt 1034 ]; do
|
||||
set -- /.${s}et[c]
|
||||
[ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
|
||||
set -- /.${s}et[c]/
|
||||
[ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
|
||||
set -- /.${s}et[c]/.
|
||||
[ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
|
||||
s=$s/
|
||||
done
|
Loading…
Reference in New Issue
Block a user