[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