[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#687114: pu: package apache2/2.2.16-6+squeeze8



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu

Please review apache2_2.2.16-6+squeeze8 for inclusion in squeeze. It fixes
a minor security issue and some important bugs:

   * CVE-2012-2687: mod_negotiation: Escape filenames in variant list to
     prevent a possible XSS vulnerability for a site where untrusted users
     can upload files to a location with MultiViews enabled.
   * Send 408 status instead of 400 if reading of a request fails with a
     timeout. This allows browsers to retry. Closes: #677086
   * mod_cache: Prevent Partial Content responses from being cached and served
     as normal response. Closes: #671204
   * mpm_itk: Fix an issue where users can sometimes get spurious 403s on
     persistent connections. Closes: #672333

Full debdiff is attached.

Cheers,
Stefan
diff -u apache2-2.2.16/debian/changelog apache2-2.2.16/debian/changelog
--- apache2-2.2.16/debian/changelog
+++ apache2-2.2.16/debian/changelog
@@ -1,3 +1,17 @@
+apache2 (2.2.16-6+squeeze8) squeeze; urgency=low
+
+  * CVE-2012-2687: mod_negotiation: Escape filenames in variant list to
+    prevent a possible XSS vulnerability for a site where untrusted users
+    can upload files to a location with MultiViews enabled.
+  * Send 408 status instead of 400 if reading of a request fails with a
+    timeout. This allows browsers to retry. Closes: #677086
+  * mod_cache: Prevent Partial Content responses from being cached and served
+    as normal response. Closes: #671204
+  * mpm_itk: Fix an issue where users can sometimes get spurious 403s on
+    persistent connections. Closes: #672333
+
+ -- Stefan Fritsch <sf@debian.org>  Sun, 09 Sep 2012 23:08:04 +0200
+
 apache2 (2.2.16-6+squeeze7) squeeze-security; urgency=high
 
   * CVE-2012-0216: Remove "Alias /doc /usr/share/doc" from the default virtual
diff -u apache2-2.2.16/debian/patches/00list apache2-2.2.16/debian/patches/00list
--- apache2-2.2.16/debian/patches/00list
+++ apache2-2.2.16/debian/patches/00list
@@ -36,6 +36,9 @@
 092_CVE-2011-3607.dpatch
 093_CVE-2012-0031.dpatch
 094_CVE-2012-0053.dpatch
+095_send_408_status.dpatch
+096_mod_cache_partial_content-2.2.x.dpatch
+097_CVE-2012-2687.dpatch
 099_config_guess_sub_update
 200_cp_suexec.dpatch
 201_build_suexec-custom.dpatch
diff -u apache2-2.2.16/debian/mpm-itk/patches/series apache2-2.2.16/debian/mpm-itk/patches/series
--- apache2-2.2.16/debian/mpm-itk/patches/series
+++ apache2-2.2.16/debian/mpm-itk/patches/series
@@ -10,0 +11 @@
+11-fix-htaccess-reads-for-persistent-connections.patch
only in patch2:
unchanged:
--- apache2-2.2.16.orig/debian/patches/097_CVE-2012-2687.dpatch
+++ apache2-2.2.16/debian/patches/097_CVE-2012-2687.dpatch
@@ -0,0 +1,20 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: low impact XSS in mod_negotiation
+## DP: backport of upstream r1374421
+diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c
+index 25e6034..ef4a72a 100644
+--- a/modules/mappers/mod_negotiation.c
++++ b/modules/mappers/mod_negotiation.c
+@@ -2658,9 +2658,9 @@ static char *make_variant_list(request_rec *r, negotiation_state *neg)
+          * need to change the calculation of max_vlist_array above.
+          */
+         *((const char **) apr_array_push(arr)) = "<li><a href=\"";
+-        *((const char **) apr_array_push(arr)) = filename;
++        *((const char **) apr_array_push(arr)) = ap_escape_path_segment(r->pool, filename);
+         *((const char **) apr_array_push(arr)) = "\">";
+-        *((const char **) apr_array_push(arr)) = filename;
++        *((const char **) apr_array_push(arr)) = ap_escape_html(r->pool, filename);
+         *((const char **) apr_array_push(arr)) = "</a> ";
+         *((const char **) apr_array_push(arr)) = description;
+ 
only in patch2:
unchanged:
--- apache2-2.2.16.orig/debian/patches/095_send_408_status.dpatch
+++ apache2-2.2.16/debian/patches/095_send_408_status.dpatch
@@ -0,0 +1,170 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: backport of upstream r1100200, debian bug #677086
+#
+#commit 590aa99baedb5ae15305e593384f98998ca883fe
+#Author: Eric Covener <covener@apache.org>
+#Date:   Fri May 6 13:14:27 2011 +0000
+#
+#    Merge r820760, r919323, r937858, r938265 from trunk:
+#    
+#    Reviewed By: sf, trawick, covener
+#    
+#        core: Treat timeout reading request as 408 error, not 400.
+#        Log 408 errors in access log as was done in Apache 1.3.x.
+#    
+#        PR: 39785
+#        Submitted by: Nobutaka Mantani, Stefan Fritsch
+#        Reviewed and added to by: Dan Poirier
+#    
+#    
+#        * Only log a 408 if it is no keepalive timeout.
+#    
+#        PR: 39785
+#        Submitted by: Mark Montague <markmont umich.edu>, rpluem
+#        Reviewed by: rpluem
+#    
+#    
+#        PR49167, unexpected 413 and double-errordoc during a timeout reading a
+#        chunk-size.
+#    
+#    
+#    
+#        Use the more specific 408 (timed out) instead of a generic 400 during a timeout
+#        reading a chunk-length.
+#    
+#    
+#    
+#    
+#    git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1100200 13f79535-47bb-0310-9956-ffa450edef68
+#
+#diff --git a/CHANGES b/CHANGES
+#index 9cc3ee3..1fe363f 100644
+#--- a/CHANGES
+#+++ b/CHANGES
+#@@ -1,6 +1,19 @@
+#                                                          -*- coding: utf-8 -*-
+# Changes with Apache 2.2.18
+# 
+#+  *) Log an error for failures to read a chunk-size, and return 408 instead
+#+     413 when this is due to a read timeout.  This change also fixes some cases 
+#+     of two error documents being sent in the response for the same scenario. 
+#+     [Eric Covener] PR49167
+#+
+#+  *) core: Only log a 408 if it is no keepalive timeout. PR 39785
+#+     [Ruediger Pluem,  Mark Montague <markmont umich.edu>]
+#+
+#+  *) core: Treat timeout reading request as 408 error, not 400.
+#+     Log 408 errors in access log as was done in Apache 1.3.x.
+#+     PR 39785 [Nobutaka Mantani <nobutaka nobutaka.org>, Stefan Fritsch,
+#+     Dan Poirier]
+#+
+#   *) Core HTTP: disable keepalive when the Client has sent
+#      Expect: 100-continue
+#      but we respond directly with a non-100 response.  Keepalive here led
+diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
+index b429989..1aed70b 100644
+--- a/modules/http/http_filters.c
++++ b/modules/http/http_filters.c
+@@ -384,8 +384,13 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ 
+             /* Detect chunksize error (such as overflow) */
+             if (rv != APR_SUCCESS || ctx->remaining < 0) {
++                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "Error reading first chunk %s ", 
++                              (ctx->remaining < 0) ? "(overflow)" : "");
+                 ctx->remaining = 0; /* Reset it in case we have to
+                                      * come back here later */
++                if (APR_STATUS_IS_TIMEUP(rv)) { 
++                    http_error = HTTP_REQUEST_TIME_OUT;
++                }
+                 return bail_out_on_error(ctx, f, http_error);
+             }
+ 
+@@ -485,10 +490,14 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ 
+                 /* Detect chunksize error (such as overflow) */
+                 if (rv != APR_SUCCESS || ctx->remaining < 0) {
++                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "Error reading chunk %s ", 
++                                  (ctx->remaining < 0) ? "(overflow)" : "");
+                     ctx->remaining = 0; /* Reset it in case we have to
+                                          * come back here later */
+-                    bail_out_on_error(ctx, f, http_error);
+-                    return rv;
++                    if (APR_STATUS_IS_TIMEUP(rv)) { 
++                        http_error = HTTP_REQUEST_TIME_OUT;
++                    }
++                    return bail_out_on_error(ctx, f, http_error);
+                 }
+ 
+                 if (!ctx->remaining) {
+diff --git a/server/protocol.c b/server/protocol.c
+index 9851360..62d8baf 100644
+--- a/server/protocol.c
++++ b/server/protocol.c
+@@ -608,6 +608,9 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
+                 r->proto_num = HTTP_VERSION(1,0);
+                 r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");
+             }
++            else if (rv == APR_TIMEUP) {
++                r->status = HTTP_REQUEST_TIME_OUT;
++            }
+             return 0;
+         }
+     } while ((len <= 0) && (++num_blank_lines < max_blank_lines));
+@@ -691,7 +694,12 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb
+                          &len, r, 0, bb);
+ 
+         if (rv != APR_SUCCESS) {
+-            r->status = HTTP_BAD_REQUEST;
++            if (rv == APR_TIMEUP) {
++                r->status = HTTP_REQUEST_TIME_OUT;
++            }
++            else {
++                r->status = HTTP_BAD_REQUEST;
++            }
+ 
+             /* ap_rgetline returns APR_ENOSPC if it fills up the buffer before
+              * finding the end-of-line.  This is only going to happen if it
+@@ -877,7 +885,7 @@ request_rec *ap_read_request(conn_rec *conn)
+     r->read_length     = 0;
+     r->read_body       = REQUEST_NO_BODY;
+ 
+-    r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
++    r->status          = HTTP_OK;  /* Until further notice */
+     r->the_request     = NULL;
+ 
+     /* Begin by presuming any module can make its own path_info assumptions,
+@@ -898,6 +906,14 @@ request_rec *ap_read_request(conn_rec *conn)
+             apr_brigade_destroy(tmp_bb);
+             return r;
+         }
++        else if (r->status == HTTP_REQUEST_TIME_OUT) {
++            ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
++            if (!r->connection->keepalives) {
++                ap_run_log_transaction(r);
++            }
++            apr_brigade_destroy(tmp_bb);
++            return r;
++        }
+ 
+         apr_brigade_destroy(tmp_bb);
+         return NULL;
+@@ -916,7 +932,7 @@ request_rec *ap_read_request(conn_rec *conn)
+ 
+     if (!r->assbackwards) {
+         ap_get_mime_headers_core(r, tmp_bb);
+-        if (r->status != HTTP_REQUEST_TIME_OUT) {
++        if (r->status != HTTP_OK) {
+             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                           "request failed: error reading the headers");
+             ap_send_error_response(r, 0);
+@@ -957,8 +973,6 @@ request_rec *ap_read_request(conn_rec *conn)
+ 
+     apr_brigade_destroy(tmp_bb);
+ 
+-    r->status = HTTP_OK;                         /* Until further notice. */
+-
+     /* update what we think the virtual host is based on the headers we've
+      * now read. may update status.
+      */
only in patch2:
unchanged:
--- apache2-2.2.16.orig/debian/patches/096_mod_cache_partial_content-2.2.x.dpatch
+++ apache2-2.2.16/debian/patches/096_mod_cache_partial_content-2.2.x.dpatch
@@ -0,0 +1,74 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Add r1343951 from upstream branch 2.2.x
+## DP: Debian bug #671204
+
+*) mod_disk_cache, mod_mem_cache: Decline the opportunity to cache if the
+   response is a 206 Partial Content. This stops a reverse proxied partial
+   response from becoming cached, and then being served in subsequent
+   responses. [Graham Leggett]
+
+
+Index: a/modules/cache/mod_cache.c
+===================================================================
+--- a/modules/cache/mod_cache.c	(revision 1176912)
++++ a/modules/cache/mod_cache.c	(working copy)
+@@ -473,7 +473,8 @@
+          * We include 304 Not Modified here too as this is the origin server
+          * telling us to serve the cached copy.
+          */
+-        if (exps != NULL || cc_out != NULL) {
++        if ((exps != NULL || cc_out != NULL)
++            && r->status != HTTP_PARTIAL_CONTENT) {
+             /* We are also allowed to cache any response given that it has a
+              * valid Expires or Cache Control header. If we find a either of
+              * those here,  we pass request through the rest of the tests. From
+@@ -486,6 +487,9 @@
+              * include the following: an Expires header (section 14.21); a
+              * "max-age", "s-maxage",  "must-revalidate", "proxy-revalidate",
+              * "public" or "private" cache-control directive (section 14.9).
++             *
++             * But do NOT store 206 responses in any case since we
++             * don't (yet) cache partial responses.
+              */
+         }
+         else {
+Index: modules/cache/mod_mem_cache.c
+===================================================================
+--- a/modules/cache/mod_mem_cache.c	(revision 1176912)
++++ a/modules/cache/mod_mem_cache.c	(working copy)
+@@ -313,6 +313,14 @@
+     cache_object_t *obj, *tmp_obj;
+     mem_cache_object_t *mobj;
+ 
++    /* we don't support caching of range requests (yet) */
++    if (r->status == HTTP_PARTIAL_CONTENT) {
++        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
++                     "disk_cache: URL %s partial content response not cached",
++                     key);
++        return DECLINED;
++    }
++
+     if (len == -1) {
+         /* Caching a streaming response. Assume the response is
+          * less than or equal to max_streaming_buffer_size. We will
+Index: modules/cache/mod_disk_cache.c
+===================================================================
+--- a/modules/cache/mod_disk_cache.c	(revision 1176912)
++++ a/modules/cache/mod_disk_cache.c	(working copy)
+@@ -330,6 +330,14 @@
+         return DECLINED;
+     }
+ 
++    /* we don't support caching of range requests (yet) */
++    if (r->status == HTTP_PARTIAL_CONTENT) {
++        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
++                     "disk_cache: URL %s partial content response not cached",
++                     key);
++        return DECLINED;
++    }
++
+     /* Allocate and initialize cache_object_t and disk_cache_object_t */
+     h->cache_obj = obj = apr_pcalloc(r->pool, sizeof(*obj));
+     obj->vobj = dobj = apr_pcalloc(r->pool, sizeof(*dobj));
only in patch2:
unchanged:
--- apache2-2.2.16.orig/debian/mpm-itk/patches/11-fix-htaccess-reads-for-persistent-connections.patch
+++ apache2-2.2.16/debian/mpm-itk/patches/11-fix-htaccess-reads-for-persistent-connections.patch
@@ -0,0 +1,45 @@
+Fix an issue where users can sometimes get spurious 403s on persistent
+connections (the description in the comments explains the logic).
+This would particularly hit people with reverse proxies, since these
+have a higher tendency of accessing things from different vhosts in
+the same connection.
+
+Index: httpd-2.2.17/server/config.c
+===================================================================
+--- httpd-2.2.17.orig/server/config.c
++++ httpd-2.2.17/server/config.c
+@@ -1840,6 +1840,34 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(a
+         else {
+             if (!APR_STATUS_IS_ENOENT(status)
+                 && !APR_STATUS_IS_ENOTDIR(status)) {
++#ifdef ITK_MPM
++                /*
++                 * If we are in a persistent connection, we might end up in a state
++                 * where we can no longer read .htaccess files because we have already
++                 * setuid(). This can either be because the previous request was for
++                 * another vhost (basically the same problem as when setuid() fails in
++                 * itk.c), or it can be because a .htaccess file is readable only by
++                 * root.
++                 *
++                 * In any case, we don't want to give out a 403, since the request has
++                 * a very real chance of succeeding on a fresh connection (where
++                 * presumably uid=0). Thus, we give up serving the request on this
++                 * TCP connection, and do a hard close of the socket. As long as we're
++                 * in a persistent connection (and there _should_ not be a way this
++                 * would happen on the first request in a connection, save for subrequests,
++                 * which we special-case), this is allowed, as it is what happens on
++                 * a timeout. The browser will simply open a new connection and try
++                 * again (there's of course a performance hit, though, both due to
++                 * the new connection setup and the fork() of a new server child).
++                 */
++                if (r->main == NULL && getuid() != 0) {
++                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, status, r,
++                                  "Couldn't read %s, closing connection.",
++                                  filename);
++                    ap_lingering_close(r->connection);
++                    exit(0);
++                }
++#endif          
+                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r,
+                               "%s pcfg_openfile: unable to check htaccess file, "
+                               "ensure it is readable",

Reply to: