summaryrefslogtreecommitdiff
path: root/modules/http
diff options
context:
space:
mode:
authorWilliam A. Rowe Jr <wrowe@apache.org>2014-08-22 18:18:08 +0000
committerWilliam A. Rowe Jr <wrowe@apache.org>2014-08-22 18:18:08 +0000
commit4992fc660a6241668a7d7993edab3f527f7fc7f2 (patch)
tree220a2c7db1606f244ff80c06d38de38b82f90b41 /modules/http
parent465de31db17e13d28051eb107c503c5152786276 (diff)
downloadhttpd-4992fc660a6241668a7d7993edab3f527f7fc7f2.tar.gz
SECURITY: CVE-2013-5704 (cve.mitre.org)
core: HTTP trailers could be used to replace HTTP headers late during request processing, potentially undoing or otherwise confusing modules that examined or modified request headers earlier. Adds "MergeTrailers" directive to restore legacy behavior. Submitted by: Edward Lu, Yann Ylavic, Joe Orton, Eric Covener Backports: r1610814 Reviewed by: covener, wrowe, ylavic git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1619884 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http')
-rw-r--r--modules/http/http_filters.c65
-rw-r--r--modules/http/http_request.c4
2 files changed, 55 insertions, 14 deletions
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 2a0a979d5f..0b8600962f 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -231,6 +231,49 @@ static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b,
}
+static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *b, int merge)
+{
+ int rv;
+ apr_bucket *e;
+ request_rec *r = f->r;
+ apr_table_t *saved_headers_in = r->headers_in;
+ int saved_status = r->status;
+
+ r->status = HTTP_OK;
+ r->headers_in = r->trailers_in;
+ apr_table_clear(r->headers_in);
+ ctx->state = BODY_NONE;
+ ap_get_mime_headers(r);
+
+ if(r->status == HTTP_OK) {
+ r->status = saved_status;
+ e = apr_bucket_eos_create(f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(b, e);
+ ctx->eos_sent = 1;
+ rv = APR_SUCCESS;
+ }
+ else {
+ const char *error_notes = apr_table_get(r->notes,
+ "error-notes");
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Error while reading HTTP trailer: %i%s%s",
+ r->status, error_notes ? ": " : "",
+ error_notes ? error_notes : "");
+ rv = APR_EINVAL;
+ }
+
+ if(!merge) {
+ r->headers_in = saved_headers_in;
+ }
+ else {
+ r->headers_in = apr_table_overlay(r->pool, saved_headers_in,
+ r->trailers_in);
+ }
+
+ return rv;
+}
+
/* This is the HTTP_INPUT filter for HTTP requests and responses from
* proxied servers (mod_proxy). It handles chunked and content-length
* bodies. This can only be inserted/used after the headers
@@ -240,6 +283,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
ap_input_mode_t mode, apr_read_type_e block,
apr_off_t readbytes)
{
+ core_server_config *conf;
apr_bucket *e;
http_ctx_t *ctx = f->ctx;
apr_status_t rv;
@@ -247,6 +291,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;
apr_bucket_brigade *bb;
+ conf = (core_server_config *)
+ ap_get_module_config(f->r->server->module_config, &core_module);
+
/* just get out of the way of things we don't want. */
if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {
return ap_get_brigade(f->next, b, mode, block, readbytes);
@@ -425,13 +472,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
}
if (!ctx->remaining) {
- /* Handle trailers by calling ap_get_mime_headers again! */
- ctx->state = BODY_NONE;
- ap_get_mime_headers(f->r);
- e = apr_bucket_eos_create(f->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(b, e);
- ctx->eos_sent = 1;
- return APR_SUCCESS;
+ return read_chunked_trailers(ctx, f, b,
+ conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE);
}
}
}
@@ -534,13 +576,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
}
if (!ctx->remaining) {
- /* Handle trailers by calling ap_get_mime_headers again! */
- ctx->state = BODY_NONE;
- ap_get_mime_headers(f->r);
- e = apr_bucket_eos_create(f->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(b, e);
- ctx->eos_sent = 1;
- return APR_SUCCESS;
+ return read_chunked_trailers(ctx, f, b,
+ conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE);
}
}
break;
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
index 796d506e84..cdfec8b568 100644
--- a/modules/http/http_request.c
+++ b/modules/http/http_request.c
@@ -463,6 +463,7 @@ static request_rec *internal_internal_redirect(const char *new_uri,
new->main = r->main;
new->headers_in = r->headers_in;
+ new->trailers_in = r->trailers_in;
new->headers_out = apr_table_make(r->pool, 12);
if (ap_is_HTTP_REDIRECT(new->status)) {
const char *location = apr_table_get(r->headers_out, "Location");
@@ -470,6 +471,7 @@ static request_rec *internal_internal_redirect(const char *new_uri,
apr_table_setn(new->headers_out, "Location", location);
}
new->err_headers_out = r->err_headers_out;
+ new->trailers_out = apr_table_make(r->pool, 5);
new->subprocess_env = rename_original_env(r->pool, r->subprocess_env);
new->notes = apr_table_make(r->pool, 5);
@@ -583,6 +585,8 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r)
r->headers_out);
r->err_headers_out = apr_table_overlay(r->pool, rr->err_headers_out,
r->err_headers_out);
+ r->trailers_out = apr_table_overlay(r->pool, rr->trailers_out,
+ r->trailers_out);
r->subprocess_env = apr_table_overlay(r->pool, rr->subprocess_env,
r->subprocess_env);