From f615bda33ed9381b6bb3b0218c6ab5f0393664be Mon Sep 17 00:00:00 2001 From: "willchan@chromium.org" Date: Sun, 21 Nov 2010 01:04:56 +0000 Subject: Leak NSS to prevent shutdown crashes. NSS can be used by non-joinable threads (worker threads). These can access it after ~AtExitManager has already triggered the NSS shutdown code, so we can crash on shutdown. Therefore we leak NSS. BUG=61585 TEST=existing Review URL: http://codereview.chromium.org/5240001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66904 0039d316-1c4b-4281-b951-d872f2087c98 --- base/nss_util.cc | 133 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 59 deletions(-) (limited to 'base') diff --git a/base/nss_util.cc b/base/nss_util.cc index fd91142..580fb60 100644 --- a/base/nss_util.cc +++ b/base/nss_util.cc @@ -19,8 +19,8 @@ #endif #include "base/file_util.h" +#include "base/lazy_instance.h" #include "base/logging.h" -#include "base/singleton.h" #include "base/stringprintf.h" #include "base/thread_restrictions.h" @@ -83,7 +83,7 @@ void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) { struct statfs buf; if (statfs(database_dir.value().c_str(), &buf) == 0) { if (buf.f_type == NFS_SUPER_MAGIC) { - scoped_ptr env(base::Environment::Create()); + scoped_ptr env(Environment::Create()); const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; if (!env->HasVar(use_cache_env_var)) env->SetVar(use_cache_env_var, "yes"); @@ -111,12 +111,19 @@ SECMODModule *InitDefaultRootCerts() { // A singleton to initialize/deinitialize NSPR. // Separate from the NSS singleton because we initialize NSPR on the UI thread. +// Now that we're leaking the singleton, we could merge back with the NSS +// singleton. class NSPRInitSingleton { - public: + private: + friend struct DefaultLazyInstanceTraits; + NSPRInitSingleton() { PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); } + // NOTE(willchan): We don't actually execute this code since we leak NSS to + // prevent non-joinable threads from using NSS after it's already been shut + // down. ~NSPRInitSingleton() { PL_ArenaFinish(); PRStatus prstatus = PR_Cleanup(); @@ -126,14 +133,59 @@ class NSPRInitSingleton { } }; +LazyInstance > + g_nspr_singleton(LINKER_INITIALIZED); + class NSSInitSingleton { public: +#if defined(OS_CHROMEOS) + void OpenPersistentNSSDB() { + if (!chromeos_user_logged_in_) { + chromeos_user_logged_in_ = true; + real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(), + "Real NSS database"); + } + } +#endif // defined(OS_CHROMEOS) + + bool OpenTestNSSDB(const FilePath& path, const char* description) { + test_db_slot_ = OpenUserDB(path, description); + return !!test_db_slot_; + } + + void CloseTestNSSDB() { + if (test_db_slot_) { + SECStatus status = SECMOD_CloseUserDB(test_db_slot_); + if (status != SECSuccess) + LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); + PK11_FreeSlot(test_db_slot_); + test_db_slot_ = NULL; + } + } + + PK11SlotInfo* GetDefaultKeySlot() { + if (test_db_slot_) + return PK11_ReferenceSlot(test_db_slot_); + if (real_db_slot_) + return PK11_ReferenceSlot(real_db_slot_); + return PK11_GetInternalKeySlot(); + } + +#if defined(USE_NSS) + Lock* write_lock() { + return &write_lock_; + } +#endif // defined(USE_NSS) + + private: + friend struct DefaultLazyInstanceTraits; + NSSInitSingleton() : real_db_slot_(NULL), test_db_slot_(NULL), root_(NULL), chromeos_user_logged_in_(false) { - base::EnsureNSPRInit(); + EnsureNSPRInit(); // We *must* have NSS >= 3.12.3. See bug 26448. COMPILE_ASSERT( @@ -207,15 +259,13 @@ class NSSInitSingleton { PK11_FreeSlot(slot); } - // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 - // is fixed, we will no longer need the lock. We should detect this and not - // initialize a Lock here. - write_lock_.reset(new Lock()); - root_ = InitDefaultRootCerts(); #endif // !defined(USE_NSS) } + // NOTE(willchan): We don't actually execute this code since we leak NSS to + // prevent non-joinable threads from using NSS after it's already been shut + // down. ~NSSInitSingleton() { if (real_db_slot_) { SECMOD_CloseUserDB(real_db_slot_); @@ -238,46 +288,6 @@ class NSSInitSingleton { } } -#if defined(OS_CHROMEOS) - void OpenPersistentNSSDB() { - if (!chromeos_user_logged_in_) { - chromeos_user_logged_in_ = true; - real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(), - "Real NSS database"); - } - } -#endif // defined(OS_CHROMEOS) - - bool OpenTestNSSDB(const FilePath& path, const char* description) { - test_db_slot_ = OpenUserDB(path, description); - return !!test_db_slot_; - } - - void CloseTestNSSDB() { - if (test_db_slot_) { - SECStatus status = SECMOD_CloseUserDB(test_db_slot_); - if (status != SECSuccess) - LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); - PK11_FreeSlot(test_db_slot_); - test_db_slot_ = NULL; - } - } - - PK11SlotInfo* GetDefaultKeySlot() { - if (test_db_slot_) - return PK11_ReferenceSlot(test_db_slot_); - if (real_db_slot_) - return PK11_ReferenceSlot(real_db_slot_); - return PK11_GetInternalKeySlot(); - } - -#if defined(USE_NSS) - Lock* write_lock() { - return write_lock_.get(); - } -#endif // defined(USE_NSS) - - private: static PK11SlotInfo* OpenUserDB(const FilePath& path, const char* description) { const std::string modspec = @@ -300,35 +310,40 @@ class NSSInitSingleton { SECMODModule *root_; bool chromeos_user_logged_in_; #if defined(USE_NSS) - scoped_ptr write_lock_; + // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 + // is fixed, we will no longer need the lock. + Lock write_lock_; #endif // defined(USE_NSS) }; +LazyInstance > + g_nss_singleton(LINKER_INITIALIZED); + } // namespace void EnsureNSPRInit() { - Singleton::get(); + g_nspr_singleton.Get(); } void EnsureNSSInit() { // Initializing SSL causes us to do blocking IO. // Temporarily allow it until we fix // http://code.google.com/p/chromium/issues/detail?id=59847 - base::ThreadRestrictions::ScopedAllowIO allow_io; - Singleton::get(); + ThreadRestrictions::ScopedAllowIO allow_io; + g_nss_singleton.Get(); } #if defined(USE_NSS) bool OpenTestNSSDB(const FilePath& path, const char* description) { - return Singleton::get()->OpenTestNSSDB(path, description); + return g_nss_singleton.Get().OpenTestNSSDB(path, description); } void CloseTestNSSDB() { - Singleton::get()->CloseTestNSSDB(); + g_nss_singleton.Get().CloseTestNSSDB(); } Lock* GetNSSWriteLock() { - return Singleton::get()->write_lock(); + return g_nss_singleton.Get().write_lock(); } AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { @@ -347,7 +362,7 @@ AutoNSSWriteLock::~AutoNSSWriteLock() { #if defined(OS_CHROMEOS) void OpenPersistentNSSDB() { - Singleton::get()->OpenPersistentNSSDB(); + g_nss_singleton.Get().OpenPersistentNSSDB(); } #endif @@ -357,7 +372,7 @@ Time PRTimeToBaseTime(PRTime prtime) { PRExplodedTime prxtime; PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); - base::Time::Exploded exploded; + Time::Exploded exploded; exploded.year = prxtime.tm_year; exploded.month = prxtime.tm_month + 1; exploded.day_of_week = prxtime.tm_wday; @@ -371,7 +386,7 @@ Time PRTimeToBaseTime(PRTime prtime) { } PK11SlotInfo* GetDefaultNSSKeySlot() { - return Singleton::get()->GetDefaultKeySlot(); + return g_nss_singleton.Get().GetDefaultKeySlot(); } } // namespace base -- cgit v1.1