Bug 769288 - Part 5: Close private socket connections when the lsat private browsing instance dies. r=bsmith,mcmanus
☠☠ backed out by 553a3bcf1fe7 ☠ ☠
authorJosh Matthews <josh@joshmatthews.net>
Fri, 07 Dec 2012 17:50:43 -0500
changeset 115624 6d8d78bd56a972dd3bf51472192d09f173643278
parent 115623 e75cd1e1fca33d040197fd6c752703bb88651456
child 115625 912331d0c2fd6adce51501b5eff32557fc1845a5
push idunknown
push userunknown
push dateunknown
reviewersbsmith, mcmanus
bugs769288
milestone20.0a1
Bug 769288 - Part 5: Close private socket connections when the lsat private browsing instance dies. r=bsmith,mcmanus
netwerk/base/public/nsASocketHandler.h
netwerk/base/src/nsSocketTransport2.cpp
netwerk/base/src/nsSocketTransportService2.cpp
netwerk/base/src/nsSocketTransportService2.h
security/manager/ssl/src/Makefile.in
security/manager/ssl/src/PublicSSL.h
security/manager/ssl/src/SharedSSLState.cpp
security/manager/ssl/src/SharedSSLState.h
security/manager/ssl/src/nsCertOverrideService.cpp
security/manager/ssl/src/nsNSSCertificateDB.cpp
security/manager/ssl/src/nsNSSCertificateDB.h
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsRecentBadCerts.cpp
security/manager/ssl/src/nsRecentBadCerts.h
--- a/netwerk/base/public/nsASocketHandler.h
+++ b/netwerk/base/public/nsASocketHandler.h
@@ -10,16 +10,17 @@
 
 class nsASocketHandler : public nsISupports
 {
 public:
     nsASocketHandler()
         : mCondition(NS_OK)
         , mPollFlags(0)
         , mPollTimeout(UINT16_MAX)
+        , mIsPrivate(false)
         {}
 
     //
     // this condition variable will be checked to determine if the socket
     // handler should be detached.  it must only be accessed on the socket
     // thread.
     //
     nsresult mCondition;
@@ -37,16 +38,18 @@ public:
     // then OnSocketReady will be called with outFlags = -1.
     //
     // the default value for this member is UINT16_MAX, which disables the
     // timeout error checking.  (i.e., a timeout value of UINT16_MAX is
     // never reached.)
     //
     uint16_t mPollTimeout;
 
+    bool mIsPrivate;
+
     //
     // called to service a socket
     // 
     // params:
     //   socketRef - socket identifier
     //   fd        - socket file descriptor
     //   outFlags  - value of PR_PollDesc::out_flags after PR_Poll returns
     //               or -1 if a timeout occurred
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -2201,16 +2201,17 @@ nsSocketTransport::GetConnectionFlags(ui
     *value = mConnectionFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSocketTransport::SetConnectionFlags(uint32_t value)
 {
     mConnectionFlags = value;
+    mIsPrivate = value & nsISocketTransport::NO_PERMANENT_STORAGE;
     return NS_OK;
 }
 
 
 #ifdef ENABLE_SOCKET_TRACING
 
 #include <stdio.h>
 #include <ctype.h>
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -18,25 +18,17 @@
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIOService.h"
 #include "NetworkActivityMonitor.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Likely.h"
-
-
-// XXX: There is no good header file to put these in. :(
-namespace mozilla { namespace psm {
-
-void InitializeSSLServerCertVerificationThreads();
-void StopSSLServerCertVerificationThreads();
-
-} } // namespace mozilla::psm
+#include "mozilla/PublicSSL.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gSocketTransportLog = nullptr;
 #endif
 
@@ -465,16 +457,17 @@ nsSocketTransportService::Init()
     if (tmpPrefService) {
         tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
     }
     UpdatePrefs();
 
     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
     if (obsSvc) {
         obsSvc->AddObserver(this, "profile-initial-state", false);
+        obsSvc->AddObserver(this, "last-pb-context-exited", false);
     }
 
     mInitialized = true;
     return NS_OK;
 }
 
 // called from main thread only
 NS_IMETHODIMP
@@ -512,16 +505,17 @@ nsSocketTransportService::Shutdown()
 
     nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (tmpPrefService) 
         tmpPrefService->RemoveObserver(SEND_BUFFER_PREF, this);
 
     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
     if (obsSvc) {
         obsSvc->RemoveObserver(this, "profile-initial-state");
+        obsSvc->RemoveObserver(this, "last-pb-context-exited");
     }
 
     mozilla::net::NetworkActivityMonitor::Shutdown();
 
     mInitialized = false;
     mShuttingDown = false;
 
     return NS_OK;
@@ -879,19 +873,52 @@ nsSocketTransportService::Observe(nsISup
     if (!strcmp(topic, "profile-initial-state")) {
         int32_t blipInterval = Preferences::GetInt(BLIP_INTERVAL_PREF, 0);
         if (blipInterval <= 0) {
             return NS_OK;
         }
 
         return net::NetworkActivityMonitor::Init(blipInterval);
     }
+
+    if (!strcmp(topic, "last-pb-context-exited")) {
+        nsCOMPtr<nsIRunnable> ev =
+          NS_NewRunnableMethod(this,
+                               &nsSocketTransportService::ClosePrivateConnections);
+        nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
+        NS_ENSURE_SUCCESS(rv, rv);
+    }
+
     return NS_OK;
 }
 
+void
+nsSocketTransportService::ClosePrivateConnections()
+{
+    // Must be called on the socket thread.
+#ifdef DEBUG
+    bool onSTSThread;
+    IsOnCurrentThread(&onSTSThread);
+    MOZ_ASSERT(onSTSThread);
+#endif
+
+    for (int32_t i = mActiveCount - 1; i >= 0; --i) {
+        if (mActiveList[i].mHandler->mIsPrivate) {
+            DetachSocket(mActiveList, &mActiveList[i]);
+        }
+    }
+    for (int32_t i = mIdleCount - 1; i >= 0; --i) {
+        if (mIdleList[i].mHandler->mIsPrivate) {
+            DetachSocket(mIdleList, &mIdleList[i]);
+        }
+    }
+
+    mozilla::ClearPrivateSSLState();
+}
+
 NS_IMETHODIMP
 nsSocketTransportService::GetSendBufferSize(int32_t *value)
 {
     *value = mSendBufferSize;
     return NS_OK;
 }
 
 
--- a/netwerk/base/src/nsSocketTransportService2.h
+++ b/netwerk/base/src/nsSocketTransportService2.h
@@ -183,16 +183,18 @@ private:
     int32_t     mSendBufferSize;
 
     // Socket thread only for dynamically adjusting max socket size
 #if defined(XP_WIN)
     void ProbeMaxCount();
 #endif
     bool mProbedMaxCount;
 
+    void ClosePrivateConnections();
+
     void AnalyzeConnection(nsTArray<mozilla::net::SocketInfo> *data,
                            SocketContext *context, bool aActive);
 };
 
 extern nsSocketTransportService *gSocketTransportService;
 extern PRThread                 *gSocketThread;
 
 #endif // !nsSocketTransportService_h__
