[httpd] core: fix bypassing of mod_headers rules via chunked requests (CVE-2013-5704)

Jan Kaluža jkaluza at fedoraproject.org
Wed Dec 17 08:26:02 UTC 2014


commit af9996ce6998c4c343dc7ac5677fd4f159085480
Author: Jan Kaluza <jkaluza at redhat.com>
Date:   Wed Dec 17 09:25:50 2014 +0100

    core: fix bypassing of mod_headers rules via chunked requests (CVE-2013-5704)
    
    - mod_cache: fix NULL pointer dereference on empty Content-Type (CVE-2014-3581)
    - mod_proxy_fcgi: fix a potential crash with long headers (CVE-2014-3583)
    - mod_lua: fix handling of the Require line when a LuaAuthzProvider is used
      in multiple Require directives with different arguments (CVE-2014-8109)

 httpd-2.4.10-CVE-2014-3583.patch |   75 ++++++++
 httpd-2.4.10-CVE-2014-8109.patch |  108 +++++++++++
 httpd-2.4.6-CVE-2013-5704.patch  |  381 ++++++++++++++++++++++++++++++++++++++
 httpd-2.4.6-CVE-2014-3581.patch  |   17 ++
 httpd.spec                       |   19 ++-
 5 files changed, 599 insertions(+), 1 deletions(-)
