[apache2] 04/05: Add more fixes for CVE-2015-3183 patch from upstream

Stefan Fritsch sf at moszumanska.debian.org
Sat Aug 1 21:11:48 UTC 2015


This is an automated email from the git hooks/post-receive script.

sf pushed a commit to branch jessie
in repository apache2.

commit b4a381aa5d92f6cd84a3940219a9f86ea6aff32c
Author: Stefan Fritsch <sf at sfritsch.de>
Date:   Sat Aug 1 22:38:33 2015 +0200

    Add more fixes for CVE-2015-3183 patch from upstream
---
 .../CVE-2015-3183-chunk-header-parsing.diff        | 179 +++++++++++----------
 1 file changed, 98 insertions(+), 81 deletions(-)

diff --git a/debian/patches/CVE-2015-3183-chunk-header-parsing.diff b/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
index 238e650..2089c15 100644
--- a/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
+++ b/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
@@ -2,9 +2,11 @@
 # https://svn.apache.org/r1685904
 # https://svn.apache.org/r1685950
 # https://svn.apache.org/r1686271
+# https://svn.apache.org/r1688935
+# https://svn.apache.org/r1689821
 --- apache2.orig/modules/http/http_filters.c
 +++ apache2/modules/http/http_filters.c
-@@ -57,24 +57,28 @@
+@@ -57,24 +57,29 @@
  
  APLOG_USE_MODULE(http);
  
@@ -24,6 +26,7 @@
 -        BODY_CHUNK,
 -        BODY_CHUNK_PART
 +    apr_int32_t chunk_used;
++    apr_int32_t chunk_bws;
 +    apr_int32_t chunkbits;
 +    enum
 +    {
@@ -47,7 +50,7 @@
      apr_bucket_brigade *bb;
  } http_ctx_t;
  
-@@ -119,117 +123,148 @@ static apr_status_t bail_out_on_error(ht
+@@ -119,117 +124,154 @@ static apr_status_t bail_out_on_error(ht
      return ap_pass_brigade(f->r->output_filters, bb);
  }
  
@@ -143,6 +146,7 @@
 +            ctx->remaining = 0;
 +            ctx->chunkbits = sizeof(apr_off_t) * 8;
 +            ctx->chunk_used = 0;
++            ctx->chunk_bws = 0;
          }
 -        if (len > 0) {
 -            break;  /* we got the data we want */
@@ -190,7 +194,12 @@
 +            }
 +        }
 +        else if (c == ' ' || c == '\t') {
++            /* Be lenient up to 10 BWS (term from rfc7230 - 3.2.3).
++             */
 +            ctx->state = BODY_CHUNK_CR;
++            if (++ctx->chunk_bws > 10) {
++                return APR_EINVAL;
++            }
 +        }
 +        else if (ctx->state == BODY_CHUNK_CR) {
 +            /*
@@ -295,7 +304,7 @@
  
  static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f,
                                            apr_bucket_brigade *b, int merge)
-@@ -243,7 +278,6 @@ static apr_status_t read_chunked_trailer
+@@ -243,7 +285,6 @@ static apr_status_t read_chunked_trailer
      r->status = HTTP_OK;
      r->headers_in = r->trailers_in;
      apr_table_clear(r->headers_in);
@@ -303,15 +312,18 @@
      ap_get_mime_headers(r);
  
      if(r->status == HTTP_OK) {
-@@ -290,6 +324,7 @@ apr_status_t ap_http_filter(ap_filter_t
-     apr_off_t totalread;
+@@ -287,9 +328,9 @@ apr_status_t ap_http_filter(ap_filter_t
+     apr_bucket *e;
+     http_ctx_t *ctx = f->ctx;
+     apr_status_t rv;
+-    apr_off_t totalread;
      int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;
      apr_bucket_brigade *bb;
 +    int again;
  
      conf = (core_server_config *)
          ap_get_module_config(f->r->server->module_config, &core_module);
-@@ -303,7 +338,6 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -303,7 +344,6 @@ apr_status_t ap_http_filter(ap_filter_t
          const char *tenc, *lenp;
          f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
          ctx->state = BODY_NONE;
@@ -319,7 +331,7 @@
          ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
          bb = ctx->bb;
  
-@@ -335,14 +369,17 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -335,14 +375,17 @@ apr_status_t ap_http_filter(ap_filter_t
                   * reading the connection until it is closed by the server."
                   */
                  ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02555)
@@ -340,7 +352,7 @@
              }
              lenp = NULL;
          }
-@@ -361,7 +398,7 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -361,7 +404,7 @@ apr_status_t ap_http_filter(ap_filter_t
                  ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587)
                                "Invalid Content-Length");
  
@@ -349,7 +361,7 @@
              }
  
              /* If we have a limit in effect and we know the C-L ahead of
-@@ -403,7 +440,8 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -403,7 +446,8 @@ apr_status_t ap_http_filter(ap_filter_t
              if (!ap_is_HTTP_SUCCESS(f->r->status)) {
                  ctx->state = BODY_NONE;
                  ctx->eos_sent = 1;
@@ -359,7 +371,7 @@
                  char *tmp;
                  int len;
  
-@@ -426,285 +464,194 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -426,285 +470,199 @@ apr_status_t ap_http_filter(ap_filter_t
                  ap_pass_brigade(f->c->output_filters, bb);
              }
          }
@@ -374,9 +386,7 @@
 +        APR_BRIGADE_INSERT_TAIL(b, e);
 +        return APR_SUCCESS;
 +    }
- 
--            rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
--                                block, 0);
++
 +    do {
 +        apr_brigade_cleanup(b);
 +        again = 0; /* until further notice */
@@ -386,10 +396,13 @@
 +        case BODY_CHUNK:
 +        case BODY_CHUNK_PART:
 +        case BODY_CHUNK_EXT:
++        case BODY_CHUNK_CR:
 +        case BODY_CHUNK_LF:
 +        case BODY_CHUNK_END:
 +        case BODY_CHUNK_END_LF: {
-+
+ 
+-            rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
+-                                block, 0);
 +            rv = ap_get_brigade(f->next, b, AP_MODE_GETLINE, block, 0);
  
              /* for timeout */
@@ -590,9 +603,22 @@
 +                readbytes = ctx->remaining;
 +            }
 +            if (readbytes > 0) {
++                apr_off_t totalread;
++
++                rv = ap_get_brigade(f->next, b, mode, block, readbytes);
++
++                /* for timeout */
++                if (block == APR_NONBLOCK_READ
++                        && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b))
++                                || (APR_STATUS_IS_EAGAIN(rv)))) {
++                    return APR_EAGAIN;
++                }
  
 -    rv = ap_get_brigade(f->next, b, mode, block, readbytes);
-+                rv = ap_get_brigade(f->next, b, mode, block, readbytes);
++                if (rv == APR_EOF && ctx->state != BODY_NONE
++                        && ctx->remaining > 0) {
++                    return APR_INCOMPLETE;
++                }
  
 -    if (rv == APR_EOF && ctx->state != BODY_NONE &&
 -            ctx->remaining > 0) {
@@ -601,19 +627,14 @@
 -    if (rv != APR_SUCCESS) {
 -        return rv;
 -    }
-+                /* for timeout */
-+                if (block == APR_NONBLOCK_READ
-+                        && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b))
-+                                || (APR_STATUS_IS_EAGAIN(rv)))) {
-+                    return APR_EAGAIN;
++                if (rv != APR_SUCCESS) {
++                    return rv;
 +                }
  
 -    /* How many bytes did we just read? */
 -    apr_brigade_length(b, 0, &totalread);
-+                if (rv == APR_EOF && ctx->state != BODY_NONE
-+                        && ctx->remaining > 0) {
-+                    return APR_INCOMPLETE;
-+                }
++                /* How many bytes did we just read? */
++                apr_brigade_length(b, 0, &totalread);
  
 -    /* If this happens, we have a bucket of unknown length.  Die because
 -     * it means our assumptions have changed. */
@@ -626,12 +647,47 @@
 -            if (APR_BUCKET_IS_EOS(e)) {
 -                apr_bucket_delete(e);
 -                return APR_INCOMPLETE;
--            }
++                /* If this happens, we have a bucket of unknown length.  Die because
++                 * it means our assumptions have changed. */
++                AP_DEBUG_ASSERT(totalread >= 0);
++
++                if (ctx->state != BODY_NONE) {
++                    ctx->remaining -= totalread;
++                    if (ctx->remaining > 0) {
++                        e = APR_BRIGADE_LAST(b);
++                        if (APR_BUCKET_IS_EOS(e)) {
++                            apr_bucket_delete(e);
++                            return APR_INCOMPLETE;
++                        }
++                    }
++                    else if (ctx->state == BODY_CHUNK_DATA) {
++                        /* next chunk please */
++                        ctx->state = BODY_CHUNK_END;
++                        ctx->chunk_used = 0;
++                    }
++                }
++
++                /* We have a limit in effect. */
++                if (ctx->limit) {
++                    /* FIXME: Note that we might get slightly confused on
++                     * chunked inputs as we'd need to compensate for the chunk
++                     * lengths which may not really count.  This seems to be up
++                     * for interpretation.
++                     */
++                    ctx->limit_used += totalread;
++                    if (ctx->limit < ctx->limit_used) {
++                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r,
++                                      APLOGNO(01591) "Read content length of "
++                                      "%" APR_OFF_T_FMT " is larger than the "
++                                      "configured limit of %" APR_OFF_T_FMT,
++                                      ctx->limit_used, ctx->limit);
++                        return bail_out_on_error(ctx, f,
++                                                 HTTP_REQUEST_ENTITY_TOO_LARGE);
++                    }
++                }
+             }
 -        }
 -    }