--- a/security/manager/ssl/src/Makefile.in
+++ b/security/manager/ssl/src/Makefile.in
@@ -78,25 +78,30 @@ CPPSRCS = 				\
   $(NULL)
 
 ifdef MOZ_XUL
 CPPSRCS += nsCertTree.cpp
 endif
 
 CSRCS += md4.c
 
-
 EXTRA_DEPS = $(NSS_DEP_LIBS)
 
 DEFINES += \
   -DNSS_ENABLE_ECC \
   -DDLL_PREFIX=\"$(DLL_PREFIX)\" \
   -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" \
   $(NULL)
 
 EXPORTS += \
   CryptoTask.h \
   nsNSSShutDown.h \
   ScopedNSSTypes.h \
   $(NULL)
 
+EXPORTS_NAMESPACES = mozilla
+
+EXPORTS_mozilla += \
+  PublicSSL.h \
+  $(NULL)
+
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/PublicSSL.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SSL_h
+#define mozilla_SSL_h
+
+namespace mozilla {
+
+void ClearPrivateSSLState();
+
+namespace psm {
+
+void InitializeSSLServerCertVerificationThreads();
+void StopSSLServerCertVerificationThreads();
+
+} //namespace psm
+} // namespace mozilla
+
+#endif
+
--- a/security/manager/ssl/src/SharedSSLState.cpp
+++ b/security/manager/ssl/src/SharedSSLState.cpp
@@ -7,18 +7,94 @@
 #include "SharedSSLState.h"
 #include "nsClientAuthRemember.h"
 #include "nsComponentManagerUtils.h"
 #include "nsICertOverrideService.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "nsCRT.h"
