]> granicus.if.org Git - apache/commitdiff
Merge r1632742, r1634836 from trunk:
authorJeff Trawick <trawick@apache.org>
Wed, 15 Apr 2015 16:56:22 +0000 (16:56 +0000)
committerJeff Trawick <trawick@apache.org>
Wed, 15 Apr 2015 16:56:22 +0000 (16:56 +0000)
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

CHANGES
STATUS
modules/filters/mod_buffer.c

diff --git a/CHANGES b/CHANGES
index 2c7bb58b4358255ec90cf74c54d80604ef67f5fc..48dec809fd0b54ff8adc0d30a0b13604f83b7a8c 100644 (file)
--- 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 cab8902ed4c38c616e1b80cc187c28dcc9edd875..53716266d9ba60989ef653d63f881502a225bfcb 100644 (file)
--- 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.
index cf552aa78459d02a68f365412cd6e8c7201d5a85..8140af5d454b418edf78509592cc0bacf55737d5 100644 (file)
@@ -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));
         }
     }