Package: release.debian.org Severity: normal Tags: wheezy User: release.debian....@packages.debian.org Usertags: pu
Hi, please review the update for apache2 for inclusion into s-p-u. It fixes a low-impact security issue and also includes two one-line bug fixes. The changelog is below, debdiff is attached. As I couldn't find any mail about it, I guess that 7.8 "Not yet planned; likely mid-December" is not yet closed? Thanks in advance. Cheers, Stefan * CVE-2013-5704: Fix handling of chunk trailers. A remote attacker could use this flaw to bypass intended mod_headers restrictions, allowing them to send requests to applications that include headers that should have been removed by mod_headers. The new behavior is to not merge trailers into the headers autmatically. A new directive "MergeTrailers" is introduced to restore the old behavior. * Fix hostname comparison with SNI to be case insensitive. Closes: #771199 * Fix valule of SSL_CLIENT_S_DN_UID in mod_ssl (broken in 2.2.15). Closes: #773841 * Add paragraph about session ticket key life-time and forward secrecy to README.Debian. Closes: #762619 README.Debian | 15 + changelog | 17 + patches/CVE-2013-5704_trailers.patch | 383 +++++++++++++++++++++++++++++++ patches/SNI_case_insensitve.diff | 13 + patches/mod_ssl_SSL_CLIENT_S_DN_UID.diff | 13 + patches/series | 3
diff -Nru apache2-2.2.22/debian/changelog apache2-2.2.22/debian/changelog --- apache2-2.2.22/debian/changelog 2014-07-24 17:32:33.000000000 +0200 +++ apache2-2.2.22/debian/changelog 2014-12-23 23:44:50.000000000 +0100 @@ -1,3 +1,20 @@ +apache2 (2.2.22-13+deb7u4) wheezy; urgency=medium + + * CVE-2013-5704: Fix handling of chunk trailers. A remote attacker could + use this flaw to bypass intended mod_headers restrictions, allowing + them to send requests to applications that include headers that should + have been removed by mod_headers. + The new behavior is to not merge trailers into the headers autmatically. + A new directive "MergeTrailers" is introduced to restore the old + behavior. + * Fix hostname comparison with SNI to be case insensitive. Closes: #771199 + * Fix valule of SSL_CLIENT_S_DN_UID in mod_ssl (broken in 2.2.15). + Closes: #773841 + * Add paragraph about session ticket key life-time and forward secrecy to + README.Debian. Closes: #762619 + + -- Stefan Fritsch <s...@debian.org> Tue, 23 Dec 2014 23:44:24 +0100 + apache2 (2.2.22-13+deb7u3) wheezy-security; urgency=high * CVE-2014-0226: Fix a race condition in scoreboard handling, diff -Nru apache2-2.2.22/debian/patches/CVE-2013-5704_trailers.patch apache2-2.2.22/debian/patches/CVE-2013-5704_trailers.patch --- apache2-2.2.22/debian/patches/CVE-2013-5704_trailers.patch 1970-01-01 01:00:00.000000000 +0100 +++ apache2-2.2.22/debian/patches/CVE-2013-5704_trailers.patch 2014-12-22 21:59:22.000000000 +0100 @@ -0,0 +1,383 @@ +# http://svn,apache.org/r1619489 +# +# *) 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. [Edward Lu, Yann Ylavic, Joe Orton, Eric Covener] +# +Index: apache2/modules/loggers/mod_log_config.c +=================================================================== +--- apache2.orig/modules/loggers/mod_log_config.c ++++ apache2/modules/loggers/mod_log_config.c +@@ -412,6 +412,12 @@ + 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) +@@ -495,6 +501,11 @@ + 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)); +@@ -813,7 +824,7 @@ + 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); +@@ -883,7 +894,16 @@ + 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]; + +@@ -1389,7 +1409,7 @@ + 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) + { +@@ -1558,6 +1578,9 @@ + 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 */ +Index: apache2/modules/http/http_request.c +=================================================================== +--- apache2.orig/modules/http/http_request.c ++++ apache2/modules/http/http_request.c +@@ -384,8 +384,10 @@ + 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); + 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); + +@@ -495,6 +497,8 @@ + 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); + +Index: apache2/modules/http/http_filters.c +=================================================================== +--- apache2.orig/modules/http/http_filters.c ++++ apache2/modules/http/http_filters.c +@@ -206,6 +206,49 @@ + } + + ++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 +@@ -215,6 +258,7 @@ + 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; +@@ -222,6 +266,9 @@ + 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); +@@ -395,13 +442,8 @@ + } + + 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); + } + } + } +@@ -501,13 +543,8 @@ + } + + 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; +Index: apache2/modules/proxy/proxy_util.c +=================================================================== +--- apache2.orig/modules/proxy/proxy_util.c ++++ apache2/modules/proxy/proxy_util.c +@@ -350,8 +350,11 @@ + rp->status = HTTP_OK; + + rp->headers_in = apr_table_make(r->pool, 50); ++ rp->trailers_in = apr_table_make(r->pool, 5); ++ + rp->subprocess_env = apr_table_make(r->pool, 50); + rp->headers_out = apr_table_make(r->pool, 12); ++ rp->trailers_out = apr_table_make(r->pool, 5); + rp->err_headers_out = apr_table_make(r->pool, 5); + rp->notes = apr_table_make(r->pool, 5); + +Index: apache2/modules/proxy/mod_proxy_http.c +=================================================================== +--- apache2.orig/modules/proxy/mod_proxy_http.c ++++ apache2/modules/proxy/mod_proxy_http.c +@@ -1229,6 +1229,7 @@ + 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; + + /* +@@ -1355,6 +1356,14 @@ + #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, +@@ -1808,6 +1817,12 @@ + /* next time try a non-blocking read */ + mode = APR_NONBLOCK_READ; + ++ if (!apr_is_empty_table(rp->trailers_in)) { ++ apr_table_do(add_trailers, r->trailers_out, ++ rp->trailers_in, NULL); ++ apr_table_clear(rp->trailers_in); ++ } ++ + apr_brigade_length(bb, 0, &readbytes); + backend->worker->s->read += readbytes; + #if DEBUGGING +Index: apache2/include/httpd.h +=================================================================== +--- apache2.orig/include/httpd.h ++++ apache2/include/httpd.h +@@ -1006,6 +1006,11 @@ + * record to improve 64bit alignment the next time we need to break + * binary compatibility for some other reason. + */ ++ ++ /** MIME trailer environment from the request */ ++ apr_table_t *trailers_in; ++ /** MIME trailer environment from the response */ ++ apr_table_t *trailers_out; + }; + + /** +Index: apache2/include/http_core.h +=================================================================== +--- apache2.orig/include/http_core.h ++++ apache2/include/http_core.h +@@ -613,6 +613,10 @@ + #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; + +Index: apache2/server/protocol.c +=================================================================== +--- apache2.orig/server/protocol.c ++++ apache2/server/protocol.c +@@ -708,6 +708,8 @@ + 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; + } + +@@ -887,9 +889,11 @@ + 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); +@@ -1117,7 +1121,8 @@ + + rnew->status = HTTP_OK; + +- rnew->headers_in = apr_table_copy(rnew->pool, r->headers_in); ++ 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 +@@ -1129,6 +1134,7 @@ + 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; +Index: apache2/server/core.c +=================================================================== +--- apache2.orig/server/core.c ++++ apache2/server/core.c +@@ -542,6 +542,10 @@ + ? virt->trace_enable + : base->trace_enable; + ++ conf->merge_trailers = (virt->merge_trailers != AP_MERGE_TRAILERS_UNSET) ++ ? virt->merge_trailers ++ : base->merge_trailers; ++ + return conf; + } + +@@ -3295,6 +3299,16 @@ + return NULL; + } + ++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 + */ +@@ -3534,6 +3548,8 @@ + AP_INIT_FLAG("Suexec", unixd_set_suexec, NULL, RSRC_CONF, + "Enable or disable suEXEC support"), + #endif ++AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF, ++ "merge request trailers into request headers or not"), + { NULL } + }; + diff -Nru apache2-2.2.22/debian/patches/mod_ssl_SSL_CLIENT_S_DN_UID.diff apache2-2.2.22/debian/patches/mod_ssl_SSL_CLIENT_S_DN_UID.diff --- apache2-2.2.22/debian/patches/mod_ssl_SSL_CLIENT_S_DN_UID.diff 1970-01-01 01:00:00.000000000 +0100 +++ apache2-2.2.22/debian/patches/mod_ssl_SSL_CLIENT_S_DN_UID.diff 2014-12-23 23:26:38.000000000 +0100 @@ -0,0 +1,13 @@ +# http://svn.apache.org/viewvc?view=revision&revision=1445112 +# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=773841 +--- apache2.orig/modules/ssl/ssl_engine_vars.c ++++ apache2/modules/ssl/ssl_engine_vars.c +@@ -431,7 +431,7 @@ static const struct { + { "S", NID_surname, 1 }, + { "D", NID_description, 1 }, + #ifdef NID_userId +- { "UID", NID_x500UniqueIdentifier, 1 }, ++ { "UID", NID_userId, 1 }, + #endif + { "Email", NID_pkcs9_emailAddress, 1 }, + { NULL, 0, 0 } diff -Nru apache2-2.2.22/debian/patches/series apache2-2.2.22/debian/patches/series --- apache2-2.2.22/debian/patches/series 2014-07-23 23:26:50.000000000 +0200 +++ apache2-2.2.22/debian/patches/series 2014-12-23 23:22:05.000000000 +0100 @@ -45,3 +45,6 @@ CVE-2014-0226_scoreboard.patch CVE-2014-0231_mod_cgid-DoS.patch CVE-2014-0118_mod_deflate-DoS.patch +CVE-2013-5704_trailers.patch +SNI_case_insensitve.diff +mod_ssl_SSL_CLIENT_S_DN_UID.diff diff -Nru apache2-2.2.22/debian/patches/SNI_case_insensitve.diff apache2-2.2.22/debian/patches/SNI_case_insensitve.diff --- apache2-2.2.22/debian/patches/SNI_case_insensitve.diff 1970-01-01 01:00:00.000000000 +0100 +++ apache2-2.2.22/debian/patches/SNI_case_insensitve.diff 2014-12-23 23:09:09.000000000 +0100 @@ -0,0 +1,13 @@ +# https://svn.apache.org/viewvc?view=revision&revision=r1515565 +# http://bugs.debian.org/771199 +--- apache2.orig/modules/ssl/ssl_engine_kernel.c ++++ apache2/modules/ssl/ssl_engine_kernel.c +@@ -136,7 +136,7 @@ int ssl_hook_ReadReq(request_rec *r) + if (rv != APR_SUCCESS || scope_id) { + return HTTP_BAD_REQUEST; + } +- if (strcmp(host, servername)) { ++ if (strcasecmp(host, servername)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Hostname %s provided via SNI and hostname %s provided" + " via HTTP are different", servername, host); diff -Nru apache2-2.2.22/debian/README.Debian apache2-2.2.22/debian/README.Debian --- apache2-2.2.22/debian/README.Debian 2014-07-23 22:56:40.000000000 +0200 +++ apache2-2.2.22/debian/README.Debian 2014-12-23 23:41:18.000000000 +0100 @@ -11,6 +11,8 @@ Enabling SSL Creating self-signed certificates SSL workaround for MSIE + ECC keys and ECDH ciphers + Session ticket key life-time and forward secrecy Suexec @@ -246,6 +248,19 @@ A special compatibility fix for older Safari browsers is enabled if using an up-to-date libssl-1.0.0 (version 1.0.1e-2+deb7u8 or newer). +Session ticket key life-time and forward secrecy +------------------------------------------------ + +Apache uses TLS session tickets to improve handshake performance. By default, a +new session key key is (re-)generated at startup and at every graceful restart. +This means that an attacker that somehow gets access to the memory of the +running apache process may decrypt past connections that have used the current +session ticket key. This breaks forward secrecy even if the used cipher would +have provided forward secrecy. There is currently no way to change Apache's +behavior. If you want to mitigate this kind of attack, you should consider +increasing the frequency of graceful restarts by changing the log rotation in +/etc/logrotate.d/apache2 from weekly to daily. + Suexec ======