Index: net/android/keystore_openssl.cc |
diff --git a/net/android/keystore_openssl.cc b/net/android/keystore_openssl.cc |
index afdca30de0d772d51261d9dfa7dbda242374e0bf..38fa46b846ac9e15861226d166bb9cad9ff52ff6 100644 |
--- a/net/android/keystore_openssl.cc |
+++ b/net/android/keystore_openssl.cc |
@@ -310,6 +310,44 @@ bool GetRsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) { |
return true; |
} |
+// On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not |
+// added to the global engine list. If all references to it are dropped, OpenSSL |
+// will dlclose the module, leaving a dangling function pointer in the RSA |
+// CRYPTO_EX_DATA class. To work around this, leak an extra reference to the |
+// ENGINE we extract in GetRsaLegacyKey. |
+// |
+// In 4.2, this change avoids the problem: |
+// https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1dddbe73ca5cb3d61 |
+// |
+// https://crbug.com/381465 |
+class KeystoreEngineWorkaround { |
+public: |
Ryan Sleevi
2014/06/17 21:55:37
indent 1 space
davidben
2014/06/17 23:43:18
Done.
|
+ KeystoreEngineWorkaround() : leaked_(false) {} |
+ |
+ void LeakRsaEngine(EVP_PKEY* pkey) { |
+ if (leaked_) |
+ return; |
+ ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey)); |
+ if (!rsa.get() || |
+ !rsa.get()->engine || |
+ strcmp(ENGINE_get_id(rsa.get()->engine), "keystore") || |
+ !ENGINE_init(rsa.get()->engine)) { |
Ryan Sleevi
2014/06/17 21:55:37
Don't use get()-> for operator->
Don't use get() f
davidben
2014/06/17 23:43:17
ScopedOpenSSL doesn't actually provide a whole lot
|
+ NOTREACHED(); |
+ return; |
+ } |
+ leaked_ = true; |
+ } |
+ |
+private: |
Ryan Sleevi
2014/06/17 21:55:37
indent 1 space
davidben
2014/06/17 23:43:17
Done.
|
+ bool leaked_; |
Ryan Sleevi
2014/06/17 21:55:37
s/leaked_/leaked_engine_/ perhaps?
Just so it's c
davidben
2014/06/17 23:43:17
Done.
|
+}; |
+ |
+void LeakRsaEngine(EVP_PKEY* pkey) { |
+ static base::LazyInstance<KeystoreEngineWorkaround> s_instance = |
Ryan Sleevi
2014/06/17 21:55:37
this should be a ::Leaky lazy instance
davidben
2014/06/17 23:43:18
Done.
|
+ LAZY_INSTANCE_INITIALIZER; |
+ s_instance.Get().LeakRsaEngine(pkey); |
+} |
+ |
// Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object |
// for Android 4.0 to 4.1.x. Must only be used on Android < 4.2. |
// |private_key| is a JNI reference (local or global) to the object. |
@@ -320,6 +358,7 @@ EVP_PKEY* GetRsaLegacyKey(jobject private_key) { |
GetOpenSSLSystemHandleForPrivateKey(private_key); |
if (sys_pkey != NULL) { |
CRYPTO_add(&sys_pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); |
+ LeakRsaEngine(sys_pkey); |
} else { |
// GetOpenSSLSystemHandleForPrivateKey() will fail on Android |
// 4.0.3 and earlier. However, it is possible to get the key |