+#include "nsServiceManagerUtils.h"
+#include "nsRecentBadCerts.h"
+#include "PSMRunnable.h"
+#include "PublicSSL.h"
+#include "ssl.h"
+#include "nsNetCID.h"
+
+using mozilla::psm::SyncRunnableBase;
+
+namespace {
+
+class MainThreadClearer : public SyncRunnableBase
+{
+public:
+  MainThreadClearer() : mShouldClearSessionCache(false) {}
+
+  void RunOnTargetThread() {
+    // In some cases it's possible to cause PSM/NSS to initialize while XPCOM shutdown
+    // is in progress. We want to avoid this, since they do not handle the situation well,
+    // hence the flags to avoid instantiating the services if they don't already exist.
+
+    if (mozilla::psm::SharedSSLState::CertOverrideServiceInstantiated()) {
+      nsCOMPtr<nsICertOverrideService> icos = do_GetService(NS_CERTOVERRIDE_CONTRACTID);
+      if (icos) {
+        icos->ClearValidityOverride(
+          NS_LITERAL_CSTRING("all:temporary-certificates"),
+          0);
+      }
+    }
+
+    if (mozilla::psm::SharedSSLState::CertDBServiceInstantiated()) {
+      nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
+      if (certdb) {
+        nsCOMPtr<nsIRecentBadCerts> badCerts;
+        certdb->GetRecentBadCerts(true, getter_AddRefs(badCerts));
+        if (badCerts) {
+          badCerts->ResetStoredCerts();
+        }
+      }
+    }
+
+    // This needs to be checked on the main thread to avoid racing with NSS
+    // initialization.
+    mShouldClearSessionCache = mozilla::psm::PrivateSSLState() &&
+                               mozilla::psm::PrivateSSLState()->SocketCreated();
+  }
+  bool mShouldClearSessionCache;
+};
+
+} // anonymous namespace
 
 namespace mozilla {
+
+void ClearPrivateSSLState()
+{
+  // This only works if it is called on the socket transport
+  // service thread immediately after closing all private SSL
+  // connections.
+#ifdef DEBUG
+  nsresult rv;
+  nsCOMPtr<nsIEventTarget> sts
+    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  bool onSTSThread;
+  sts->IsOnCurrentThread(&onSTSThread);
+  MOZ_ASSERT(NS_SUCCEEDED(rv) && onSTSThread);
+#endif
+
+  RefPtr<MainThreadClearer> runnable = new MainThreadClearer;
+  runnable->DispatchToMainThreadAndWait();
+
+  // If NSS isn't initialized, this throws an assertion. We guard it by checking if
+  // the session cache might even have anything worth clearing.
+  if (runnable->mShouldClearSessionCache) {
+    SSL_ClearSessionCache();
+  }
+}
+
 namespace psm {
 
 namespace {
 class PrivateBrowsingObserver : public nsIObserver {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   PrivateBrowsingObserver(SharedSSLState* aOwner) : mOwner(aOwner) {}
@@ -41,36 +117,61 @@ PrivateBrowsingObserver::Observe(nsISupp
   if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
     mOwner->ResetStoredData();
   }
   return NS_OK;
 }
 
 SharedSSLState::SharedSSLState()
 : mClientAuthRemember(new nsClientAuthRememberService)
+, mSocketCreated(false)
 {
   mIOLayerHelpers.Init();
   mClientAuthRemember->Init();
 }
 
+SharedSSLState::~SharedSSLState()
+{
+}
+
 void
 SharedSSLState::NotePrivateBrowsingStatus()
 {
+  MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
   mObserver = new PrivateBrowsingObserver(this);
   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
   obsSvc->AddObserver(mObserver, "last-pb-context-exited", false);
 }
 
 void
 SharedSSLState::ResetStoredData()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   mClientAuthRemember->ClearRememberedDecisions();
   mIOLayerHelpers.clearStoredData();
 }
 
+void
+SharedSSLState::NoteSocketCreated()
+{
+  MutexAutoLock lock(sLock);
+  mSocketCreated = true;
+}
+
+bool
+SharedSSLState::SocketCreated()
+{
+  MutexAutoLock lock(sLock);
+  return mSocketCreated;
+}
+
+Mutex SharedSSLState::sLock("SharedSSLState::sLock");
+bool SharedSSLState::sCertOverrideSvcExists = false;
+bool SharedSSLState::sCertDBExists = false;
+
 /*static*/ void
 SharedSSLState::GlobalInit()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
   gPublicState = new SharedSSLState();
   gPrivateState = new SharedSSLState();
   gPrivateState->NotePrivateBrowsingStatus();
 }
@@ -84,16 +185,44 @@ SharedSSLState::GlobalCleanup()
   delete gPrivateState;
   gPrivateState = nullptr;
 
   gPublicState->Cleanup();
   delete gPublicState;
   gPublicState = nullptr;
 }
 
