HEADS UP - Security flaw in libc glob code

Matthias Schmidt matthias at dragonflybsd.org
Fri Oct 8 02:22:14 PDT 2010


Hi,

attached is a patch (based on the one of NetBSD) which fixes the glob
issue.  Please test the patch to be sure that everything works (it
should be).

The patch is also available here:

http://leaf.dragonflybsd.org/~matthias/libc_glob_flaw.diff

Cheers

	Matthias
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index 0f25c58..9a88a47 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -137,6 +137,14 @@ typedef char Char;
 #define	ismeta(c)	(((c)&M_QUOTE) != 0)
 
 
+#define	GLOB_LIMIT_MALLOC	65536
+#define	GLOB_LIMIT_STAT		128
+#define	GLOB_LIMIT_READDIR	16384
+
+#define	GLOB_INDEX_MALLOC	0
+#define	GLOB_INDEX_STAT		1
+#define	GLOB_INDEX_READDIR	2
+
 static int	 compare(const void *, const void *);
 static int	 g_Ctoc(const Char *, char *, size_t);
 static int	 g_lstat(const Char *, struct stat *, glob_t *);
@@ -162,6 +170,9 @@ static int	 match(const Char *, const Char *, const Char *);
 static void	 qprintf(const char *, const Char *);
 #endif
 
+/* 0 = malloc(), 1 = stat(), 2 = readdir() */
+static size_t limits[] = { 0, 0, 0 };
+
 int
 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
      glob_t *pglob)
@@ -560,6 +571,14 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend_last, const Char *pattern,
 			if (g_lstat(pathbuf, &sb, pglob))
 				return(0);
 
+			if ((pglob->gl_flags & GLOB_LIMIT) &&
+			    limits[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) {
+				errno = 0;
+				*pathend++ = SEP;
+				*pathend = EOS;
+				return GLOB_NOSPACE;
+			}
+
 			if (((pglob->gl_flags & GLOB_MARK) &&
 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
 			    || (S_ISLNK(sb.st_mode) &&
@@ -643,6 +662,14 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last, const Char *pattern,
 		size_t clen;
 		mbstate_t mbs;
 
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limits[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) {
+			errno = 0;
+			*pathend++ = SEP;
+			*pathend = EOS;
+			return GLOB_NOSPACE;
+		}
+
 		/* Initial DOT must be matched literally. */
 		if (dp->d_name[0] == DOT && *pattern != DOT &&
 		    !(pglob->gl_flags & GLOB_PERIOD))
@@ -729,6 +756,7 @@ globextend(const Char *path, glob_t *pglob, size_t *limit)
 	for (p = path; *p++;)
 		continue;
 	len = MB_CUR_MAX * (size_t)(p - path);	/* XXX overallocation */
+	limits[GLOB_INDEX_MALLOC] += len;
 	if ((copy = malloc(len)) != NULL) {
 		if (g_Ctoc(path, copy, len)) {
 			free(copy);
@@ -737,6 +765,12 @@ globextend(const Char *path, glob_t *pglob, size_t *limit)
 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
 	}
 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+	if ((pglob->gl_flags & GLOB_LIMIT) &&
+		(newsize + limits[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) {
+		errno = 0;
+		return GLOB_NOSPACE;
+	}
+
 	return(copy == NULL ? GLOB_NOSPACE : 0);
 }
 




More information about the Users mailing list