7049240 Problem with utility/apache
authorPetr Sumbera <petr.sumbera@oracle.com>
Mon, 15 Aug 2011 11:41:24 -0700
changeset 472 b4bf6ad34a2d
parent 471 ed3afe437ba0
child 473 b88384d5a7ae
7049240 Problem with utility/apache
components/apr/patches/CVE-2011-0419.patch
components/apr/patches/CVE-2011-1928.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/apr/patches/CVE-2011-0419.patch	Mon Aug 15 11:41:24 2011 -0700
@@ -0,0 +1,632 @@
+
+https://bugzilla.redhat.com/show_bug.cgi?id=703390
+
+http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/strings/apr_fnmatch.c?r1=731029&r2=1098902
+
+--- strings/apr_fnmatch.c.fnmatch
++++ strings/apr_fnmatch.c
[email protected]@ -1,50 +1,58 @@
+-/*
+- * Copyright (c) 1989, 1993, 1994
+- *      The Regents of the University of California.  All rights reserved.
++/* Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
+  *
+- * This code is derived from software contributed to Berkeley by
+- * Guido van Rossum.
++ * http://www.apache.org/licenses/LICENSE-2.0
+  *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- *    notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- *    notice, this list of conditions and the following disclaimer in the
+- *    documentation and/or other materials provided with the distribution.
+- * 3. All advertising materials mentioning features or use of this software
+- *    must display the following acknowledgement:
+- *      This product includes software developed by the University of
+- *      California, Berkeley and its contributors.
+- * 4. Neither the name of the University nor the names of its contributors
+- *    may be used to endorse or promote products derived from this software
+- *    without specific prior written permission.
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */ 
++
++
++/* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008
++ * as described in;
++ *   http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html
++ *
++ * Filename pattern matches defined in section 2.13, "Pattern Matching Notation"
++ * from chapter 2. "Shell Command Language"
++ *   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
++ * where; 1. A bracket expression starting with an unquoted <circumflex> '^' 
++ * character CONTINUES to specify a non-matching list; 2. an explicit <period> '.' 
++ * in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading 
++ * <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce
++ * a valid bracket expression is treated as an ordinary character; 4. a differing
++ * number of consecutive slashes within pattern and string will NOT match;
++ * 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character.
++ *
++ * Bracket expansion defined in section 9.3.5, "RE Bracket Expression",
++ * from chapter 9, "Regular Expressions"
++ *   http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05
++ * with no support for collating symbols, equivalence class expressions or 
++ * character class expressions.  A partial range expression with a leading 
++ * hyphen following a valid range expression will match only the ordinary
++ * <hyphen> and the ending character (e.g. "[a-m-z]" will match characters 
++ * 'a' through 'm', a <hyphen> '-', or a 'z').
++ *
++ * NOTE: Only POSIX/C single byte locales are correctly supported at this time.
++ * Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results,
++ * particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and
++ * nonalpha characters within a range.
+  *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
++ * XXX comments below indicate porting required for multi-byte character sets
++ * and non-POSIX locale collation orders; requires mbr* APIs to track shift
++ * state of pattern and string (rewinding pattern and string repeatedly).
++ *
++ * Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g.
++ * UTF-8, SHIFT-JIS, etc).  Any implementation allowing '\' as an alternate
++ * path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS.
+  */
+ 
+-#if defined(LIBC_SCCS) && !defined(lint)
+-static char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
+-#endif /* LIBC_SCCS and not lint */
+-
+-/*
+- * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+- * Compares a filename or pathname to a pattern.
+- */
+-#ifndef WIN32
+-#include "apr_private.h"
+-#endif
+ #include "apr_file_info.h"
+ #include "apr_fnmatch.h"
+ #include "apr_tables.h"
[email protected]@ -55,196 +63,355 @@ static char sccsid[] = "@(#)fnmatch.c	8.
+ # include <ctype.h>
+ #endif
+ 
+-#define	EOS	'\0'
+-
+-static const char *rangematch(const char *, int, int);
+ 
+-APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, const char *string, int flags)
++/* Most MBCS/collation/case issues handled here.  Wildcard '*' is not handled.
++ * EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over, 
++ * however the "\/" sequence is advanced to '/'.
++ *
++ * Both pattern and string are **char to support pointer increment of arbitrary
++ * multibyte characters for the given locale, in a later iteration of this code
++ */
++static APR_INLINE int fnmatch_ch(const char **pattern, const char **string, int flags)
+ {
+-    const char *stringstart;
+-    char c, test;
++    const char * const mismatch = *pattern;
++    const int nocase = !!(flags & APR_FNM_CASE_BLIND);
++    const int escape = !(flags & APR_FNM_NOESCAPE);
++    const int slash = !!(flags & APR_FNM_PATHNAME);
++    int result = APR_FNM_NOMATCH;
++    const char *startch;
++    int negate;
++
++    if (**pattern == '[')
++    {
++        ++*pattern;
++
++        /* Handle negation, either leading ! or ^ operators (never both) */
++        negate = ((**pattern == '!') || (**pattern == '^'));
++        if (negate)
++            ++*pattern;
++
++        while (**pattern)
++        {
++            /* ']' is an ordinary character at the start of the range pattern */
++            if ((**pattern == ']') && (*pattern > mismatch)) {
++                ++*pattern;
++                /* XXX: Fix for MBCS character width */
++                ++*string;
++                return (result ^ negate);
++            }
++
++            if (escape && (**pattern == '\\')) {
++                ++*pattern;
++
++                /* Patterns must be terminated with ']', not EOS */
++                if (!**pattern)
++                    break;
++            }
++
++            /* Patterns must be terminated with ']' not '/' */
++            if (slash && (**pattern == '/'))
++                break;
++
++            /* Look at only well-formed range patterns; ']' is allowed only if escaped,
++             * while '/' is not allowed at all in FNM_PATHNAME mode.
++             */
++            /* XXX: Fix for locale/MBCS character width */
++            if (((*pattern)[1] == '-') && (*pattern)[2] 
++                    && ((escape && ((*pattern)[2] != '\\'))
++                          ? (((*pattern)[2] != ']') && (!slash || ((*pattern)[2] != '/')))
++                          : (((*pattern)[3]) && (!slash || ((*pattern)[3] != '/'))))) {
++                startch = *pattern;
++                *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
++
++                /* XXX: handle locale/MBCS comparison, advance by MBCS char width */
++                if ((**string >= *startch) && (**string <= **pattern))
++                    result = 0;
++                else if (nocase && (isupper(**string) || isupper(*startch)
++                                                      || isupper(**pattern))
++                            && (tolower(**string) >= tolower(*startch)) 
++                            && (tolower(**string) <= tolower(**pattern)))
++                    result = 0;
++
++                ++*pattern;
++                continue;
++            }
++
++            /* XXX: handle locale/MBCS comparison, advance by MBCS char width */
++            if ((**string == **pattern))
++                result = 0;
++            else if (nocase && (isupper(**string) || isupper(**pattern))
++                            && (tolower(**string) == tolower(**pattern)))
++                result = 0;
+ 
+-    for (stringstart = string;;) {
+-	switch (c = *pattern++) {
+-	case EOS:
+-	    return (*string == EOS ? APR_SUCCESS : APR_FNM_NOMATCH);
+-	case '?':
+-	    if (*string == EOS) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    if (*string == '/' && (flags & APR_FNM_PATHNAME)) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+-		(string == stringstart ||
+-		 ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    ++string;
+-	    break;
+-	case '*':
+-	    c = *pattern;
+-	    /* Collapse multiple stars. */
+-	    while (c == '*') {
+-		c = *++pattern;
+-	    }
+-
+-	    if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+-		(string == stringstart ||
+-		 ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-
+-	    /* Optimize for pattern with * at end or before /. */
+-	    if (c == EOS) {
+-		if (flags & APR_FNM_PATHNAME) {
+-		    return (strchr(string, '/') == NULL ? APR_SUCCESS : APR_FNM_NOMATCH);
+-		}
+-		else {
+-		    return (APR_SUCCESS);
+-		}
+-	    }
+-	    else if (c == '/' && flags & APR_FNM_PATHNAME) {
+-	        if ((string = strchr(string, '/')) == NULL) {
+-		    return (APR_FNM_NOMATCH);
+-		}
+-		break;
+-	    }
+-
+-	    /* General case, use recursion. */
+-	    while ((test = *string) != EOS) {
+-	        if (!apr_fnmatch(pattern, string, flags & ~APR_FNM_PERIOD)) {
+-		    return (APR_SUCCESS);
+-		}
+-		if (test == '/' && flags & APR_FNM_PATHNAME) {
+-		    break;
+-		}
+-		++string;
+-	    }
+-	    return (APR_FNM_NOMATCH);
+-	case '[':
+-	    if (*string == EOS) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    if (*string == '/' && flags & APR_FNM_PATHNAME) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+-		(string == stringstart ||
+-		 ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+-	        return (APR_FNM_NOMATCH);
+-	    }
+-	    if ((pattern = rangematch(pattern, *string, flags)) == NULL) {
+-		return (APR_FNM_NOMATCH);
+-	    }
+-	    ++string;
+-	    break;
+-	case '\\':
+-	    if (!(flags & APR_FNM_NOESCAPE)) {
+-		if ((c = *pattern++) == EOS) {
+-		    c = '\\';
+-		    --pattern;
+-		}
+-	    }
+-	    /* FALLTHROUGH */
+-	default:
+-	    if (flags & APR_FNM_CASE_BLIND) {
+-	        if (apr_tolower(c) != apr_tolower(*string)) {
+-		    return (APR_FNM_NOMATCH);
+-		}
+-	    }
+-	    else if (c != *string) {
+-	        return (APR_FNM_NOMATCH);
+-	    }
+-	    string++;
+-	    break;
+-	}
+-    /* NOTREACHED */
++            ++*pattern;
++        }
++
++        /* NOT a properly balanced [expr] pattern; Rewind to test '[' literal */
++        *pattern = mismatch;
++        result = APR_FNM_NOMATCH;
++    }
++    else if (**pattern == '?') {
++        /* Optimize '?' match before unescaping **pattern */
++        if (!**string || (slash && (**string == '/')))
++            return APR_FNM_NOMATCH;
++        result = 0;
++        goto fnmatch_ch_success;
+     }
++    else if (escape && (**pattern == '\\') && (*pattern)[1]) {
++        ++*pattern;
++    }
++
++    /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */
++    if (**string == **pattern)
++        result = 0;
++    else if (nocase && (isupper(**string) || isupper(**pattern))
++                    && (tolower(**string) == tolower(**pattern)))
++        result = 0;
++
++    /* Refuse to advance over trailing slash or nulls
++     */
++    if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/'))))
++        return result;
++
++fnmatch_ch_success:
++    ++*pattern;
++    ++*string;
++    return result;
+ }
+ 
+-static const char *rangematch(const char *pattern, int test, int flags)
+-{
+-    int negate, ok;
+-    char c, c2;
+ 
+-    /*
+-     * 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 ([email protected])
++APR_DECLARE(int) apr_fnmatch(const char *pattern, const char *string, int flags)
++{
++    static const char dummystring[2] = {' ', 0};
++    const int escape = !(flags & APR_FNM_NOESCAPE);
++    const int slash = !!(flags & APR_FNM_PATHNAME);
++    const char *strendseg;
++    const char *dummyptr;
++    const char *matchptr;
++    int wild;
++    /* For '*' wild processing only; surpress 'used before initialization'
++     * warnings with dummy initialization values;
+      */
+-    if ((negate = (*pattern == '!' || *pattern == '^'))) {
+-	++pattern;
+-    }
++    const char *strstartseg = NULL;
++    const char *mismatch = NULL;
++    int matchlen = 0;
++
++    while (*pattern)
++    {
++        /* Match balanced slashes, starting a new segment pattern
++         */
++        if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
++            ++pattern;
++        if (slash && (*pattern == '/') && (*string == '/')) {
++            ++pattern;
++            ++string;
++        }            
++
++        /* At the beginning of each segment, validate leading period behavior.
++         */
++        if ((flags & APR_FNM_PERIOD) && (*string == '.'))
++        {
++            if (*pattern == '.')
++                ++pattern;
++            else if (escape && (*pattern == '\\') && (pattern[1] == '.'))
++                pattern += 2;
++            else
++                return APR_FNM_NOMATCH;
++            ++string;
++        }
++
++        /* Determine the end of string segment
++         *
++         * Presumes '/' character is unique, not composite in any MBCS encoding
++         */
++        if (slash) {
++            strendseg = strchr(string, '/');
++            if (!strendseg)
++                strendseg = strchr(string, '\0');
++        }
++        else {
++            strendseg = strchr(string, '\0');
++        }
++
++        /* Allow pattern '*' to be consumed even with no remaining string to match
++         */
++        while (*pattern && !(slash && ((*pattern == '/')
++                                       || (escape && (*pattern == '\\')
++                                                  && (pattern[1] == '/'))))
++                        && ((string < strendseg)
++                            || ((*pattern == '*') && (string == strendseg))))
++        {
++            /* Reduce groups of '*' and '?' to n '?' matches
++             * followed by one '*' test for simplicity
++             */
++            for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern)
++            {
++                if (*pattern == '*') {
++                    wild = 1;
++                }
++                else if (string < strendseg) {  /* && (*pattern == '?') */
++                    /* XXX: Advance 1 char for MBCS locale */
++                    ++string;
++                }
++                else {  /* (string >= strendseg) && (*pattern == '?') */
++                    return APR_FNM_NOMATCH;
++                }
++            }
++
++            if (wild)
++            {
++                strstartseg = string;
++                mismatch = pattern;
++
++                /* Count fixed (non '*') char matches remaining in pattern
++                 * excluding '/' (or "\/") and '*'
++                 */
++                for (matchptr = pattern, matchlen = 0; 1; ++matchlen)
++                {
++                    if ((*matchptr == '\0') 
++                        || (slash && ((*matchptr == '/')
++                                      || (escape && (*matchptr == '\\')
++                                                 && (matchptr[1] == '/')))))
++                    {
++                        /* Compare precisely this many trailing string chars,
++                         * the resulting match needs no wildcard loop
++                         */
++                        /* XXX: Adjust for MBCS */
++                        if (string + matchlen > strendseg)
++                            return APR_FNM_NOMATCH;
++
++                        string = strendseg - matchlen;
++                        wild = 0;
++                        break;
++                    }
++
++                    if (*matchptr == '*')
++                    {
++                        /* Ensure at least this many trailing string chars remain
++                         * for the first comparison
++                         */
++                        /* XXX: Adjust for MBCS */
++                        if (string + matchlen > strendseg)
++                            return APR_FNM_NOMATCH;
++
++                        /* Begin first wild comparison at the current position */
++                        break;
++                    }
++
++                    /* Skip forward in pattern by a single character match
++                     * Use a dummy fnmatch_ch() test to count one "[range]" escape
++                     */ 
++                    /* XXX: Adjust for MBCS */
++                    if (escape && (*matchptr == '\\') && matchptr[1]) {
++                        matchptr += 2;
++                    }
++                    else if (*matchptr == '[') {
++                        dummyptr = dummystring;
++                        fnmatch_ch(&matchptr, &dummyptr, flags);
++                    }
++                    else {
++                        ++matchptr;
++                    }
++                }
++            }
++
++            /* Incrementally match string against the pattern
++             */
++            while (*pattern && (string < strendseg))
++            {
++                /* Success; begin a new wild pattern search
++                 */
++                if (*pattern == '*')
++                    break;
++
++                if (slash && ((*string == '/') || (*pattern == '/')
++                                               || (escape && (*pattern == '\\')
++                                                   && (pattern[1] == '/'))))
++                    break;
++
++                /* Compare ch's (the pattern is advanced over "\/" to the '/',
++                 * but slashes will mismatch, and are not consumed)
++                 */
++                if (!fnmatch_ch(&pattern, &string, flags))
++                    continue;
++
++                /* Failed to match, loop against next char offset of string segment 
++                 * until not enough string chars remain to match the fixed pattern
++                 */
++                if (wild) {
++                    /* XXX: Advance 1 char for MBCS locale */
++                    string = ++strstartseg;
++                    if (string + matchlen > strendseg)
++                        return APR_FNM_NOMATCH;
++
++                    pattern = mismatch;
++                    continue;
++                }
++                else
++                    return APR_FNM_NOMATCH;
++            }
++        }
++
++        if (*string && (!slash || (*string != '/')))
++            return APR_FNM_NOMATCH;
+ 
+-    for (ok = 0; (c = *pattern++) != ']';) {
+-        if (c == '\\' && !(flags & APR_FNM_NOESCAPE)) {
+-	    c = *pattern++;
+-	}
+-	if (c == EOS) {
+-	    return (NULL);
+-	}
+-	if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
+-	    pattern += 2;
+-	    if (c2 == '\\' && !(flags & APR_FNM_NOESCAPE)) {
+-		c2 = *pattern++;
+-	    }
+-	    if (c2 == EOS) {
+-		return (NULL);
+-	    }
+-	    if ((c <= test && test <= c2)
+-		|| ((flags & APR_FNM_CASE_BLIND)
+-		    && ((apr_tolower(c) <= apr_tolower(test))
+-			&& (apr_tolower(test) <= apr_tolower(c2))))) {
+-		ok = 1;
+-	    }
+-	}
+-	else if ((c == test)
+-		 || ((flags & APR_FNM_CASE_BLIND)
+-		     && (apr_tolower(c) == apr_tolower(test)))) {
+-	    ok = 1;
+-	}
++        if (*pattern && (!slash || ((*pattern != '/')
++                                    && (!escape || (*pattern != '\\')
++                                                || (pattern[1] != '/')))))
++            return APR_FNM_NOMATCH;
+     }
+-    return (ok == negate ? NULL : pattern);
++
++    /* pattern is at EOS; if string is also, declare success
++     */
++    if (!*string)
++        return 0;
++
++    /* pattern didn't match to the end of string */
++    return APR_FNM_NOMATCH;
+ }
+ 
+ 
+-/* This function is an Apache addition */
+-/* return non-zero if pattern has any glob chars in it */
++/* This function is an Apache addition
++ * return non-zero if pattern has any glob chars in it
++ * @bug Function does not distinguish for FNM_PATHNAME mode, which renders
++ * a false positive for test[/]this (which is not a range, but 
++ * seperate test[ and ]this segments and no glob.)
++ * @bug Function does not distinguish for non-FNM_ESCAPE mode.
++ * @bug Function does not parse []] correctly
++ * Solution may be to use fnmatch_ch() to walk the patterns?
++ */
+ APR_DECLARE(int) apr_fnmatch_test(const char *pattern)
+ {
+     int nesting;
+ 
+     nesting = 0;
+     while (*pattern) {
+-	switch (*pattern) {
+-	case '?':
+-	case '*':
+-	    return 1;
+-
+-	case '\\':
+-	    if (*++pattern == '\0') {
+-		return 0;
+-	    }
+-	    break;
+-
+-	case '[':	/* '[' is only a glob if it has a matching ']' */
+-	    ++nesting;
+-	    break;
+-
+-	case ']':
+-	    if (nesting) {
+-		return 1;
+-	    }
+-	    break;
+-	}
+-	++pattern;
+-    }
++        switch (*pattern) {
++        case '?':
++        case '*':
++            return 1;
++
++        case '\\':
++            if (*++pattern == '\0') {
++                return 0;
++            }
++            break;
++
++        case '[':         /* '[' is only a glob if it has a matching ']' */
++            ++nesting;
++            break;
++
++        case ']':
++            if (nesting) {
++                return 1;
++            }
++            break;
++        }
++        ++pattern;    }
+     return 0;
+ }
+ 
++
+ /* Find all files matching the specified pattern */
+ APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern, 
+                                          apr_array_header_t **result,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/apr/patches/CVE-2011-1928.patch	Mon Aug 15 11:41:24 2011 -0700
@@ -0,0 +1,153 @@
+
+Fix regressions in fnmatch rewrite.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=706203
+
+http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/strings/apr_fnmatch.c?r1=1098902&r2=1124999
+
+--- strings/apr_fnmatch.c.fnmatch
++++ strings/apr_fnmatch.c
[email protected]@ -90,10 +90,13 @@ static APR_INLINE int fnmatch_ch(const c
+         if (negate)
+             ++*pattern;
+ 
++        /* ']' is an ordinary character at the start of the range pattern */
++        if (**pattern == ']')
++            goto leadingclosebrace;
++
+         while (**pattern)
+         {
+-            /* ']' is an ordinary character at the start of the range pattern */
+-            if ((**pattern == ']') && (*pattern > mismatch)) {
++            if (**pattern == ']') {
+                 ++*pattern;
+                 /* XXX: Fix for MBCS character width */
+                 ++*string;
[email protected]@ -112,17 +115,23 @@ static APR_INLINE int fnmatch_ch(const c
+             if (slash && (**pattern == '/'))
+                 break;
+ 
+-            /* Look at only well-formed range patterns; ']' is allowed only if escaped,
+-             * while '/' is not allowed at all in FNM_PATHNAME mode.
++leadingclosebrace:
++            /* Look at only well-formed range patterns; 
++             * "x-]" is not allowed unless escaped ("x-\]")
++             * XXX: Fix for locale/MBCS character width
+              */
+-            /* XXX: Fix for locale/MBCS character width */
+-            if (((*pattern)[1] == '-') && (*pattern)[2] 
+-                    && ((escape && ((*pattern)[2] != '\\'))
+-                          ? (((*pattern)[2] != ']') && (!slash || ((*pattern)[2] != '/')))
+-                          : (((*pattern)[3]) && (!slash || ((*pattern)[3] != '/'))))) {
++            if (((*pattern)[1] == '-') && ((*pattern)[2] != ']'))
++            {
+                 startch = *pattern;
+                 *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
+ 
++                /* NOT a properly balanced [expr] pattern, EOS terminated 
++                 * or ranges containing a slash in FNM_PATHNAME mode pattern
++                 * fall out to to the rewind and test '[' literal code path
++                 */
++                if (!**pattern || (slash && (**pattern == '/')))
++                    break;
++
+                 /* XXX: handle locale/MBCS comparison, advance by MBCS char width */
+                 if ((**string >= *startch) && (**string <= **pattern))
+                     result = 0;
[email protected]@ -146,7 +155,9 @@ static APR_INLINE int fnmatch_ch(const c
+             ++*pattern;
+         }
+ 
+-        /* NOT a properly balanced [expr] pattern; Rewind to test '[' literal */
++        /* NOT a properly balanced [expr] pattern; Rewind
++         * and reset result to test '[' literal
++         */
+         *pattern = mismatch;
+         result = APR_FNM_NOMATCH;
+     }
[email protected]@ -196,9 +207,13 @@ APR_DECLARE(int) apr_fnmatch(const char 
+     const char *mismatch = NULL;
+     int matchlen = 0;
+ 
+-    while (*pattern)
++    if (*pattern == '*')
++        goto firstsegment;
++
++    while (*pattern && *string)
+     {
+-        /* Match balanced slashes, starting a new segment pattern
++        /* Pre-decode "\/" which has no special significance, and
++         * match balanced slashes, starting a new segment pattern
+          */
+         if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
+             ++pattern;
[email protected]@ -207,6 +222,7 @@ APR_DECLARE(int) apr_fnmatch(const char 
+             ++string;
+         }            
+ 
++firstsegment:
+         /* At the beginning of each segment, validate leading period behavior.
+          */
+         if ((flags & APR_FNM_PERIOD) && (*string == '.'))
[email protected]@ -235,12 +251,17 @@ APR_DECLARE(int) apr_fnmatch(const char 
+ 
+         /* Allow pattern '*' to be consumed even with no remaining string to match
+          */
+-        while (*pattern && !(slash && ((*pattern == '/')
+-                                       || (escape && (*pattern == '\\')
+-                                                  && (pattern[1] == '/'))))
+-                        && ((string < strendseg)
+-                            || ((*pattern == '*') && (string == strendseg))))
++        while (*pattern)
+         {
++            if ((string > strendseg)
++                || ((string == strendseg) && (*pattern != '*')))
++                break;
++
++            if (slash && ((*pattern == '/')
++                           || (escape && (*pattern == '\\')
++                                      && (pattern[1] == '/'))))
++                break;
++
+             /* Reduce groups of '*' and '?' to n '?' matches
+              * followed by one '*' test for simplicity
+              */
[email protected]@ -324,9 +345,10 @@ APR_DECLARE(int) apr_fnmatch(const char 
+                 if (*pattern == '*')
+                     break;
+ 
+-                if (slash && ((*string == '/') || (*pattern == '/')
+-                                               || (escape && (*pattern == '\\')
+-                                                   && (pattern[1] == '/'))))
++                if (slash && ((*string == '/')
++                              || (*pattern == '/')
++                              || (escape && (*pattern == '\\')
++                                         && (pattern[1] == '/'))))
+                     break;
+ 
+                 /* Compare ch's (the pattern is advanced over "\/" to the '/',
[email protected]@ -352,18 +374,18 @@ APR_DECLARE(int) apr_fnmatch(const char 
+             }
+         }
+ 
+-        if (*string && (!slash || (*string != '/')))
++        if (*string && !(slash && (*string == '/')))
+             return APR_FNM_NOMATCH;
+ 
+-        if (*pattern && (!slash || ((*pattern != '/')
+-                                    && (!escape || (*pattern != '\\')
+-                                                || (pattern[1] != '/')))))
++        if (*pattern && !(slash && ((*pattern == '/')
++                                    || (escape && (*pattern == '\\')
++                                               && (pattern[1] == '/')))))
+             return APR_FNM_NOMATCH;
+     }
+ 
+-    /* pattern is at EOS; if string is also, declare success
++    /* Where both pattern and string are at EOS, declare success
+      */
+-    if (!*string)
++    if (!*string && !*pattern)
+         return 0;
+ 
+     /* pattern didn't match to the end of string */