+/*static*/ void
+SharedSSLState::NoteCertOverrideServiceInstantiated()
+{
+  MutexAutoLock lock(sLock);
+  sCertOverrideSvcExists = true;
+}
+
+/*static*/ bool
+SharedSSLState::CertOverrideServiceInstantiated()
+{
+  MutexAutoLock lock(sLock);
+  return sCertOverrideSvcExists;
+}
+
+/*static*/ void
+SharedSSLState::NoteCertDBServiceInstantiated()
+{
+  MutexAutoLock lock(sLock);
+  sCertDBExists = true;
+}
+
+/*static*/ bool
+SharedSSLState::CertDBServiceInstantiated()
+{
+  MutexAutoLock lock(sLock);
+  return sCertDBExists;
+}
+
 void
 SharedSSLState::Cleanup()
 {
   mIOLayerHelpers.Cleanup();
 }
 
 SharedSSLState*
 PublicSSLState()
--- a/security/manager/ssl/src/SharedSSLState.h
+++ b/security/manager/ssl/src/SharedSSLState.h
@@ -6,48 +6,66 @@
 
 #ifndef SharedSSLState_h
 #define SharedSSLState_h
 
 #include "mozilla/RefPtr.h"
 #include "nsNSSIOLayer.h"
 
 class nsClientAuthRememberService;
