From: Jeff Trawick Date: Wed, 15 Apr 2015 16:56:22 +0000 (+0000) Subject: Merge r1632742, r1634836 from trunk: X-Git-Tag: 2.4.13~230 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7db699707692409b0b478bb4fb30861e8a427bd;p=thirdparty%2Fapache%2Fhttpd.git Merge r1632742, r1634836 from trunk: mod_buffer: Forward flushed input data immediately and avoid (unlikely) access to freed memory. Submitted by: ylavic, jailletc36 Reviewed by: covener, rjung git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1673871 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 2c7bb58b435..48dec809fd0 100644 --- a/CHANGES +++ b/CHANGES @@ -141,6 +141,9 @@ Changes with Apache 2.4.11 request headers earlier. Adds "MergeTrailers" directive to restore legacy behavior. [Edward Lu, Yann Ylavic, Joe Orton, Eric Covener] + *) mod_buffer: Forward flushed input data immediately and avoid (unlikely) + access to freed memory. [Yann Ylavic, Christophe Jaillet] + *) core: Add CGIPassAuth directive to control whether HTTP authorization headers are passed to scripts as CGI variables. PR 56855. [Jeff Trawick] diff --git a/STATUS b/STATUS index cab8902ed4c..53716266d9b 100644 --- a/STATUS +++ b/STATUS @@ -105,13 +105,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_buffer: Forward flushed input data immediately and avoid (unlikely) - access to freed memory. - trunk patch: http://svn.apache.org/r1632742 - http://svn.apache.org/r1634836 (CHANGES entry) - 2.4.x patches: trunk works (modulo CHANGES). - +1: ylavic, covener, rjung - *) mod_proxy_http: Use the "Connection: close" header for requests to backends not recycling connections (disablereuse), including the default reverse and forward proxies. diff --git a/modules/filters/mod_buffer.c b/modules/filters/mod_buffer.c index cf552aa7845..8140af5d454 100644 --- a/modules/filters/mod_buffer.c +++ b/modules/filters/mod_buffer.c @@ -213,28 +213,33 @@ static apr_status_t buffer_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, /* if our buffer is empty, read off the network until the buffer is full */ if (APR_BRIGADE_EMPTY(ctx->bb)) { + int seen_flush = 0; + ctx->remaining = ctx->conf->size; - while (!ctx->seen_eos && ctx->remaining > 0) { + while (!ctx->seen_eos && !seen_flush && ctx->remaining > 0) { const char *data; apr_size_t size = 0; - rv = ap_get_brigade(f->next, ctx->tmp, mode, block, ctx->remaining); - - /* if an error was received, bail out now. If the error is - * EAGAIN and we have not yet seen an EOS, we will definitely - * be called again, at which point we will send our buffered - * data. Instead of sending EAGAIN, some filters return an - * empty brigade instead when data is not yet available. In - * this case, pass through the APR_SUCCESS and emulate the - * underlying filter. - */ - if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(ctx->tmp)) { - return rv; + if (APR_BRIGADE_EMPTY(ctx->tmp)) { + rv = ap_get_brigade(f->next, ctx->tmp, mode, block, + ctx->remaining); + + /* if an error was received, bail out now. If the error is + * EAGAIN and we have not yet seen an EOS, we will definitely + * be called again, at which point we will send our buffered + * data. Instead of sending EAGAIN, some filters return an + * empty brigade instead when data is not yet available. In + * this case, pass through the APR_SUCCESS and emulate the + * underlying filter. + */ + if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(ctx->tmp)) { + return rv; + } } - for (e = APR_BRIGADE_FIRST(ctx->tmp); e != APR_BRIGADE_SENTINEL( - ctx->tmp); e = APR_BUCKET_NEXT(e)) { + do { + e = APR_BRIGADE_FIRST(ctx->tmp); /* if we see an EOS, we are done */ if (APR_BUCKET_IS_EOS(e)) { @@ -248,6 +253,7 @@ static apr_status_t buffer_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, if (APR_BUCKET_IS_FLUSH(e)) { APR_BUCKET_REMOVE(e); APR_BRIGADE_INSERT_TAIL(ctx->bb, e); + seen_flush = 1; break; } @@ -260,7 +266,7 @@ static apr_status_t buffer_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, /* read the bucket in, pack it into the buffer */ if (APR_SUCCESS == (rv = apr_bucket_read(e, &data, &size, - APR_BLOCK_READ))) { + APR_BLOCK_READ))) { apr_brigade_write(ctx->bb, NULL, NULL, data, size); ctx->remaining -= size; apr_bucket_delete(e); @@ -268,7 +274,7 @@ static apr_status_t buffer_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, return rv; } - } + } while (!APR_BRIGADE_EMPTY(ctx->tmp)); } }