On Mon, Feb 1, 2016 at 10:10 AM, Joachim Achtzehnter <joac...@kraut.ca> wrote:
> The problem was first discovered with Apache 2.4.18 compiled against
> OpenSSL/1.0.1m. The running system, which is an i686 Linux system, used the
> same versions.
>
> We then installed our old mod_ssl.so from Apache 2.4.12, everything else
> unchanged, and this worked. This was enough of a hint to debug the 2.4.18
> version of the module. Before doing this, we downloaded the latest
> apr/apr-util, and OpenSSL packages, and rebuilt everything. OpenSSL is now
> at 1.0.2f. All of this was installed on the running system, and it behaved
> the same way, with some files causing the client to hang forever.

Thanks for the details.

>
> Applying the patch I included in the previous message gets it working for
> us.

This restores the previous (pre 2.4.18) behaviour of flushing output
on every read, which I'd prefer to avoid, if possible.

Could you provide some network capture (tcpdump, wireshark...) when
the lock-up occurs?
Is EnableMMap somehow always involded here (you mention it in the
original message)?
That would help to build a reproducer...

Maybe the attached patch could be "enough" to fix the issue?
This patch also includes some minimal logging (level NOTICE) to help
diagnose in case of lock-up, still.
It may be necessary to apply patch [1] before (conflict with current
2.4.x, which the attached patch is based on).

Regards,
Yann.

[1] 
http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/ssl/ssl_engine_io.c?r1=1722179&r2=1722178&pathrev=1722179&view=patch
Index: modules/ssl/ssl_engine_io.c
===================================================================
--- modules/ssl/ssl_engine_io.c	(revision 1727923)
+++ modules/ssl/ssl_engine_io.c	(working copy)
@@ -183,11 +183,19 @@ static int bio_filter_out_read(BIO *bio, char *out
     return -1;
 }
 
+static int modssl_ssl_need_flush(SSL *ssl)
+{
+#if OPENSSL_VERSION_NUMBER < 0x0009080df
+     return !SSL_is_init_finished(ssl);
+#else
+     return SSL_in_connect_init(ssl);
+#endif
+}
+
 static int bio_filter_out_write(BIO *bio, const char *in, int inl)
 {
     bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
     apr_bucket *e;
-    int need_flush;
 
     /* Abort early if the client has initiated a renegotiation. */
     if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
@@ -210,24 +218,20 @@ static int bio_filter_out_write(BIO *bio, const ch
      * not to do so correctly in some cases (< 0.9.8m; see PR 46952),
      * or on the proxy/client side (after ssl23_client_hello(), e.g.
      * ssl/proxy.t test suite).
-     *
-     * Historically, this flush call was performed only for an SSLv2
-     * connection or for a proxy connection.  Calling _out_flush can
-     * be expensive in cases where requests/reponses are pipelined,
-     * so limit the performance impact to handshake time.
      */
-#if OPENSSL_VERSION_NUMBER < 0x0009080df
-     need_flush = !SSL_is_init_finished(outctx->filter_ctx->pssl);
-#else
-     need_flush = SSL_in_connect_init(outctx->filter_ctx->pssl);
-#endif
-    if (need_flush) {
-        e = apr_bucket_flush_create(outctx->bb->bucket_alloc);
-        APR_BRIGADE_INSERT_TAIL(outctx->bb, e);
+    if (!modssl_ssl_need_flush(outctx->filter_ctx->pssl)) {
+        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, outctx->c,
+                      "bio[%pp] out: passing %d bytes", bio, inl);
+        if (bio_filter_out_pass(outctx) < 0) {
+            return -1;
+        }
     }
-
-    if (bio_filter_out_pass(outctx) < 0) {
-        return -1;
+    else {
+        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, outctx->c,
+                      "bio[%pp] out: flushing %d bytes", bio, inl);
+        if (bio_filter_out_flush(bio) < 0) {
+            return -1;
+        }
     }
 
     return inl;
@@ -468,6 +472,31 @@ static int bio_filter_in_read(BIO *bio, char *in,
 
     BIO_clear_retry_flags(bio);
 
+    /* In theory, OpenSSL should flush as necessary, but it is known
+     * not to do so correctly in some cases (< 0.9.8m; see PR 46952),
+     * or on the proxy/client side (after ssl23_client_hello(), e.g.
+     * ssl/proxy.t test suite).
+     *
+     * Historically, this flush call was performed only for an SSLv2
+     * connection or for a proxy connection.  Calling _out_flush can
+     * be expensive in cases where requests/reponses are pipelined,
+     * so limit the performance impact to handshake time.
+     */
+    if (modssl_ssl_need_flush(inctx->filter_ctx->pssl)) {
+        bio_filter_out_ctx_t *outctx = inctx->bio_out->ptr;
+        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, outctx->c,
+                      "bio[%pp] in: flushing", inctx->bio_out);
+        if (bio_filter_out_flush(inctx->bio_out) < 0) {
+            inctx->rc = outctx->rc;
+            return -1;
+        }
+    }
+    else {
+        conn_rec *c = SSL_get_app_data(inctx->filter_ctx->pssl);
+        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, c,
+                      "bio[%pp] in: not flushing", inctx->bio_out);
+    }
+
     if (!inctx->bb) {
         inctx->rc = APR_EOF;
         return -1;

Reply via email to