Module Name: src
Committed By: christos
Date: Mon Jan 31 04:20:50 UTC 2011
Modified Files:
src/lib/libc/gen: fnmatch.c
Log Message:
Limit recursions to avoid DoS attacks from Maksymilian Arciemowicz
To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.22 src/lib/libc/gen/fnmatch.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libc/gen/fnmatch.c
diff -u src/lib/libc/gen/fnmatch.c:1.21 src/lib/libc/gen/fnmatch.c:1.22
--- src/lib/libc/gen/fnmatch.c:1.21 Sat Dec 24 16:11:16 2005
+++ src/lib/libc/gen/fnmatch.c Sun Jan 30 23:20:50 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $ */
+/* $NetBSD: fnmatch.c,v 1.22 2011/01/31 04:20:50 christos Exp $ */
/*
* Copyright (c) 1989, 1993, 1994
@@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
#else
-__RCSID("$NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $");
+__RCSID("$NetBSD: fnmatch.c,v 1.22 2011/01/31 04:20:50 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@@ -59,23 +59,59 @@
#define EOS '\0'
-static const char *rangematch __P((const char *, int, int));
-
static inline int
foldcase(int ch, int flags)
{
if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
- return (tolower(ch));
- return (ch);
+ return tolower(ch);
+ return ch;
}
#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
-int
-fnmatch(pattern, string, flags)
- const char *pattern, *string;
- int flags;
+static const char *
+rangematch(const char *pattern, int test, int flags)
+{
+ int negate, ok;
+ char c, c2;
+
+ _DIAGASSERT(pattern != NULL);
+
+ /*
+ * A bracket expression starting with an unquoted circumflex
+ * character produces unspecified results (IEEE 1003.2-1992,
+ * 3.13.2). This implementation treats it like '!', for
+ * consistency with the regular expression syntax.
+ * J.T. Conklin ([email protected])
+ */
+ if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
+ ++pattern;
+
+ for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
+ if (c == '\\' && !(flags & FNM_NOESCAPE))
+ c = FOLDCASE(*pattern++, flags);
+ if (c == EOS)
+ return NULL;
+ if (*pattern == '-'
+ && (c2 = FOLDCASE(*(pattern + 1), flags)) != EOS &&
+ c2 != ']') {
+ pattern += 2;
+ if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ c2 = FOLDCASE(*pattern++, flags);
+ if (c2 == EOS)
+ return NULL;
+ if (c <= test && test <= c2)
+ ok = 1;
+ } else if (c == test)
+ ok = 1;
+ }
+ return ok == negate ? NULL : pattern;
+}
+
+
+static int
+fnmatchx(const char *pattern, const char *string, int flags, size_t recursion)
{
const char *stringstart;
char c, test;
@@ -83,21 +119,24 @@
_DIAGASSERT(pattern != NULL);
_DIAGASSERT(string != NULL);
+ if (recursion-- == 0)
+ return FNM_NORES;
+
for (stringstart = string;;)
switch (c = FOLDCASE(*pattern++, flags)) {
case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/')
- return (0);
- return (*string == EOS ? 0 : FNM_NOMATCH);
+ return 0;
+ return *string == EOS ? 0 : FNM_NOMATCH;
case '?':
if (*string == EOS)
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
if (*string == '/' && (flags & FNM_PATHNAME))
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
++string;
break;
case '*':
@@ -109,41 +148,45 @@
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
/* Optimize for pattern with * at end or before /. */
if (c == EOS) {
if (flags & FNM_PATHNAME)
- return ((flags & FNM_LEADING_DIR) ||
+ return (flags & FNM_LEADING_DIR) ||
strchr(string, '/') == NULL ?
- 0 : FNM_NOMATCH);
+ 0 : FNM_NOMATCH;
else
- return (0);
+ return 0;
} else if (c == '/' && flags & FNM_PATHNAME) {
if ((string = strchr(string, '/')) == NULL)
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
break;
}
/* General case, use recursion. */
while ((test = FOLDCASE(*string, flags)) != EOS) {
- if (!fnmatch(pattern, string,
- flags & ~FNM_PERIOD))
- return (0);
+ int e;
+ switch ((e = fnmatchx(pattern, string,
+ flags & ~FNM_PERIOD, recursion))) {
+ case FNM_NOMATCH:
+ break;
+ default:
+ return e;
+ }
if (test == '/' && flags & FNM_PATHNAME)
break;
++string;
}
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
case '[':
if (*string == EOS)
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
if (*string == '/' && flags & FNM_PATHNAME)
- return (FNM_NOMATCH);
- if ((pattern =
- rangematch(pattern, FOLDCASE(*string, flags),
- flags)) == NULL)
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
+ if ((pattern = rangematch(pattern,
+ FOLDCASE(*string, flags), flags)) == NULL)
+ return FNM_NOMATCH;
++string;
break;
case '\\':
@@ -156,49 +199,14 @@
/* FALLTHROUGH */
default:
if (c != FOLDCASE(*string++, flags))
- return (FNM_NOMATCH);
+ return FNM_NOMATCH;
break;
}
/* NOTREACHED */
}
-static const char *
-rangematch(pattern, test, flags)
- const char *pattern;
- int test, flags;
+int
+fnmatch(const char *pattern, const char *string, int flags)
{
- int negate, ok;
- char c, c2;
-
- _DIAGASSERT(pattern != NULL);
-
- /*
- * A bracket expression starting with an unquoted circumflex
- * character produces unspecified results (IEEE 1003.2-1992,
- * 3.13.2). This implementation treats it like '!', for
- * consistency with the regular expression syntax.
- * J.T. Conklin ([email protected])
- */
- if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
- ++pattern;
-
- for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
- if (c == '\\' && !(flags & FNM_NOESCAPE))
- c = FOLDCASE(*pattern++, flags);
- if (c == EOS)
- return (NULL);
- if (*pattern == '-'
- && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
- c2 != ']') {
- pattern += 2;
- if (c2 == '\\' && !(flags & FNM_NOESCAPE))
- c2 = FOLDCASE(*pattern++, flags);
- if (c2 == EOS)
- return (NULL);
- if (c <= test && test <= c2)
- ok = 1;
- } else if (c == test)
- ok = 1;
- }
- return (ok == negate ? NULL : pattern);
+ return fnmatchx(pattern, string, flags, 128);
}