-class nsIRecentBadCertsService;
-class nsICertOverrideService;
 class nsIObserver;
 
 namespace mozilla {
 namespace psm {
 
 class SharedSSLState {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedSSLState)
   SharedSSLState();
+  ~SharedSSLState();
 
   static void GlobalInit();
   static void GlobalCleanup();
 
   nsClientAuthRememberService* GetClientAuthRememberService() {
     return mClientAuthRemember;
   }
 
   nsSSLIOLayerHelpers& IOLayerHelpers() {
     return mIOLayerHelpers;
   }
 
+  // Main-thread only
   void ResetStoredData();
   void NotePrivateBrowsingStatus();
 
+  // The following methods may be called from any thread
+  bool SocketCreated();
+  void NoteSocketCreated();
+  static void NoteCertOverrideServiceInstantiated();
+  static void NoteCertDBServiceInstantiated();
+  static bool CertOverrideServiceInstantiated();
+  static bool CertDBServiceInstantiated();
+
 private:
   void Cleanup();
 
   nsCOMPtr<nsIObserver> mObserver;
   RefPtr<nsClientAuthRememberService> mClientAuthRemember;
   nsSSLIOLayerHelpers mIOLayerHelpers;
+
+  // Since various NSS-related services can be instantiated on any thread,
+  // these flags all require the following lock for synchronization.
+  static Mutex sLock;
+  static bool sCertOverrideSvcExists;
+  static bool sCertDBExists;
+  // True if any sockets have been created that use this shared data.
+  // Requires synchronization between the socket and main threads for
+  // reading/writing.
+  bool mSocketCreated;
 };
 
 SharedSSLState* PublicSSLState();
 SharedSSLState* PrivateSSLState();
 
 } // namespace psm
 } // namespace mozilla
 
--- a/security/manager/ssl/src/nsCertOverrideService.cpp
+++ b/security/manager/ssl/src/nsCertOverrideService.cpp
@@ -14,24 +14,26 @@
 #include "nsILineInputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsPromiseFlatString.h"
 #include "nsThreadUtils.h"
 #include "nsStringBuffer.h"
 #include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
 
 #include "nspr.h"
 #include "pk11pub.h"
 #include "certdb.h"
 #include "sechash.h"
 #include "ssl.h" // For SSL_ClearSessionCache
 
 using namespace mozilla;
