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