---
diff --git a/httpd-2.4.10-CVE-2014-3583.patch b/httpd-2.4.10-CVE-2014-3583.patch
new file mode 100644
index 0000000..7794a3d
--- /dev/null
+++ b/httpd-2.4.10-CVE-2014-3583.patch
@@ -0,0 +1,75 @@
+--- a/modules/proxy/mod_proxy_fcgi.c	2014/11/12 15:32:12	1638817
++++ b/modules/proxy/mod_proxy_fcgi.c	2014/11/12 15:41:07	1638818
+@@ -18,6 +18,8 @@
+ #include "util_fcgi.h"
+ #include "util_script.h"
+ 
++#include "apr_lib.h" /* for apr_iscntrl() */
++
+ module AP_MODULE_DECLARE_DATA proxy_fcgi_module;
+ 
+ /*
+@@ -310,13 +312,12 @@
+  *
+  * Returns 0 if it can't find the end of the headers, and 1 if it found the
+  * end of the headers. */
+-static int handle_headers(request_rec *r,
+-                          int *state,
+-                          char *readbuf)
++static int handle_headers(request_rec *r, int *state,
++                          const char *readbuf, apr_size_t readlen)
+ {
+     const char *itr = readbuf;
+ 
+-    while (*itr) {
++    while (readlen) {
+         if (*itr == '\r') {
+             switch (*state) {
+                 case HDR_STATE_GOT_CRLF:
+@@ -347,13 +348,17 @@
+                      break;
+             }
+         }
+-        else {
++        else if (*itr == '\t' || !apr_iscntrl(*itr)) {
+             *state = HDR_STATE_READING_HEADERS;
+         }
++        else {
++            return -1;
++        }
+ 
+         if (*state == HDR_STATE_DONE_WITH_HEADERS)
+             break;
+ 
++        --readlen;
+         ++itr;
+     }
+ 
+@@ -563,7 +568,14 @@
+                     APR_BRIGADE_INSERT_TAIL(ob, b);
+ 
+                     if (! seen_end_of_headers) {
+-                        int st = handle_headers(r, &header_state, iobuf);
++                        int st = handle_headers(r, &header_state, iobuf,
++                                                readbuflen);
++
++                        if (st == -1) {
++                            *err = "parsing response headers";
++                            rv = APR_EINVAL;
++                            break;
++                        }
+ 
+                         if (st == 1) {
+                             int status;
+@@ -684,6 +696,11 @@
+                 break;
+             }
+ 
++            if (*err) {
++                /* stop on error in the above switch */
++                break;
++            }
++
+             if (plen) {
+                 rv = get_data_full(conn, iobuf, plen);
+                 if (rv != APR_SUCCESS) {
diff --git a/httpd-2.4.10-CVE-2014-8109.patch b/httpd-2.4.10-CVE-2014-8109.patch
new file mode 100644
index 0000000..9a1ac4e
--- /dev/null
+++ b/httpd-2.4.10-CVE-2014-8109.patch
@@ -0,0 +1,108 @@
+From 3f1693d558d0758f829c8b53993f1749ddf6ffcb Mon Sep 17 00:00:00 2001
+From: Jim Jagielski <jim at apache.org>
+Date: Tue, 2 Dec 2014 12:50:59 +0000
+Subject: [PATCH] Merge r1642499 from trunk:
+
+  *) SECURITY: CVE-2014-8109 (cve.mitre.org)
+     mod_lua: Fix handling of the Require line when a LuaAuthzProvider is
+     used in multiple Require directives with different arguments.
+     PR57204 [Edward Lu <Chaosed0 gmail.com>]
+
+Submitted By: Edward Lu
+Committed By: covener
+
+
+Submitted by: covener
+Reviewed/backported by: jim
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1642861 13f79535-47bb-0310-9956-ffa450edef68
+---
+ CHANGES               |  5 +++++
+ STATUS                |  7 -------
+ modules/lua/mod_lua.c | 27 +++++++++++++++++----------
+ 3 files changed, 22 insertions(+), 17 deletions(-)
+
+diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c
+index b2dca75..e6d2cfc 100644
+--- a/modules/lua/mod_lua.c
++++ b/modules/lua/mod_lua.c
+@@ -66,9 +66,13 @@ typedef struct {
+     const char *file_name;
+     const char *function_name;
+     ap_lua_vm_spec *spec;
+-    apr_array_header_t *args;
+ } lua_authz_provider_spec;
+ 
++typedef struct {
++    lua_authz_provider_spec *spec;
++    apr_array_header_t *args;
++} lua_authz_provider_func;
++
+ apr_hash_t *lua_authz_providers;
+ 
+ typedef struct
+@@ -1692,6 +1696,7 @@ static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
+ {
+     const char *provider_name;
+     lua_authz_provider_spec *spec;
++    lua_authz_provider_func *func = apr_pcalloc(cmd->pool, sizeof(lua_authz_provider_func));
+ 
+     apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE,
+                           cmd->temp_pool);
+@@ -1699,16 +1704,17 @@ static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
+ 
+     spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING);
+     ap_assert(spec != NULL);
++    func->spec = spec;
+ 
+     if (require_line && *require_line) {
+         const char *arg;
+-        spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
++        func->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
+         while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) {
+-            APR_ARRAY_PUSH(spec->args, const char *) = arg;
++            APR_ARRAY_PUSH(func->args, const char *) = arg;
+         }
+     }
+ 
+-    *parsed_require_line = spec;
++    *parsed_require_line = func;
+     return NULL;
+ }
+ 
+@@ -1722,7 +1728,8 @@ static authz_status lua_authz_check(request_rec *r, const char *require_line,
+                                                          &lua_module);
+     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
+                                                      &lua_module);
+-    const lua_authz_provider_spec *prov_spec = parsed_require_line;
++    const lua_authz_provider_func *prov_func = parsed_require_line;
++    const lua_authz_provider_spec *prov_spec = prov_func->spec;
+     int result;
+     int nargs = 0;
+ 
+@@ -1744,19 +1751,19 @@ static authz_status lua_authz_check(request_rec *r, const char *require_line,
+         return AUTHZ_GENERAL_ERROR;
+     }
+     ap_lua_run_lua_request(L, r);
+-    if (prov_spec->args) {
++    if (prov_func->args) {
+         int i;
+-        if (!lua_checkstack(L, prov_spec->args->nelts)) {
++        if (!lua_checkstack(L, prov_func->args->nelts)) {
+             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
+                           "Error: authz provider %s: too many arguments", prov_spec->name);
+             ap_lua_release_state(L, spec, r);
+             return AUTHZ_GENERAL_ERROR;
+         }
+-        for (i = 0; i < prov_spec->args->nelts; i++) {
+-            const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *);
++        for (i = 0; i < prov_func->args->nelts; i++) {
++            const char *arg = APR_ARRAY_IDX(prov_func->args, i, const char *);
+             lua_pushstring(L, arg);
+         }
+-        nargs = prov_spec->args->nelts;
++        nargs = prov_func->args->nelts;
+     }
+     if (lua_pcall(L, 1 + nargs, 1, 0)) {
+         const char *err = lua_tostring(L, -1);
diff --git a/httpd-2.4.6-CVE-2013-5704.patch b/httpd-2.4.6-CVE-2013-5704.patch
new file mode 100644
index 0000000..410ca21
--- /dev/null
+++ b/httpd-2.4.6-CVE-2013-5704.patch
@@ -0,0 +1,381 @@
+diff --git a/include/http_core.h b/include/http_core.h
+index 3c47989..f6f4aa2 100644
+--- a/include/http_core.h
++++ b/include/http_core.h
+@@ -663,6 +663,10 @@ typedef struct {
+ #define AP_TRACE_ENABLE    1
+ #define AP_TRACE_EXTENDED  2
+     int trace_enable;
++#define AP_MERGE_TRAILERS_UNSET    0
++#define AP_MERGE_TRAILERS_ENABLE   1
++#define AP_MERGE_TRAILERS_DISABLE  2
++    int merge_trailers;
+ 
+ } core_server_config;
+ 
+diff --git a/include/httpd.h b/include/httpd.h
+index 36cd58d..2e415f9 100644
+--- a/include/httpd.h
++++ b/include/httpd.h
+@@ -1032,6 +1032,11 @@ struct request_rec {
+      */
+     apr_sockaddr_t *useragent_addr;
+     char *useragent_ip;
++
++    /** MIME trailer environment from the request */
++    apr_table_t *trailers_in;
++    /** MIME trailer environment from the response */
++    apr_table_t *trailers_out;
+ };
+ 
+ /**
+diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
+index 24a939a..2ae8f46 100644
+--- a/modules/http/http_filters.c
++++ b/modules/http/http_filters.c
+@@ -214,6 +214,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
+@@ -223,6 +266,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;
+@@ -230,6 +274,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);
+@@ -403,13 +450,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);
+             }
+         }
+     }
+@@ -509,13 +551,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 796d506..cdfec8b 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);
+ 
+diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c
+index 25f5030..b021dd3 100644
+--- a/modules/loggers/mod_log_config.c
++++ b/modules/loggers/mod_log_config.c
+@@ -431,6 +431,12 @@ static const char *log_header_in(request_rec *r, char *a)
+     return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a));
+ }
+ 
++static const char *log_trailer_in(request_rec *r, char *a)
++{
++    return ap_escape_logitem(r->pool, apr_table_get(r->trailers_in, a));
++}
++
++
+ static APR_INLINE char *find_multiple_headers(apr_pool_t *pool,
+                                               const apr_table_t *table,
+                                               const char *key)
+@@ -514,6 +520,11 @@ static const char *log_header_out(request_rec *r, char *a)
+     return ap_escape_logitem(r->pool, cp);
+ }
+ 
++static const char *log_trailer_out(request_rec *r, char *a)
++{
++    return ap_escape_logitem(r->pool, apr_table_get(r->trailers_out, a));
++}
++
+ static const char *log_note(request_rec *r, char *a)
+ {
+     return ap_escape_logitem(r->pool, apr_table_get(r->notes, a));
+@@ -916,7 +927,7 @@ static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
+ static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
+ {
+     const char *s = *sa;
+-    ap_log_handler *handler;
++    ap_log_handler *handler = NULL;
+ 
+     if (*s != '%') {
+         return parse_log_misc_string(p, it, sa);
+@@ -986,7 +997,16 @@ static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
+             break;
+ 
+         default:
+-            handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
++            /* check for '^' + two character format first */
++            if (*s == '^' && *(s+1) && *(s+2)) { 
++                handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3); 
++                if (handler) { 
++                   s += 3;
++                }
++            }
++            if (!handler) {  
++                handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);  
++            }
+             if (!handler) {
+                 char dummy[2];
+ 
+@@ -1516,7 +1536,7 @@ static void ap_register_log_handler(apr_pool_t *p, char *tag,
+     log_struct->func = handler;
+     log_struct->want_orig_default = def;
+ 
+-    apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
++    apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct);
+ }
+ static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle)
+ {
+@@ -1686,6 +1706,9 @@ static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
+         log_pfn_register(p, "U", log_request_uri, 1);
+         log_pfn_register(p, "s", log_status, 1);
+         log_pfn_register(p, "R", log_handler, 1);
++
++        log_pfn_register(p, "^ti", log_trailer_in, 0);
++        log_pfn_register(p, "^to", log_trailer_out, 0);
+     }
+ 
+     /* reset to default conditions */
+diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
+index 7ae0fa4..05f33b4 100644
+--- a/modules/proxy/mod_proxy_http.c
++++ b/modules/proxy/mod_proxy_http.c
+@@ -994,8 +994,11 @@ static request_rec *make_fake_req(conn_rec *c, request_rec *r)
+     rp->status          = HTTP_OK;
+ 
+     rp->headers_in      = apr_table_make(pool, 50);
++    rp->trailers_in     = apr_table_make(pool, 5);
++
+     rp->subprocess_env  = apr_table_make(pool, 50);
+     rp->headers_out     = apr_table_make(pool, 12);
++    rp->trailers_out    = apr_table_make(pool, 5);
+     rp->err_headers_out = apr_table_make(pool, 5);
+     rp->notes           = apr_table_make(pool, 5);
+ 
+@@ -1076,6 +1079,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
+     psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+ 
+     r->headers_out = apr_table_make(r->pool, 20);
++    r->trailers_out = apr_table_make(r->pool, 5);
+     *pread_len = 0;
+ 
+     /*
+@@ -1206,6 +1210,14 @@ apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec
+ #define AP_MAX_INTERIM_RESPONSES 10
+ #endif
+ 
++static int add_trailers(void *data, const char *key, const char *val)
++{
++    if (val) {
++        apr_table_add((apr_table_t*)data, key, val);
++    }
++    return 1;
++}
++
+ static
+ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
+                                             proxy_conn_rec **backend_ptr,
+@@ -1717,6 +1729,12 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
+                     /* next time try a non-blocking read */
+                     mode = APR_NONBLOCK_READ;
+ 
++                    if (!apr_is_empty_table(backend->r->trailers_in)) {
++                        apr_table_do(add_trailers, r->trailers_out,
++                                backend->r->trailers_in, NULL);
++                        apr_table_clear(backend->r->trailers_in);
++                    }
++
+                     apr_brigade_length(bb, 0, &readbytes);
+                     backend->worker->s->read += readbytes;
+ #if DEBUGGING
+diff --git a/server/core.c b/server/core.c
+index 024bab6..7cfde63 100644
+--- a/server/core.c
++++ b/server/core.c
+@@ -523,6 +523,10 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
+     if (virt->error_log_req)
+         conf->error_log_req = virt->error_log_req;
+ 
++    conf->merge_trailers = (virt->merge_trailers != AP_MERGE_TRAILERS_UNSET)
++                           ? virt->merge_trailers
++                           : base->merge_trailers;
++
+     return conf;
+ }
+ 
+@@ -3877,6 +3881,16 @@ AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag,
+ }
+ 
+ 
++static const char *set_merge_trailers(cmd_parms *cmd, void *dummy, int arg)
++{
++    core_server_config *conf = ap_get_module_config(cmd->server->module_config,
++                                                    &core_module);
++    conf->merge_trailers = (arg ? AP_MERGE_TRAILERS_ENABLE :
++            AP_MERGE_TRAILERS_DISABLE);
++
++    return NULL;
++}
++
+ /* Note --- ErrorDocument will now work from .htaccess files.
+  * The AllowOverride of Fileinfo allows webmasters to turn it off
+  */
+@@ -4124,6 +4138,8 @@ AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
+ #endif
+ AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
+               "'on' (default), 'off' or 'extended' to trace request body content"),
++AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF,
++              "merge request trailers into request headers or not"),
+ { NULL }
+ };
+ 
+@@ -4206,7 +4222,6 @@ static int core_map_to_storage(request_rec *r)
+ 
+ static int do_nothing(request_rec *r) { return OK; }
+ 
+-
+ static int core_override_type(request_rec *r)
+ {
+     core_dir_config *conf =
+diff --git a/server/protocol.c b/server/protocol.c
+index 14329eb..46fc034 100644
+--- a/server/protocol.c
++++ b/server/protocol.c
+@@ -718,6 +718,8 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb
+                 r->status = HTTP_REQUEST_TIME_OUT;
+             }
+             else {
++                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, 
++                              "Failed to read request header line %s", field);
+                 r->status = HTTP_BAD_REQUEST;
+             }
+ 
+@@ -917,9 +919,11 @@ request_rec *ap_read_request(conn_rec *conn)
+     r->allowed_methods = ap_make_method_list(p, 2);
+ 
+     r->headers_in      = apr_table_make(r->pool, 25);
++    r->trailers_in     = apr_table_make(r->pool, 5);
+     r->subprocess_env  = apr_table_make(r->pool, 25);
+     r->headers_out     = apr_table_make(r->pool, 12);
+     r->err_headers_out = apr_table_make(r->pool, 5);
++    r->trailers_out    = apr_table_make(r->pool, 5);
+     r->notes           = apr_table_make(r->pool, 5);
+ 
+     r->request_config  = ap_create_request_config(r->pool);
+@@ -1162,6 +1166,7 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew,
+     rnew->status          = HTTP_OK;
+ 
+     rnew->headers_in      = apr_table_copy(rnew->pool, r->headers_in);
++    rnew->trailers_in     = apr_table_copy(rnew->pool, r->trailers_in);
+ 
+     /* did the original request have a body?  (e.g. POST w/SSI tags)
+      * if so, make sure the subrequest doesn't inherit body headers
+@@ -1173,6 +1178,7 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew,
+     rnew->subprocess_env  = apr_table_copy(rnew->pool, r->subprocess_env);
+     rnew->headers_out     = apr_table_make(rnew->pool, 5);
+     rnew->err_headers_out = apr_table_make(rnew->pool, 5);
++    rnew->trailers_out    = apr_table_make(rnew->pool, 5);
+     rnew->notes           = apr_table_make(rnew->pool, 5);
+ 
+     rnew->expecting_100   = r->expecting_100;
diff --git a/httpd-2.4.6-CVE-2014-3581.patch b/httpd-2.4.6-CVE-2014-3581.patch
new file mode 100644
index 0000000..0702899
--- /dev/null
+++ b/httpd-2.4.6-CVE-2014-3581.patch
@@ -0,0 +1,17 @@
+diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c
+index 7b7fb45..fbebb1e 100644
+--- a/modules/cache/cache_util.c
++++ b/modules/cache/cache_util.c
+@@ -1251,8 +1251,10 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r)
+ 
+     if (r->content_type
+             && !apr_table_get(headers_out, "Content-Type")) {
+-        apr_table_setn(headers_out, "Content-Type",
+-                       ap_make_content_type(r, r->content_type));
++        const char *ctype = ap_make_content_type(r, r->content_type);
++        if (ctype) {
++            apr_table_setn(headers_out, "Content-Type", ctype);
++        }
+     }
+ 
+     if (r->content_encoding
diff --git a/httpd.spec b/httpd.spec
index d88386f..8a63aa4 100644
--- a/httpd.spec
+++ b/httpd.spec
@@ -14,7 +14,7 @@
 Summary: Apache HTTP Server
 Name: httpd
 Version: 2.4.10
-Release: 14%{?dist}
+Release: 15%{?dist}
 URL: http://httpd.apache.org/
 Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
 Source1: index.html
@@ -72,6 +72,11 @@ Patch35: httpd-2.4.10-sslciphdefault.patch
 Patch55: httpd-2.4.4-malformed-host.patch
 Patch56: httpd-2.4.4-mod_unique_id.patch
 Patch57: httpd-2.4.10-sigint.patch
+# Security fixes
+Patch100: httpd-2.4.6-CVE-2013-5704.patch
+Patch101: httpd-2.4.6-CVE-2014-3581.patch
+Patch102: httpd-2.4.10-CVE-2014-3583.patch
+Patch103: httpd-2.4.10-CVE-2014-8109.patch
 License: ASL 2.0
 Group: System Environment/Daemons
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@@ -216,6 +221,11 @@ interface for storing and accessing per-user session data.
 %patch56 -p1 -b .uniqueid
 %patch57 -p1 -b .sigint
 
+%patch100 -p1 -b cve20135704
+%patch101 -p1 -b cve20143581
+%patch102 -p1 -b cve20143583
+%patch103 -p1 -b cve20148109
+
 # Patch in the vendor string
 sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h
 
@@ -669,6 +679,13 @@ rm -rf $RPM_BUILD_ROOT
 %{_rpmconfigdir}/macros.d/macros.httpd
 
 %changelog
+* Wed Dec 17 2014 Jan Kaluza <jkaluza at redhat.com> - 2.4.10-15
+- core: fix bypassing of mod_headers rules via chunked requests (CVE-2013-5704)
+- mod_cache: fix NULL pointer dereference on empty Content-Type (CVE-2014-3581)
+- mod_proxy_fcgi: fix a potential crash with long headers (CVE-2014-3583)
+- mod_lua: fix handling of the Require line when a LuaAuthzProvider is used
+  in multiple Require directives with different arguments (CVE-2014-8109)
+
 * Tue Oct 14 2014 Joe Orton <jorton at redhat.com> - 2.4.10-14
 - require apr-util 1.5.x
 


More information about the scm-commits mailing list