Module Name:    src
Committed By:   christos
Date:           Wed Apr 26 14:56:54 UTC 2017

Modified Files:
        src/lib/libc/gen: glob.c

Log Message:
Switch from a recursive pattern matching algorithm to handle '*'
to a backtracking one. Avoids DoS attacks with patterns "a*a*a*a*a*...b"
matching against "aaaaaaaaaaaa..." https://research.swtch.com/glob


To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/lib/libc/gen/glob.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/glob.c
diff -u src/lib/libc/gen/glob.c:1.36 src/lib/libc/gen/glob.c:1.37
--- src/lib/libc/gen/glob.c:1.36	Sun Sep  4 14:27:08 2016
+++ src/lib/libc/gen/glob.c	Wed Apr 26 10:56:54 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: glob.c,v 1.36 2016/09/04 18:27:08 joerg Exp $	*/
+/*	$NetBSD: glob.c,v 1.37 2017/04/26 14:56:54 christos 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.36 2016/09/04 18:27:08 joerg Exp $");
+__RCSID("$NetBSD: glob.c,v 1.37 2017/04/26 14:56:54 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -936,39 +936,45 @@ nospace:
 
 
 /*
- * pattern matching function for filenames.  Each occurrence of the *
- * pattern causes a recursion level.
+ * pattern matching function for filenames.
  */
 static int
 match(const Char *name, const Char *pat, const Char *patend)
 {
 	int ok, negate_range;
 	Char c, k;
+	const Char *patNext, *nameNext, *nameStart, *nameEnd;
 
 	_DIAGASSERT(name != NULL);
 	_DIAGASSERT(pat != NULL);
 	_DIAGASSERT(patend != NULL);
-
-	while (pat < patend) {
-		c = *pat++;
+	patNext = pat;
+	nameStart = nameNext = name;
+	nameEnd = NULL;
+
+	while (pat < patend || *name) {
+		c = *pat;
+		if (*name == EOS)
+			nameEnd = name;
 		switch (c & M_MASK) {
 		case M_ALL:
-			while (pat < patend && (*pat & M_MASK) == M_ALL)
-				pat++;	/* eat consecutive '*' */
-			if (pat == patend)
-				return 1;
-			for (; !match(name, pat, patend); name++)
-				if (*name == EOS)
-					return 0;
-			return 1;
+			while (pat[1] == '*') pat++;
+			patNext = pat;
+			nameNext = name + 1;
+			pat++;
+			continue;
 		case M_ONE:
-			if (*name++ == EOS)
-				return 0;
-			break;
+			if (*name == EOS)
+				break;
+			pat++;
+			name++;
+			continue;
 		case M_SET:
 			ok = 0;
-			if ((k = *name++) == EOS)
-				return 0;
+			if ((k = *name) == EOS)
+				break;
+			pat++;
+			name++;
 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
 				++pat;
 			while (((c = *pat++) & M_MASK) != M_END)
@@ -979,15 +985,24 @@ match(const Char *name, const Char *pat,
 				} else if (c == k)
 					ok = 1;
 			if (ok == negate_range)
-				return 0;
-			break;
+				break;
+			continue;
 		default:
-			if (*name++ != c)
-				return 0;
-			break;
+			if (*name != c)
+				break;
+			pat++;
+			name++;
+			continue;
 		}
+		if (nameNext != nameStart
+		    && (nameEnd == NULL || nameNext <= nameEnd)) {
+			pat = patNext;
+			name = nameNext;
+			continue;
+		}
+		return 0;
 	}
-	return *name == EOS;
+	return 1;
 }
 
 /* Free allocated data belonging to a glob_t structure. */

Reply via email to