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. */