[apache2] 03/05: Apply compatibility fixes for CVE-2015-3183 fix 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 08ce11f4eb80c9f163cbaa46e3f2bedee3b1e105
Author: Stefan Fritsch <sf at sfritsch.de>
Date:   Sat Jun 27 16:39:43 2015 +0200

    Apply compatibility fixes for CVE-2015-3183 fix from upstream
---
 .../CVE-2015-3183-chunk-header-parsing.diff        | 215 +++++++++++----------
 1 file changed, 114 insertions(+), 101 deletions(-)

diff --git a/debian/patches/CVE-2015-3183-chunk-header-parsing.diff b/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
index 9ded744..238e650 100644
--- a/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
+++ b/debian/patches/CVE-2015-3183-chunk-header-parsing.diff
@@ -1,7 +1,10 @@
 # https://svn.apache.org/r1684515
+# https://svn.apache.org/r1685904
+# https://svn.apache.org/r1685950
+# https://svn.apache.org/r1686271
 --- apache2.orig/modules/http/http_filters.c
 +++ apache2/modules/http/http_filters.c
-@@ -57,24 +57,27 @@
+@@ -57,24 +57,28 @@
  
  APLOG_USE_MODULE(http);
  
@@ -29,10 +32,11 @@
 +        BODY_CHUNK, /* chunk expected */
 +        BODY_CHUNK_PART, /* chunk digits */
 +        BODY_CHUNK_EXT, /* chunk extension */
-+        BODY_CHUNK_LF, /* got CR, expect LF after digits/extension */
++        BODY_CHUNK_CR, /* got space(s) after digits, expect [CR]LF or ext */
++        BODY_CHUNK_LF, /* got CR after digits or ext, expect LF */
 +        BODY_CHUNK_DATA, /* data constrained by chunked encoding */
 +        BODY_CHUNK_END, /* chunked data terminating CRLF */
-+        BODY_CHUNK_END_LF, /* got CR, expect LF after data */
++        BODY_CHUNK_END_LF, /* got CR after data, expect LF */
 +        BODY_CHUNK_TRAILER /* trailers */
      } state;
 -    int eos_sent;
@@ -43,7 +47,7 @@
      apr_bucket_brigade *bb;
  } http_ctx_t;
  
-@@ -119,117 +122,139 @@ static apr_status_t bail_out_on_error(ht
+@@ -119,117 +123,148 @@ static apr_status_t bail_out_on_error(ht
      return ap_pass_brigade(f->r->output_filters, bb);
  }
  
@@ -98,10 +102,10 @@
 -         e = APR_BUCKET_PREV(e)) {
 +    while (i < len) {
 +        char c = buffer[i];
-+
-+        ap_xlate_proto_from_ascii(&c, 1);
  
 -        if (APR_BUCKET_IS_METADATA(e)) {
++        ap_xlate_proto_from_ascii(&c, 1);
++
 +        /* handle CRLF after the chunk */
 +        if (ctx->state == BODY_CHUNK_END
 +                || ctx->state == BODY_CHUNK_END_LF) {
@@ -139,7 +143,9 @@
 +            ctx->remaining = 0;
 +            ctx->chunkbits = sizeof(apr_off_t) * 8;
 +            ctx->chunk_used = 0;
-+        }
+         }
+-        if (len > 0) {
+-            break;  /* we got the data we want */
 +
 +        if (c == LF) {
 +            if (ctx->remaining) {
@@ -149,14 +155,6 @@
 +                ctx->state = BODY_CHUNK_TRAILER;
 +            }
          }
--        if (len > 0) {
--            break;  /* we got the data we want */
-+        else if (ctx->state == BODY_CHUNK_LF) {
-+            /*
-+             * LF expected.
-+             */
-+            return APR_EINVAL;
-         }
 -        /* If we got a zero-length data bucket, we try the next one */
 -    }
 -    /* We had no data in this brigade */
@@ -171,6 +169,12 @@
 -    ctx->pos = ctx->chunk_ln;
 -    return APR_SUCCESS;
 -}
++        else if (ctx->state == BODY_CHUNK_LF) {
++            /*
++             * LF expected.
++             */
++            return APR_EINVAL;
++        }
 +        else if (c == CR) {
 +            ctx->state = BODY_CHUNK_LF;
 +        }
@@ -185,6 +189,15 @@
 +                return APR_EINVAL;
 +            }
 +        }
++        else if (c == ' ' || c == '\t') {
++            ctx->state = BODY_CHUNK_CR;
++        }
++        else if (ctx->state == BODY_CHUNK_CR) {
++            /*
++             * ';', CR or LF expected.
++             */
++            return APR_EINVAL;
++        }
 +        else if (ctx->state == BODY_CHUNK_PART) {
 +            int xvalue;
  
@@ -267,22 +280,22 @@
 +        }
 +
 +        i++;
-+    }
-+
-+    /* sanity check */
-+    ctx->chunk_used += len;
-+    if (ctx->chunk_used < 0 || ctx->chunk_used > linelimit) {
-+        return APR_ENOSPC;
      }
 -    return get_remaining_chunk_line(ctx, b, linelimit);
 -}
  
