Commit c9686885 authored by Eric Covener's avatar Eric Covener
Browse files

* 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
parent 2e2de7ea
Loading
Loading
Loading
Loading
+0 −20
Original line number Diff line number Diff line
@@ -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 ]

+3 −2
Original line number Diff line number Diff line
@@ -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
+20 −0
Original line number Diff line number Diff line
@@ -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.
+7 −0
Original line number Diff line number Diff line
@@ -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,
+55 −20
Original line number Diff line number Diff line
@@ -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;

    if (!source)
        return NULL;
    if (!nmatch)
        return apr_pstrdup(p, src);
    apr_size_t no;
    apr_size_t len = 0;

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

/*