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); }