+using mozilla::psm::SharedSSLState;
 
 static const char kCertOverrideFileName[] = "cert_override.txt";
 
 void
 nsCertOverride::convertBitsToString(OverrideBits ob, nsACString &str)
 {
   str.Truncate();
 
@@ -119,21 +121,21 @@ nsCertOverrideService::Init()
       mozilla::services::GetObserverService();
 
   // If we cannot add ourselves as a profile change observer, then we will not
   // attempt to read/write any settings file. Otherwise, we would end up
   // reading/writing the wrong settings file after a profile change.
   if (observerService) {
     observerService->AddObserver(this, "profile-before-change", true);
     observerService->AddObserver(this, "profile-do-change", true);
-    observerService->AddObserver(this, "last-pb-context-exited", true);
     // simulate a profile change so we read the current profile's settings file
     Observe(nullptr, "profile-do-change", nullptr);
   }
 
+  SharedSSLState::NoteCertOverrideServiceInstantiated();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertOverrideService::Observe(nsISupports     *,
                                const char      *aTopic,
                                const PRUnichar *aData)
 {
@@ -164,20 +166,16 @@ nsCertOverrideService::Observe(nsISuppor
     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
     if (NS_SUCCEEDED(rv)) {
       mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
     } else {
       mSettingsFile = nullptr;
     }
     Read();
 
-  } else if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
-    ClearValidityOverride(
-        NS_LITERAL_CSTRING("all:temporary-certificates"),
-        0);
   }
 
   return NS_OK;
 }
 
 void
 nsCertOverrideService::RemoveAllFromMemory()
 {
--- a/security/manager/ssl/src/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/src/nsNSSCertificateDB.cpp
@@ -28,40 +28,44 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPrompt.h"
 #include "nsThreadUtils.h"
 #include "ScopedNSSTypes.h"
 #include "nsIObserverService.h"
 #include "nsRecentBadCerts.h"
+#include "SharedSSLState.h"
 
 #include "nspr.h"
 #include "certdb.h"
 #include "secerr.h"
 #include "nssb64.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "ssl.h"
 #include "ocsp.h"
 #include "plbase64.h"
 
 using namespace mozilla;
+using mozilla::psm::SharedSSLState;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
 
 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
 
 nsNSSCertificateDB::nsNSSCertificateDB()
+: mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
 {
+  SharedSSLState::NoteCertDBServiceInstantiated();
 }
 
 nsNSSCertificateDB::~nsNSSCertificateDB()
 {
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken,
@@ -1645,21 +1649,20 @@ nsNSSCertificateDB::GetCerts(nsIX509Cert
   *_retval = nssCertList;
   NS_ADDREF(*_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result)
 {
-  MOZ_ASSERT(NS_IsMainThread(), "RecentBadCerts should only be obtained on the main thread");
+  MutexAutoLock lock(mBadCertsLock);
   if (isPrivate) {
     if (!mPrivateRecentBadCerts) {
       mPrivateRecentBadCerts = new nsRecentBadCerts;
-      mPrivateRecentBadCerts->InitPrivateBrowsingObserver();
     }
     NS_ADDREF(*result = mPrivateRecentBadCerts);
   } else {
     if (!mPublicRecentBadCerts) {
       mPublicRecentBadCerts = new nsRecentBadCerts;
     }
     NS_ADDREF(*result = mPublicRecentBadCerts);
   }
--- a/security/manager/ssl/src/nsNSSCertificateDB.h
+++ b/security/manager/ssl/src/nsNSSCertificateDB.h
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NSNSSCERTIFICATEDB_H__
 #define __NSNSSCERTIFICATEDB_H__
 
 #include "nsIX509CertDB.h"
 #include "nsIX509CertDB2.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/Mutex.h"
 #include "certt.h"
 
 class nsCString;
 class nsIArray;
 class nsRecentBadCerts;
 
 class nsNSSCertificateDB : public nsIX509CertDB, public nsIX509CertDB2
 {
@@ -46,16 +47,17 @@ private:
                     uint32_t     *_count,
                     PRUnichar  ***_certNameList);
 
   CERTDERCerts *getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 
                                     uint32_t length);
   nsresult handleCACertDownload(nsIArray *x509Certs, 
                                 nsIInterfaceRequestor *ctx);
 
+  mozilla::Mutex mBadCertsLock;
   mozilla::RefPtr<nsRecentBadCerts> mPublicRecentBadCerts;
   mozilla::RefPtr<nsRecentBadCerts> mPrivateRecentBadCerts;
 };
 
 #define NS_X509CERTDB_CID { /* fb0bbc5c-452e-4783-b32c-80124693d871 */ \
     0xfb0bbc5c,                                                        \
     0x452e,                                                            \
     0x4783,                                                            \
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -2133,17 +2133,16 @@ nsNSSComponent::RandomUpdate(void *entro
 
 #define PROFILE_CHANGE_NET_TEARDOWN_TOPIC "profile-change-net-teardown"
 #define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
 #define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
 #define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
 #define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
 #define PROFILE_BEFORE_CHANGE_TOPIC "profile-before-change"
 #define PROFILE_DO_CHANGE_TOPIC "profile-do-change"
-#define LEAVE_PRIVATE_BROWSING_TOPIC "last-pb-context-exited"
 
 NS_IMETHODIMP
 nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, 
                         const PRUnichar *someData)
 {
   if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
     DoProfileApproveChange(aSubject);
   }
@@ -2281,19 +2280,16 @@ nsNSSComponent::Observe(nsISupports *aSu
   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
     DoProfileChangeNetTeardown();
   }
   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_RESTORE_TOPIC) == 0) {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network restore topic\n"));
     DoProfileChangeNetRestore();
   }
-  else if (nsCRT::strcmp(aTopic, LEAVE_PRIVATE_BROWSING_TOPIC) == 0) {
-    SSL_ClearSessionCache();
-  }
 
   return NS_OK;
 }
 
 /*static*/ nsresult
 nsNSSComponent::GetNewPrompter(nsIPrompt ** result)
 {
   NS_ENSURE_ARG_POINTER(result);
@@ -2383,17 +2379,16 @@ nsNSSComponent::RegisterObservers()
 
     observerService->AddObserver(this, PROFILE_APPROVE_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC, false);
     observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_DO_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, false);
