prevent resource DoS from brace expansion (from Maksymilian Arciemowicz)
This commit is contained in:
parent
705a4fcdb3
commit
e6d36a6ae6
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: glob.c,v 1.27 2010/09/06 14:40:25 christos Exp $ */
|
||||
/* $NetBSD: glob.c,v 1.28 2011/01/21 23:30:31 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: glob.c,v 1.27 2010/09/06 14:40:25 christos Exp $");
|
||||
__RCSID("$NetBSD: glob.c,v 1.28 2011/01/21 23:30:31 christos Exp $");
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
|
@ -87,13 +87,18 @@ __RCSID("$NetBSD: glob.c,v 1.27 2010/09/06 14:40:25 christos Exp $");
|
|||
#define NO_GETPW_R
|
||||
#endif
|
||||
|
||||
#define GLOB_LIMIT_MALLOC 65536
|
||||
#define GLOB_LIMIT_STAT 128
|
||||
#define GLOB_LIMIT_READDIR 16384
|
||||
#define GLOB_LIMIT_STRING 65536 /* number of readdirs */
|
||||
#define GLOB_LIMIT_STAT 128 /* number of stat system calls */
|
||||
#define GLOB_LIMIT_READDIR 16384 /* total buffer size of path strings */
|
||||
#define GLOB_LIMIT_PATH 1024 /* number of path elements */
|
||||
#define GLOB_LIMIT_BRACE 128 /* Number of brace calls */
|
||||
|
||||
#define GLOB_INDEX_MALLOC 0
|
||||
#define GLOB_INDEX_STAT 1
|
||||
#define GLOB_INDEX_READDIR 2
|
||||
struct glob_limit {
|
||||
size_t l_string;
|
||||
size_t l_stat;
|
||||
size_t l_readdir;
|
||||
size_t l_brace;
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX: For NetBSD 1.4.x compatibility. (kill me l8r)
|
||||
|
@ -158,17 +163,17 @@ static int g_lstat(Char *, __gl_stat_t *, glob_t *);
|
|||
static DIR *g_opendir(Char *, glob_t *);
|
||||
static Char *g_strchr(const Char *, int);
|
||||
static int g_stat(Char *, __gl_stat_t *, glob_t *);
|
||||
static int glob0(const Char *, glob_t *, size_t *);
|
||||
static int glob1(Char *, glob_t *, size_t *);
|
||||
static int glob0(const Char *, glob_t *, struct glob_limit *);
|
||||
static int glob1(Char *, glob_t *, struct glob_limit *);
|
||||
static int glob2(Char *, Char *, Char *, const Char *, glob_t *,
|
||||
size_t *);
|
||||
struct glob_limit *);
|
||||
static int glob3(Char *, Char *, Char *, const Char *, const Char *,
|
||||
const Char *, glob_t *, size_t *);
|
||||
static int globextend(const Char *, glob_t *, size_t *);
|
||||
const Char *, glob_t *, struct glob_limit *);
|
||||
static int globextend(const Char *, glob_t *, struct glob_limit *);
|
||||
static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
|
||||
static int globexp1(const Char *, glob_t *, size_t *);
|
||||
static int globexp1(const Char *, glob_t *, struct glob_limit *);
|
||||
static int globexp2(const Char *, const Char *, glob_t *, int *,
|
||||
size_t *);
|
||||
struct glob_limit *);
|
||||
static int match(const Char *, const Char *, const Char *);
|
||||
#ifdef DEBUG
|
||||
static void qprintf(const char *, Char *);
|
||||
|
@ -181,8 +186,7 @@ glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
|
|||
const u_char *patnext;
|
||||
int c;
|
||||
Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
|
||||
/* 0 = malloc(), 1 = stat(), 2 = readdir() */
|
||||
size_t limit[] = { 0, 0, 0 };
|
||||
struct glob_limit limit = { 0, 0, 0, 0 };
|
||||
|
||||
_DIAGASSERT(pattern != NULL);
|
||||
|
||||
|
@ -218,9 +222,9 @@ glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
|
|||
*bufnext = EOS;
|
||||
|
||||
if (flags & GLOB_BRACE)
|
||||
return globexp1(patbuf, pglob, limit);
|
||||
return globexp1(patbuf, pglob, &limit);
|
||||
else
|
||||
return glob0(patbuf, pglob, limit);
|
||||
return glob0(patbuf, pglob, &limit);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -229,7 +233,7 @@ glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
|
|||
* characters
|
||||
*/
|
||||
static int
|
||||
globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
|
||||
globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
|
||||
{
|
||||
const Char* ptr = pattern;
|
||||
int rv;
|
||||
|
@ -237,6 +241,12 @@ globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
|
|||
_DIAGASSERT(pattern != NULL);
|
||||
_DIAGASSERT(pglob != NULL);
|
||||
|
||||
if ((pglob->gl_flags & GLOB_LIMIT) &&
|
||||
limit->l_brace++ >= GLOB_LIMIT_BRACE) {
|
||||
errno = 0;
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
|
||||
/* Protect a single {}, for find(1), like csh */
|
||||
if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
|
||||
return glob0(pattern, pglob, limit);
|
||||
|
@ -256,7 +266,7 @@ globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
|
|||
*/
|
||||
static int
|
||||
globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
|
||||
size_t *limit)
|
||||
struct glob_limit *limit)
|
||||
{
|
||||
int i;
|
||||
Char *lm, *ls;
|
||||
|
@ -461,7 +471,7 @@ globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob)
|
|||
* to find no matches.
|
||||
*/
|
||||
static int
|
||||
glob0(const Char *pattern, glob_t *pglob, size_t *limit)
|
||||
glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
|
||||
{
|
||||
const Char *qpatnext;
|
||||
int c, error;
|
||||
|
@ -570,7 +580,7 @@ compare(const void *p, const void *q)
|
|||
}
|
||||
|
||||
static int
|
||||
glob1(Char *pattern, glob_t *pglob, size_t *limit)
|
||||
glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
|
||||
{
|
||||
Char pathbuf[MAXPATHLEN+1];
|
||||
|
||||
|
@ -596,7 +606,7 @@ glob1(Char *pattern, glob_t *pglob, size_t *limit)
|
|||
*/
|
||||
static int
|
||||
glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
||||
glob_t *pglob, size_t *limit)
|
||||
glob_t *pglob, struct glob_limit *limit)
|
||||
{
|
||||
__gl_stat_t sb;
|
||||
const Char *p;
|
||||
|
@ -624,10 +634,11 @@ glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
|||
return 0;
|
||||
|
||||
if ((pglob->gl_flags & GLOB_LIMIT) &&
|
||||
limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) {
|
||||
limit->l_stat++ >= GLOB_LIMIT_STAT) {
|
||||
errno = 0;
|
||||
*pathend++ = SEP;
|
||||
*pathend = EOS;
|
||||
printf("stat limit\n");
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
if (((pglob->gl_flags & GLOB_MARK) &&
|
||||
|
@ -692,7 +703,7 @@ glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
|||
static int
|
||||
glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
||||
const Char *restpattern, const Char *pglobstar, glob_t *pglob,
|
||||
size_t *limit)
|
||||
struct glob_limit *limit)
|
||||
{
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
|
@ -785,7 +796,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
|||
Char *dc;
|
||||
|
||||
if ((pglob->gl_flags & GLOB_LIMIT) &&
|
||||
limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) {
|
||||
limit->l_readdir++ >= GLOB_LIMIT_READDIR) {
|
||||
errno = 0;
|
||||
*pathend++ = SEP;
|
||||
*pathend = EOS;
|
||||
|
@ -894,7 +905,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
|
|||
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
|
||||
*/
|
||||
static int
|
||||
globextend(const Char *path, glob_t *pglob, size_t *limit)
|
||||
globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
|
||||
{
|
||||
char **pathv;
|
||||
size_t i, newsize, len;
|
||||
|
@ -905,6 +916,9 @@ globextend(const Char *path, glob_t *pglob, size_t *limit)
|
|||
_DIAGASSERT(pglob != NULL);
|
||||
|
||||
newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
|
||||
if ((pglob->gl_flags & GLOB_LIMIT) &&
|
||||
newsize > GLOB_LIMIT_PATH * sizeof(*pathv))
|
||||
goto nospace;
|
||||
pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :
|
||||
malloc(newsize);
|
||||
if (pathv == NULL)
|
||||
|
@ -921,7 +935,7 @@ globextend(const Char *path, glob_t *pglob, size_t *limit)
|
|||
for (p = path; *p++;)
|
||||
continue;
|
||||
len = (size_t)(p - path);
|
||||
limit[GLOB_INDEX_MALLOC] += len;
|
||||
limit->l_string += len;
|
||||
if ((copy = malloc(len)) != NULL) {
|
||||
if (g_Ctoc(path, copy, len)) {
|
||||
free(copy);
|
||||
|
@ -932,12 +946,13 @@ globextend(const Char *path, glob_t *pglob, size_t *limit)
|
|||
pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
|
||||
|
||||
if ((pglob->gl_flags & GLOB_LIMIT) &&
|
||||
(newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) {
|
||||
errno = 0;
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
(newsize + limit->l_string) >= GLOB_LIMIT_STRING)
|
||||
goto nospace;
|
||||
|
||||
return copy == NULL ? GLOB_NOSPACE : 0;
|
||||
nospace:
|
||||
errno = 0;
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue