]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r891282 from trunk:
authorRuediger Pluem <rpluem@apache.org>
Thu, 7 Jan 2010 15:11:53 +0000 (15:11 +0000)
committerRuediger Pluem <rpluem@apache.org>
Thu, 7 Jan 2010 15:11:53 +0000 (15:11 +0000)
Further mitigation for the TLS renegotation attack, CVE-2009-3555:

* modules/ssl/ssl_engine_kernel.c (has_buffered_data): New function.
  (ssl_hook_Access): Forcibly disable keepalive for the connection if
  there is any buffered data readable from the input filter stack.

* modules/ssl/ssl_engine_io.c (ssl_io_filter_input): Ensure that the
  BIO uses blocking operations when invoked outside direct control of
  the httpd filter stack.

Thanks to Hartmut Keil <Hartmut.Keil adnovum.ch> for proposing this
technique.

Submitted by: jorton
Reviewed by: rpluem, jim, trawick

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@896900 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
modules/ssl/ssl_engine_io.c
modules/ssl/ssl_engine_kernel.c

diff --git a/CHANGES b/CHANGES
index 85e4d91a16a970c93f154a53f41b1715bdea7856..b22514f5247bacb0846b138f754168fef2d34f80 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -3,10 +3,11 @@ Changes with Apache 2.2.15
 
   *) SECURITY: CVE-2009-3555 (cve.mitre.org)
      A partial fix for the TLS renegotiation prefix injection attack by
-     rejecting any client-initiated renegotiations.  Any configuration
-     which requires renegotiation for per-directory/location access 
-     control is still vulnerable, unless using OpenSSL >= 0.9.8l.  
-     [Joe Orton, Ruediger Pluem]
+     rejecting any client-initiated renegotiations. Forcibly disable keepalive
+     for the connection if there is any buffered data readable. Any
+     configuration which requires renegotiation for per-directory/location
+     access control is still vulnerable, unless using OpenSSL >= 0.9.8l.
+     [Joe Orton, Ruediger Pluem, Hartmut Keil <Hartmut.Keil adnovum.ch>]
 
   *) mod_filter: fix FilterProvider matching where "dispatch" string
      doesn't exist.
diff --git a/STATUS b/STATUS
index 0c38b4e0ddab61143b62af68c59bf10738e40fa4..782abeaacab03f3d9cd8cd25fa8c5d481f5ab5c6 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -87,12 +87,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  * mod_ssl: Further mitigation for the TLS renegotation attack, CVE-2009-3555
-      Trunk version of patch:
-         http://svn.apache.org/viewcvs.cgi?rev=891282&view=rev
-      Backport version for 2.2.x of patch:
-         Trunk version of patch works
-      +1: rpluem, jim, trawick
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]
index 985661dd9fdbc10be3d09ed6b81cca35cf80be0a..725367022695ed3e7bf22953fc3d2cedaf07dd56 100644 (file)
@@ -1371,9 +1371,17 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f,
     }
     else {
         /* We have no idea what you are talking about, so return an error. */
-        return APR_ENOTIMPL;
+        status = APR_ENOTIMPL;
     }
 
+    /* It is possible for mod_ssl's BIO to be used outside of the
+     * direct control of mod_ssl's input or output filter -- notably,
+     * when mod_ssl initiates a renegotiation.  Switching the BIO mode
+     * back to "blocking" here ensures such operations don't fail with
+     * SSL_ERROR_WANT_READ. */
+    inctx->block = APR_BLOCK_READ;
+
+    /* Handle custom errors. */
     if (status != APR_SUCCESS) {
         return ssl_io_filter_error(f, bb, status);
     }
index f0e2cb00f86c2fd0dfae7b15e0c465802c6f8ddf..f0e051d0964e60c674ed10ee9dd0513a2bf30a1c 100644 (file)
@@ -35,6 +35,29 @@ static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
 static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s);
 #endif
 
+/* Perform a speculative (and non-blocking) read from the connection
+ * filters for the given request, to determine whether there is any
+ * pending data to read.  Return non-zero if there is, else zero. */
+static int has_buffered_data(request_rec *r) 
+{
+    apr_bucket_brigade *bb;
+    apr_off_t len;
+    apr_status_t rv;
+    int result;
+    
+    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    
+    rv = ap_get_brigade(r->connection->input_filters, bb, AP_MODE_SPECULATIVE,
+                        APR_NONBLOCK_READ, 1); 
+    result = rv == APR_SUCCESS
+        && apr_brigade_length(bb, 1, &len) == APR_SUCCESS
+        && len > 0;
+    
+    apr_brigade_destroy(bb);
+    
+    return result;
+}
+
 /*
  *  Post Read Request Handler
  */
@@ -720,6 +743,23 @@ int ssl_hook_Access(request_rec *r)
         else {
             request_rec *id = r->main ? r->main : r;
 
+            /* Additional mitigation for CVE-2009-3555: At this point,
+             * before renegotiating, an (entire) request has been read
+             * from the connection.  An attacker may have sent further
+             * data to "prefix" any subsequent request by the victim's
+             * client after the renegotiation; this data may already
+             * have been read and buffered.  Forcing a connection
+             * closure after the response ensures such data will be
+             * discarded.  Legimately pipelined HTTP requests will be
+             * retried anyway with this approach. */
+            if (has_buffered_data(r)) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "insecure SSL re-negotiation required, but "
+                              "a pipelined request is present; keepalive "
+                              "disabled");
+                r->connection->keepalive = AP_CONN_CLOSE;
+            }
+
             /* do a full renegotiation */
             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                           "Performing full renegotiation: "