-+                if (rv != APR_SUCCESS) {
-+                    return rv;
-+                }
  
 -    /* If we have no more bytes remaining on a C-L request,
 -     * save the callter a roundtrip to discover EOS.
@@ -640,8 +696,14 @@
 -        e = apr_bucket_eos_create(f->c->bucket_alloc);
 -        APR_BRIGADE_INSERT_TAIL(b, e);
 -    }
-+                /* How many bytes did we just read? */
-+                apr_brigade_length(b, 0, &totalread);
++            /* If we have no more bytes remaining on a C-L request,
++             * save the caller a round trip to discover EOS.
++             */
++            if (ctx->state == BODY_LENGTH && ctx->remaining == 0) {
++                e = apr_bucket_eos_create(f->c->bucket_alloc);
++                APR_BRIGADE_INSERT_TAIL(b, e);
++                ctx->eos_sent = 1;
++            }
  
 -    /* We have a limit in effect. */
 -    if (ctx->limit) {
@@ -663,32 +725,13 @@
 -            APR_BRIGADE_INSERT_TAIL(bb, e);
 -            ctx->eos_sent = 1;
 -            return ap_pass_brigade(f->r->output_filters, bb);
--        }
++            break;
+         }
 -    }
-+                /* If this happens, we have a bucket of unknown length.  Die because
-+                 * it means our assumptions have changed. */
-+                AP_DEBUG_ASSERT(totalread >= 0);
-+
-+                if (ctx->state != BODY_NONE) {
-+                    ctx->remaining -= totalread;
-+                    if (ctx->remaining > 0) {
-+                        e = APR_BRIGADE_LAST(b);
-+                        if (APR_BUCKET_IS_EOS(e)) {
-+                            apr_bucket_delete(e);
-+                            return APR_INCOMPLETE;
-+                        }
-+                    }
-+                    else if (ctx->state == BODY_CHUNK_DATA) {
-+                        /* next chunk please */
-+                        ctx->state = BODY_CHUNK_END;
-+                        ctx->chunk_used = 0;
-+                    }
-+                }
- 
+-
 -    return APR_SUCCESS;
 -}
-+            }
- 
+-
 -/**
 - * Parse a chunk extension, detect overflow.
 - * There are two error cases:
@@ -702,30 +745,10 @@
 -{
 -    long chunksize = 0;
 -    size_t chunkbits = sizeof(long) * 8;
-+            /* If we have no more bytes remaining on a C-L request,
-+             * save the caller a round trip to discover EOS.
-+             */
-+            if (ctx->state == BODY_LENGTH && ctx->remaining == 0) {
-+                e = apr_bucket_eos_create(f->c->bucket_alloc);
-+                APR_BRIGADE_INSERT_TAIL(b, e);
-+                ctx->eos_sent = 1;
-+            }
++        case BODY_CHUNK_TRAILER: {
  
 -    ap_xlate_proto_from_ascii(b, strlen(b));
-+            /* We have a limit in effect. */
-+            if (ctx->limit) {
-+                /* FIXME: Note that we might get slightly confused on chunked inputs
-+                 * as we'd need to compensate for the chunk lengths which may not
-+                 * really count.  This seems to be up for interpretation.  */
-+                ctx->limit_used += totalread;
-+                if (ctx->limit < ctx->limit_used) {
-+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01591)
-+                                  "Read content-length of %" APR_OFF_T_FMT
-+                                  " is larger than the configured limit"
-+                                  " of %" APR_OFF_T_FMT, ctx->limit_used, ctx->limit);
-+                    return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
-+                }
-+            }
++            rv = ap_get_brigade(f->next, b, mode, block, readbytes);
  
 -    if (!apr_isxdigit(*b)) {
 -        /*
@@ -738,12 +761,6 @@
 -    while (*b == '0') {
 -        ++b;
 -    }
-+            break;
-+        }
-+        case BODY_CHUNK_TRAILER: {
-+
-+            rv = ap_get_brigade(f->next, b, mode, block, readbytes);
-+
 +            /* for timeout */
 +            if (block == APR_NONBLOCK_READ
 +                    && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b))

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-apache/apache2.git



More information about the Pkg-apache-commits mailing list