Sun Apr 24 15:41:23 2011 UTC ()
Pull up following revision(s) (requested by spz in ticket #1597):
	lib/libc/gen/glob.c: revision 1.28
	lib/libc/gen/glob.c: revision 1.29
prevent resource DoS from brace expansion (from Maksymilian Arciemowicz)
remove stray printf.


(riz)
diff -r1.23.4.1 -r1.23.4.1.2.1 src/lib/libc/gen/glob.c

cvs diff -r1.23.4.1 -r1.23.4.1.2.1 src/lib/libc/gen/glob.c (expand / switch to context diff)
--- src/lib/libc/gen/glob.c 2010/07/19 18:14:08 1.23.4.1
+++ src/lib/libc/gen/glob.c 2011/04/24 15:41:23 1.23.4.1.2.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $	*/
+/*	$NetBSD: glob.c,v 1.23.4.1.2.1 2011/04/24 15:41:23 riz 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.23.4.1 2010/07/19 18:14:08 riz Exp $");
+__RCSID("$NetBSD: glob.c,v 1.23.4.1.2.1 2011/04/24 15:41:23 riz Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -87,13 +87,18 @@
 #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,18 +163,18 @@
 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	 glob2(Char *, Char *, Char *, Char *, glob_t *,
-    size_t *);
-static int	 glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
-    size_t *);
-static int	 globextend(const 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 *,
+    struct glob_limit *);
+static int	 glob3(Char *, Char *, Char *, const Char *, 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 *);
-static int	 match(Char *, Char *, Char *);
+    struct glob_limit *);
+static int	 match(const Char *, const Char *, const Char *);
 #ifdef DEBUG
 static void	 qprintf(const char *, Char *);
 #endif
@@ -181,8 +186,7 @@
 	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 @@
 	*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 @@
  * 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 @@
 	_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 @@
  */
 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 @@
  * 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;
@@ -567,7 +577,7 @@
 }
 
 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];
 
@@ -592,11 +602,12 @@
  * meta characters.
  */
 static int
-glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob,
-    size_t *limit)
+glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    glob_t *pglob, struct glob_limit *limit)
 {
 	__gl_stat_t sb;
-	Char *p, *q;
+	const Char *p;
+	Char *q;
 	int anymeta;
 	Char *pend;
 	ptrdiff_t diff;
@@ -617,7 +628,7 @@
 				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;
@@ -683,8 +694,8 @@
 }
 
 static int
-glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern,
-    Char *restpattern, glob_t *pglob, size_t *limit)
+glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    const Char *restpattern, glob_t *pglob, struct glob_limit *limit)
 {
 	struct dirent *dp;
 	DIR *dirp;
@@ -740,7 +751,7 @@
 		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;
@@ -829,7 +840,7 @@
  *	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;
@@ -840,6 +851,9 @@
 	_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)
@@ -856,7 +870,7 @@
 	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);
@@ -867,12 +881,13 @@
 	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;
 }
 
 
@@ -881,7 +896,7 @@
  * pattern causes a recursion level.
  */
 static int
-match(Char *name, Char *pat, Char *patend)
+match(const Char *name, const Char *pat, const Char *patend)
 {
 	int ok, negate_range;
 	Char c, k;