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 (conk...@ngai.kaleida.com)
+	 */
+	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 (conk...@ngai.kaleida.com)
-	 */
-	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);
 }

Reply via email to