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