-    observerService->AddObserver(this, LEAVE_PRIVATE_BROWSING_TOPIC, false);
   }
   return NS_OK;
 }
 
 nsresult
 nsNSSComponent::DeregisterObservers()
 {
   if (!mObserversRegistered)
@@ -2409,17 +2404,16 @@ nsNSSComponent::DeregisterObservers()
 
     observerService->RemoveObserver(this, PROFILE_APPROVE_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC);
     observerService->RemoveObserver(this, PROFILE_BEFORE_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_DO_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC);
-    observerService->RemoveObserver(this, LEAVE_PRIVATE_BROWSING_TOPIC);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSComponent::RememberCert(CERTCertificate *cert)
 {
   nsNSSShutDownPreventionLock locker;
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -2578,16 +2578,18 @@ nsSSLIOLayerAddToSocket(int32_t family,
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
 
   // We are going use a clear connection first //
   if (forSTARTTLS || proxyHost) {
     infoObject->SetHandshakePending(false);
   }
 
+  infoObject->SharedState().NoteSocketCreated();
+
   return NS_OK;
  loser:
   NS_IF_RELEASE(infoObject);
   if (layer) {
     layer->dtor(layer);
   }
   return NS_ERROR_FAILURE;
 }
--- a/security/manager/ssl/src/nsRecentBadCerts.cpp
+++ b/security/manager/ssl/src/nsRecentBadCerts.cpp
@@ -17,48 +17,29 @@
 #include "nsStringBuffer.h"
 #include "nspr.h"
 #include "pk11pub.h"
 #include "certdb.h"
 #include "sechash.h"
 
 using namespace mozilla;
 
-NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecentBadCerts,
-                              nsIRecentBadCerts,
-                              nsIObserver)
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsRecentBadCerts,
+                              nsIRecentBadCerts)
 
 nsRecentBadCerts::nsRecentBadCerts()
 :monitor("nsRecentBadCerts.monitor")
 ,mNextStorePosition(0)
 {
 }
 
 nsRecentBadCerts::~nsRecentBadCerts()
 {
 }
 
-void
-nsRecentBadCerts::InitPrivateBrowsingObserver()
-{
-  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
-  obsSvc->AddObserver(this, "last-pb-context-exited", false);
-}
-
-NS_IMETHODIMP
-nsRecentBadCerts::Observe(nsISupports     *aSubject,
-                          const char      *aTopic,
-                          const PRUnichar *aData)
-{
-  if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
-    ResetStoredCerts();
-  }
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsRecentBadCerts::GetRecentBadCert(const nsAString & aHostNameWithPort, 
                                    nsISSLStatus **aStatus)
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   if (!aHostNameWithPort.Length())
     return NS_ERROR_INVALID_ARG;
 
--- a/security/manager/ssl/src/nsRecentBadCerts.h
+++ b/security/manager/ssl/src/nsRecentBadCerts.h
@@ -6,17 +6,16 @@
 
 #ifndef __RECENTBADCERTS_H__
 #define __RECENTBADCERTS_H__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ReentrantMonitor.h"
 
 #include "nsIRecentBadCertsService.h"
-#include "nsIObserver.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "cert.h"
 #include "secitem.h"
 
 class RecentBadCert
 {
 public:
@@ -51,28 +50,24 @@ public:
   bool isUntrusted;
 
 private:
   RecentBadCert(const RecentBadCert &other) MOZ_DELETE;
   RecentBadCert &operator=(const RecentBadCert &other) MOZ_DELETE;
 };
 
 class nsRecentBadCerts MOZ_FINAL : public nsIRecentBadCerts
-                                 , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRECENTBADCERTS
-  NS_DECL_NSIOBSERVER
 
   nsRecentBadCerts();
   ~nsRecentBadCerts();
 
-  void InitPrivateBrowsingObserver();
-
 protected:
     mozilla::ReentrantMonitor monitor;
 
     enum {const_recently_seen_list_size = 5};
     RecentBadCert mCerts[const_recently_seen_list_size];
 
     // will be in the range of 0 to list_size-1
     uint32_t mNextStorePosition;