From: Eric Covener Date: Thu, 27 Jun 2013 16:29:37 +0000 (+0000) Subject: * core: Limit ap_pregsub() to 64MB, add ap_pregsub_ex() for longer strings. X-Git-Tag: 2.2.25~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76a6802321b6035e974fa0a60c696b847ffc0299;p=thirdparty%2Fapache%2Fhttpd.git * core: Limit ap_pregsub() to 64MB, add ap_pregsub_ex() for longer strings. The default limit can be adjusted at compile time using AP_PREGSUB_MAXLEN. mod_setenvif: Log error on substitution overflow. Submitted by: trawick Reviewed by: trawic, wrowe, covener git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1497429 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/STATUS b/STATUS index b4c7a18483b..5198c16dacf 100644 --- a/STATUS +++ b/STATUS @@ -141,26 +141,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: 2.2.x patch: trunk patch works modulo CHANGES +1: trawick, wrowe, rjung - * core: Limit ap_pregsub() to 64MB, add ap_pregsub_ex() for longer strings. - The default limit can be adjusted at compile time using AP_PREGSUB_MAXLEN. - mod_setenvif: Log error on substitution overflow. - - IMPORTANT: This could break existing configurations which rely on - substitutions > 64MB. Those sites need to rebuild with an - override of AP_PREGSUB_MAXLEN. - 2.4.x has a much smaller limit on ap_pregsub() because that change - was introduced with the new release. - - trunk patch: - util.c: too many to list, as it is tied up in other added features and follow- - up fixes; I started with 2.4.x HEAD and backed out some semantic changes - in the code of interest - mod_setenvif.c: http://svn.apache.org/viewvc?view=revision&revision=1198966 - 2.2.x patch: http://people.apache.org/~trawick/ap_pregsub_ex_22x-2.txt - +1: trawick, wrowe, covener - - - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 1b2cfa02a62..4a48c3e0dbb 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -149,7 +149,8 @@ * 20051115.29 (2.2.21) add max_ranges to core_dir_config * 20051115.30 (2.2.21) add ap_set_accept_ranges() * 20051115.31 (2.2.23) Add forcerecovery to proxy_balancer_shared struct - # 20051115.32 (2.2.24) Add ap_get_exec_line + * 20051115.32 (2.2.24) Add ap_get_exec_line + * 20051115.33 (2.2.24) Add ap_pregsub_ex() */ #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */ @@ -157,7 +158,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20051115 #endif -#define MODULE_MAGIC_NUMBER_MINOR 32 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 33 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index 5bf2cfe7135..f353d9ff7ba 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1700,6 +1700,26 @@ AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg); AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source, size_t nmatch, ap_regmatch_t pmatch[]); +/** + * After performing a successful regex match, you may use this function to + * perform a series of string substitutions based on subexpressions that were + * matched during the call to ap_regexec + * @param p The pool to allocate from + * @param result where to store the result, will be set to NULL on error + * @param input An arbitrary string containing $1 through $9. These are + * replaced with the corresponding matched sub-expressions + * @param source The string that was originally matched to the regex + * @param nmatch the nmatch returned from ap_pregex + * @param pmatch the pmatch array returned from ap_pregex + * @param maxlen the maximum string length to return, 0 for unlimited + * @return APR_SUCCESS if successful, APR_ENOMEM or other error code otherwise. + */ +AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result, + const char *input, const char *source, + apr_size_t nmatch, + ap_regmatch_t pmatch[], + apr_size_t maxlen); + /** * We want to downcase the type/subtype for comparison purposes * but nothing else because ;parameter=foo values are case sensitive. diff --git a/modules/metadata/mod_setenvif.c b/modules/metadata/mod_setenvif.c index 2c84cedefc9..6848c9ae7c5 100644 --- a/modules/metadata/mod_setenvif.c +++ b/modules/metadata/mod_setenvif.c @@ -555,6 +555,13 @@ static int match_headers(request_rec *r) apr_table_setn(r->subprocess_env, elts[j].key, replaced); } + else { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, + "Regular expression replacement " + "failed for '%s', value too long?", + elts[j].key); + return HTTP_INTERNAL_SERVER_ERROR; + } } else { apr_table_setn(r->subprocess_env, elts[j].key, diff --git a/server/util.c b/server/util.c index b334c964537..f1fb2550f15 100644 --- a/server/util.c +++ b/server/util.c @@ -360,34 +360,38 @@ AP_DECLARE(const char *) ap_stripprefix(const char *bigstring, * AT&T V8 regexp package. */ -AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, - const char *source, size_t nmatch, - ap_regmatch_t pmatch[]) +static apr_status_t regsub_core(apr_pool_t *p, char **result, + const char *input, + const char *source, apr_size_t nmatch, + ap_regmatch_t pmatch[], apr_size_t maxlen) { const char *src = input; - char *dest, *dst; + char *dst; char c; - size_t no; - apr_size_t len; + apr_size_t no; + apr_size_t len = 0; - if (!source) - return NULL; - if (!nmatch) - return apr_pstrdup(p, src); + AP_DEBUG_ASSERT(result && p); + if (!source || nmatch>AP_MAX_REG_MATCH) + return APR_EINVAL; + if (!nmatch) { + len = strlen(src); + if (maxlen > 0 && len >= maxlen) + return APR_ENOMEM; + *result = apr_pstrmemdup(p, src, len); + return APR_SUCCESS; + } /* First pass, find the size */ - - len = 0; - while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && apr_isdigit(*src)) no = *src++ - '0'; else - no = 10; + no = AP_MAX_REG_MATCH; - if (no > 9) { /* Ordinary character. */ + if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) src++; len++; @@ -396,14 +400,17 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, if (UTIL_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "integer overflow or out of memory condition." ); - return NULL; + return APR_ENOMEM; } len += pmatch[no].rm_eo - pmatch[no].rm_so; } } - dest = dst = apr_pcalloc(p, len + 1); + if (len >= maxlen && maxlen > 0) + return APR_ENOMEM; + + *result = dst = apr_palloc(p, len + 1); /* Now actually fill in the string */ @@ -415,9 +422,9 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, else if (c == '$' && apr_isdigit(*src)) no = *src++ - '0'; else - no = 10; + no = AP_MAX_REG_MATCH; - if (no > 9) { /* Ordinary character. */ + if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; *dst++ = c; @@ -431,7 +438,35 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, } *dst = '\0'; - return dest; + return APR_SUCCESS; +} + +#ifndef AP_PREGSUB_MAXLEN +/* No API control so far in this released branch, so make it large */ +#define AP_PREGSUB_MAXLEN (64 * 1024 * 1024) +#endif +AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, + const char *source, size_t nmatch, + ap_regmatch_t pmatch[]) +{ + char *result; + apr_status_t rc = regsub_core(p, &result, input, source, nmatch, + pmatch, AP_PREGSUB_MAXLEN); + if (rc != APR_SUCCESS) + result = NULL; + return result; +} + +AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result, + const char *input, const char *source, + apr_size_t nmatch, ap_regmatch_t pmatch[], + apr_size_t maxlen) +{ + apr_status_t rc = regsub_core(p, result, input, source, nmatch, + pmatch, maxlen); + if (rc != APR_SUCCESS) + *result = NULL; + return rc; } /*