++    /* sanity check */
++    ctx->chunk_used += len;
++    if (ctx->chunk_used < 0 || ctx->chunk_used > linelimit) {
++        return APR_ENOSPC;
++    }
++
 +    return APR_SUCCESS;
 +}
  
  static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f,
                                            apr_bucket_brigade *b, int merge)
-@@ -243,7 +268,6 @@ static apr_status_t read_chunked_trailer
+@@ -243,7 +278,6 @@ static apr_status_t read_chunked_trailer
      r->status = HTTP_OK;
      r->headers_in = r->trailers_in;
      apr_table_clear(r->headers_in);
@@ -290,7 +303,7 @@
      ap_get_mime_headers(r);
  
      if(r->status == HTTP_OK) {
-@@ -290,6 +314,7 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -290,6 +324,7 @@ apr_status_t ap_http_filter(ap_filter_t
      apr_off_t totalread;
      int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;
      apr_bucket_brigade *bb;
@@ -298,7 +311,7 @@
  
      conf = (core_server_config *)
          ap_get_module_config(f->r->server->module_config, &core_module);
-@@ -303,7 +328,6 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -303,7 +338,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;
@@ -306,7 +319,7 @@
          ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
          bb = ctx->bb;
  
-@@ -335,14 +359,17 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -335,14 +369,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)
@@ -327,7 +340,7 @@
              }
              lenp = NULL;
          }
-@@ -361,7 +388,7 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -361,7 +398,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");
  
@@ -336,7 +349,7 @@
              }
  
              /* If we have a limit in effect and we know the C-L ahead of
-@@ -403,7 +430,8 @@ apr_status_t ap_http_filter(ap_filter_t
+@@ -403,7 +440,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;
@@ -346,29 +359,50 @@
                  char *tmp;
                  int len;
  
-@@ -424,287 +452,192 @@ apr_status_t ap_http_filter(ap_filter_t
-                 APR_BRIGADE_INSERT_TAIL(bb, e);
- 
+@@ -426,285 +464,194 @@ apr_status_t ap_http_filter(ap_filter_t
                  ap_pass_brigade(f->c->output_filters, bb);
-+                apr_brigade_cleanup(bb);
              }
          }
--
++    }
+ 
 -        /* We can't read the chunk until after sending 100 if required. */
 -        if (ctx->state == BODY_CHUNK) {
 -            apr_brigade_cleanup(bb);
--
++    /* sanity check in case we're read twice */
++    if (ctx->eos_sent) {
++        e = apr_bucket_eos_create(f->c->bucket_alloc);
++        APR_BRIGADE_INSERT_TAIL(b, e);
++        return APR_SUCCESS;
++    }
+ 
 -            rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
 -                                block, 0);
--
--            /* for timeout */
++    do {
++        apr_brigade_cleanup(b);
++        again = 0; /* until further notice */
++
++        /* read and handle the brigade */
++        switch (ctx->state) {
++        case BODY_CHUNK:
++        case BODY_CHUNK_PART:
++        case BODY_CHUNK_EXT:
++        case BODY_CHUNK_LF:
++        case BODY_CHUNK_END:
++        case BODY_CHUNK_END_LF: {
++
++            rv = ap_get_brigade(f->next, b, AP_MODE_GETLINE, block, 0);
+ 
+             /* for timeout */
 -            if (block == APR_NONBLOCK_READ &&
 -                ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ||
 -                  (APR_STATUS_IS_EAGAIN(rv)) )) {
 -                ctx->state = BODY_CHUNK_PART;
--                return APR_EAGAIN;
--            }
--
++            if (block == APR_NONBLOCK_READ
++                    && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b))
++                            || (APR_STATUS_IS_EAGAIN(rv)))) {
+                 return APR_EAGAIN;
+             }
+ 
 -            if (rv == APR_SUCCESS) {
 -                rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line);
 -                if (APR_STATUS_IS_EAGAIN(rv)) {
@@ -383,9 +417,11 @@
 -                        http_error = HTTP_BAD_REQUEST;
 -                    }
 -                }
--            }
++            if (rv == APR_EOF) {
++                return APR_INCOMPLETE;
+             }
 -            apr_brigade_cleanup(bb);
--
+ 
 -            /* Detect chunksize error (such as overflow) */
 -            if (rv != APR_SUCCESS || ctx->remaining < 0) {
 -                ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01589) "Error reading first chunk %s ",
@@ -396,8 +432,10 @@
 -                ctx->remaining = 0; /* Reset it in case we have to
 -                                     * come back here later */
 -                return bail_out_on_error(ctx, f, http_error);
