Workaround a leak in OpenSSL 1.0.0

This fixes another leak seen occasionally as a flaky test on RHEL 6:

Direct leak of 56 byte(s) in 1 object(s) allocated from:
    #2 0x7f21e5fe037c in CRYPTO_malloc src/openssl/crypto/mem.c:306
    #3 0x7f21e607f45c in EVP_PKEY_new src/openssl/crypto/evp/p_lib.c:186
    #4 0x7f21e608ff33 in X509_PUBKEY_get src/openssl/crypto/asn1/x_pubkey.c:147
    #5 0x7f21e60b23ad in X509_get_pubkey src/openssl/crypto/x509/x509_cmp.c:292
    #6 0x7f21e60b623d in internal_verify src/openssl/crypto/x509/x509_vfy.c:1624
    #7 0x7f21e60b3b8b in X509_verify_cert src/openssl/crypto/x509/x509_vfy.c:372
    #8 0x7f21e5d5c096 in ssl_verify_cert_chain src/openssl/ssl/ssl_cert.c:535
    #9 0x7f21e5d34157 in ssl3_get_server_certificate 
src/openssl/ssl/s3_clnt.c:1047
    #10 0x7f21e5d3289f in ssl3_connect src/openssl/ssl/s3_clnt.c:310
    #11 0x7f21e5d5705b in SSL_connect src/openssl/ssl/ssl_lib.c:933
    #12 0x7f21e5d43340 in ssl23_get_server_hello src/openssl/ssl/s23_clnt.c:693
    #13 0x7f21e5d422b0 in ssl23_connect src/openssl/ssl/s23_clnt.c:222
    #14 0x7f21e5d59f46 in SSL_do_handshake src/openssl/ssl/ssl_lib.c:2380
    #15 0x7f21e6a028a7 in kudu::security::TlsHandshake::Continue(std::string 
const&, std::string*) src/kudu/security/tls_handshake.cc:92:12

The issue turned out to be an OpenSSL 1.0.0 bug that was since fixed. But,
since we build/test against OpenSSL 1.0.0 on el6, we hit the leak.

This patch has a workaround - see the included comment for details.

Before the patch, all_types-itest failed about 10% of the time in dist-test,
and now passes reliably.

Change-Id: I65fe981c523f6fe73b3668bfb2f30a95ebf3e759
Reviewed-on: http://gerrit.cloudera.org:8080/6197
Reviewed-by: Dan Burkert <[email protected]>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/0609277c
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/0609277c
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/0609277c

Branch: refs/heads/master
Commit: 0609277c4209c02fd94d7c6fd6c23abd8b1d3b67
Parents: f726f6a
Author: Todd Lipcon <[email protected]>
Authored: Tue Feb 28 18:53:35 2017 -0800
Committer: Todd Lipcon <[email protected]>
Committed: Wed Mar 1 18:57:13 2017 +0000

----------------------------------------------------------------------
 src/kudu/security/tls_context.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/0609277c/src/kudu/security/tls_context.cc
----------------------------------------------------------------------
diff --git a/src/kudu/security/tls_context.cc b/src/kudu/security/tls_context.cc
index 28c8e0e..17b7f69 100644
--- a/src/kudu/security/tls_context.cc
+++ b/src/kudu/security/tls_context.cc
@@ -223,6 +223,22 @@ Status TlsContext::UseCertificateAndKey(const Cert& cert, 
const PrivateKey& key)
 Status TlsContext::AddTrustedCertificate(const Cert& cert) {
   VLOG(2) << "Trusting certificate " << cert.SubjectName();
 
+  {
+    // Workaround for a leak in OpenSSL <1.0.1:
+    //
+    // If we start trusting a cert, and its internal public-key field hasn't
+    // yet been populated, then the first time it's used for verification will
+    // populate it. In the case that two threads try to populate it at the 
same time,
+    // one of the thread's copies will be leaked.
+    //
+    // To avoid triggering the race, we populate the internal public key cache
+    // field up front before adding it to the trust store.
+    //
+    // See OpenSSL commit 33a688e80674aaecfac6d9484ec199daa0ee5b61.
+    PublicKey k;
+    CHECK_OK(cert.GetPublicKey(&k));
+  }
+
   unique_lock<RWMutex> lock(lock_);
   ERR_clear_error();
   auto* cert_store = SSL_CTX_get_cert_store(ctx_.get());

Reply via email to