--            }
--
++            if (rv != APR_SUCCESS) {
++                return rv;
+             }
+ 
 -            if (!ctx->remaining) {
 -                return read_chunked_trailers(ctx, f, b,
 -                        conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE);
@@ -406,22 +444,22 @@
 -    }
 -    else {
 -        bb = ctx->bb;
-     }
+-    }
++            e = APR_BRIGADE_FIRST(b);
++            while (e != APR_BRIGADE_SENTINEL(b)) {
++                const char *buffer;
++                apr_size_t len;
  
-+    /* sanity check in case we're read twice */
-     if (ctx->eos_sent) {
-         e = apr_bucket_eos_create(f->c->bucket_alloc);
-         APR_BRIGADE_INSERT_TAIL(b, e);
-         return APR_SUCCESS;
-     }
+-    if (ctx->eos_sent) {
+-        e = apr_bucket_eos_create(f->c->bucket_alloc);
+-        APR_BRIGADE_INSERT_TAIL(b, e);
+-        return APR_SUCCESS;
+-    }
++                if (!APR_BUCKET_IS_METADATA(e)) {
++                    int parsing = 0;
  
 -    if (!ctx->remaining) {
-+    do {
-+        apr_brigade_cleanup(b);
-+        again = 0; /* until further notice */
-+
-+        /* read and handle the brigade */
-         switch (ctx->state) {
+-        switch (ctx->state) {
 -        case BODY_NONE:
 -            break;
 -        case BODY_LENGTH:
@@ -429,14 +467,11 @@
 -            APR_BRIGADE_INSERT_TAIL(b, e);
 -            ctx->eos_sent = 1;
 -            return APR_SUCCESS;
-         case BODY_CHUNK:
-         case BODY_CHUNK_PART:
+-        case BODY_CHUNK:
+-        case BODY_CHUNK_PART:
 -            {
 -                apr_brigade_cleanup(bb);
-+        case BODY_CHUNK_EXT:
-+        case BODY_CHUNK_LF:
-+        case BODY_CHUNK_END:
-+        case BODY_CHUNK_END_LF: {
++                    rv = apr_bucket_read(e, &buffer, &len, APR_BLOCK_READ);
  
 -                /* We need to read the CRLF after the chunk.  */
 -                if (ctx->state == BODY_CHUNK) {
@@ -450,37 +485,14 @@
 -                    /* If we get an error, then leave */
 -                    if (rv == APR_EOF) {
 -                        return APR_INCOMPLETE;
--                    }
-+            rv = ap_get_brigade(f->next, b, AP_MODE_GETLINE, block, 0);
-+
-+            /* 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_EOF) {
-+                return APR_INCOMPLETE;
-+            }
-+
-+            if (rv != APR_SUCCESS) {
-+                return rv;
-+            }
-+
-+            e = APR_BRIGADE_FIRST(b);
-+            while (e != APR_BRIGADE_SENTINEL(b)) {
-+                const char *buffer;
-+                apr_size_t len;
-+
-+                if (!APR_BUCKET_IS_METADATA(e)) {
-+                    rv = apr_bucket_read(e, &buffer, &len, APR_BLOCK_READ);
-                     if (rv != APR_SUCCESS) {
-+                        ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590)
-+                                      "Error reading chunk %s ",
-+                                      (APR_ENOSPC == rv) ? "(overflow)" : "");
-                         return rv;
++                    if (rv == APR_SUCCESS) {
++                        parsing = 1;
++                        rv = parse_chunk_size(ctx, buffer, len,
++                                f->r->server->limit_req_fieldsize);
                      }
+                     if (rv != APR_SUCCESS) {
+-                        return rv;
+-                    }
 -                    /*
 -                     * We really don't care whats on this line. If it is RFC
 -                     * compliant it should be only \r\n. If there is more
@@ -496,7 +508,7 @@
 -                } else {
 -                    rv = APR_SUCCESS;
 -                }
- 
+-
 -                if (rv == APR_SUCCESS) {
 -                    /* Read the real chunk line. */
 -                    rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
@@ -520,15 +532,16 @@
 -                            ctx->remaining = get_chunk_size(ctx->chunk_ln);
 -                            if (ctx->remaining == INVALID_CHAR) {
 -                                rv = APR_EGENERAL;
--                                http_error = HTTP_BAD_REQUEST;
--                            }
-+                    rv = parse_chunk_size(ctx, buffer, len,
-+                                          f->r->server->limit_req_fieldsize);
-+                    if (rv != APR_SUCCESS) {
-+                        if (rv != APR_ENOSPC) {
-+                            http_error = HTTP_BAD_REQUEST;
++                        ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590)
++                                      "Error reading/parsing chunk %s ",
++                                      (APR_ENOSPC == rv) ? "(overflow)" : "");
++                        if (parsing) {
++                            if (rv != APR_ENOSPC) {
+                                 http_error = HTTP_BAD_REQUEST;
+                             }
++                            return bail_out_on_error(ctx, f, http_error);
                          }
-+                        return bail_out_on_error(ctx, f, http_error);
++                        return rv;
                      }
 -                    apr_brigade_cleanup(bb);
                  }
@@ -752,7 +765,7 @@
 -            xvalue = *b - 'A' + 0xa;
 +        default: {
 +            /* Should not happen */
-+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(02901)
++            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02901)
 +                          "Unexpected body state (%i)", (int)ctx->state);
 +            return APR_EGENERAL;
          }

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