LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSShutDown.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 56 129 43.4 %
Date: 2017-07-14 16:53:18 Functions: 14 22 63.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "nsNSSShutDown.h"
       6             : 
       7             : #include "mozilla/Casting.h"
       8             : #include "nsCOMPtr.h"
       9             : 
      10             : using namespace mozilla;
      11             : 
      12             : extern LazyLogModule gPIPNSSLog;
      13             : 
      14             : struct ObjectHashEntry : PLDHashEntryHdr {
      15             :   nsNSSShutDownObject *obj;
      16             : };
      17             : 
      18             : static bool
      19          13 : ObjectSetMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
      20             : {
      21          13 :   const ObjectHashEntry *entry = static_cast<const ObjectHashEntry*>(hdr);
      22          13 :   return entry->obj == static_cast<const nsNSSShutDownObject*>(key);
      23             : }
      24             : 
      25             : static void
      26          17 : ObjectSetInitEntry(PLDHashEntryHdr *hdr, const void *key)
      27             : {
      28          17 :   ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
      29          17 :   entry->obj = const_cast<nsNSSShutDownObject*>(static_cast<const nsNSSShutDownObject*>(key));
      30          17 : }
      31             : 
      32             : static const PLDHashTableOps gSetOps = {
      33             :   PLDHashTable::HashVoidPtrKeyStub,
      34             :   ObjectSetMatchEntry,
      35             :   PLDHashTable::MoveEntryStub,
      36             :   PLDHashTable::ClearEntryStub,
      37             :   ObjectSetInitEntry
      38             : };
      39             : 
      40           3 : StaticMutex sListLock;
      41             : Atomic<bool> sInShutdown(false);
      42             : nsNSSShutDownList *singleton = nullptr;
      43             : 
      44           1 : nsNSSShutDownList::nsNSSShutDownList()
      45             :   : mObjects(&gSetOps, sizeof(ObjectHashEntry))
      46           1 :   , mPK11LogoutCancelObjects(&gSetOps, sizeof(ObjectHashEntry))
      47             : {
      48           1 : }
      49             : 
      50           0 : nsNSSShutDownList::~nsNSSShutDownList()
      51             : {
      52           0 :   MOZ_ASSERT(this == singleton);
      53           0 :   MOZ_ASSERT(sInShutdown,
      54             :              "evaporateAllNSSResourcesAndShutDown() should have been called");
      55           0 :   singleton = nullptr;
      56           0 : }
      57             : 
      58          17 : void nsNSSShutDownList::remember(nsNSSShutDownObject *o)
      59             : {
      60          34 :   StaticMutexAutoLock lock(sListLock);
      61          17 :   if (!nsNSSShutDownList::construct(lock)) {
      62           0 :     return;
      63             :   }
      64             : 
      65          17 :   MOZ_ASSERT(o);
      66          17 :   singleton->mObjects.Add(o, fallible);
      67             : }
      68             : 
      69          13 : void nsNSSShutDownList::forget(nsNSSShutDownObject *o)
      70             : {
      71          26 :   StaticMutexAutoLock lock(sListLock);
      72          13 :   if (!singleton) {
      73           0 :     return;
      74             :   }
      75             : 
      76          13 :   MOZ_ASSERT(o);
      77          13 :   singleton->mObjects.Remove(o);
      78             : }
      79             : 
      80           0 : void nsNSSShutDownList::remember(nsOnPK11LogoutCancelObject *o)
      81             : {
      82           0 :   StaticMutexAutoLock lock(sListLock);
      83           0 :   if (!nsNSSShutDownList::construct(lock)) {
      84           0 :     return;
      85             :   }
      86             : 
      87           0 :   MOZ_ASSERT(o);
      88           0 :   singleton->mPK11LogoutCancelObjects.Add(o, fallible);
      89             : }
      90             : 
      91           0 : void nsNSSShutDownList::forget(nsOnPK11LogoutCancelObject *o)
      92             : {
      93           0 :   StaticMutexAutoLock lock(sListLock);
      94           0 :   if (!singleton) {
      95           0 :     return;
      96             :   }
      97             : 
      98           0 :   MOZ_ASSERT(o);
      99           0 :   singleton->mPK11LogoutCancelObjects.Remove(o);
     100             : }
     101             : 
     102           0 : nsresult nsNSSShutDownList::doPK11Logout()
     103             : {
     104           0 :   StaticMutexAutoLock lock(sListLock);
     105           0 :   if (!singleton) {
     106           0 :     return NS_OK;
     107             :   }
     108             : 
     109           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     110             :           ("canceling all open SSL sockets to disallow future IO\n"));
     111             : 
     112             :   // During our iteration we will set a bunch of PRBools to true.
     113             :   // Nobody else ever modifies that bool, only we do.
     114             :   // We only must ensure that our objects do not go away.
     115             :   // This is guaranteed by holding the list lock.
     116             : 
     117           0 :   for (auto iter = singleton->mPK11LogoutCancelObjects.Iter();
     118           0 :        !iter.Done();
     119           0 :        iter.Next()) {
     120           0 :     auto entry = static_cast<ObjectHashEntry*>(iter.Get());
     121             :     nsOnPK11LogoutCancelObject* pklco =
     122           0 :       BitwiseCast<nsOnPK11LogoutCancelObject*, nsNSSShutDownObject*>(entry->obj);
     123           0 :     if (pklco) {
     124           0 :       pklco->logout();
     125             :     }
     126             :   }
     127             : 
     128           0 :   return NS_OK;
     129             : }
     130             : 
     131           0 : nsresult nsNSSShutDownList::evaporateAllNSSResourcesAndShutDown()
     132             : {
     133           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
     134           0 :   if (!NS_IsMainThread()) {
     135           0 :     return NS_ERROR_NOT_SAME_THREAD;
     136             :   }
     137             : 
     138           0 :   StaticMutexAutoLock lock(sListLock);
     139             :   // Other threads can acquire an nsNSSShutDownPreventionLock and cause this
     140             :   // thread to block when it calls restructActivityToCurrentThread, below. If
     141             :   // those other threads then attempt to create an object that must be
     142             :   // remembered by the shut down list, they will call
     143             :   // nsNSSShutDownList::remember, which attempts to acquire sListLock.
     144             :   // Consequently, holding sListLock while we're in
     145             :   // restrictActivityToCurrentThread would result in deadlock. sListLock
     146             :   // protects the singleton, so if we enforce that the singleton only be created
     147             :   // and destroyed on the main thread, and if we similarly enforce that this
     148             :   // function is only called on the main thread, what we can do is check that
     149             :   // the singleton hasn't already gone away and then we don't actually have to
     150             :   // hold sListLock while calling restrictActivityToCurrentThread.
     151           0 :   if (!singleton) {
     152           0 :     return NS_OK;
     153             :   }
     154             : 
     155           0 :   sInShutdown = true;
     156             : 
     157             :   {
     158           0 :     StaticMutexAutoUnlock unlock(sListLock);
     159           0 :     PRStatus rv = singleton->mActivityState.restrictActivityToCurrentThread();
     160           0 :     if (rv != PR_SUCCESS) {
     161           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     162             :               ("failed to restrict activity to current thread"));
     163           0 :       return NS_ERROR_FAILURE;
     164             :     }
     165             :   }
     166             : 
     167           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("now evaporating NSS resources"));
     168             : 
     169             :   // Never free more than one entry, because other threads might be calling
     170             :   // us and remove themselves while we are iterating over the list,
     171             :   // and the behaviour of changing the list while iterating is undefined.
     172           0 :   while (singleton) {
     173           0 :     auto iter = singleton->mObjects.Iter();
     174           0 :     if (iter.Done()) {
     175           0 :       break;
     176             :     }
     177           0 :     auto entry = static_cast<ObjectHashEntry*>(iter.Get());
     178             :     {
     179           0 :       StaticMutexAutoUnlock unlock(sListLock);
     180           0 :       entry->obj->shutdown(nsNSSShutDownObject::ShutdownCalledFrom::List);
     181             :     }
     182           0 :     iter.Remove();
     183             :   }
     184             : 
     185           0 :   if (!singleton) {
     186           0 :     return NS_ERROR_FAILURE;
     187             :   }
     188             : 
     189           0 :   singleton->mActivityState.releaseCurrentThreadActivityRestriction();
     190           0 :   delete singleton;
     191             : 
     192           0 :   return NS_OK;
     193             : }
     194             : 
     195         277 : void nsNSSShutDownList::enterActivityState()
     196             : {
     197         554 :   StaticMutexAutoLock lock(sListLock);
     198         277 :   if (nsNSSShutDownList::construct(lock)) {
     199         277 :     singleton->mActivityState.enter();
     200             :   }
     201         277 : }
     202             : 
     203         277 : void nsNSSShutDownList::leaveActivityState()
     204             : {
     205         554 :   StaticMutexAutoLock lock(sListLock);
     206         277 :   if (singleton) {
     207         277 :     singleton->mActivityState.leave();
     208             :   }
     209         277 : }
     210             : 
     211         294 : bool nsNSSShutDownList::construct(const StaticMutexAutoLock& /*proofOfLock*/)
     212             : {
     213         294 :   if (!singleton && !sInShutdown && XRE_IsParentProcess()) {
     214           1 :     singleton = new nsNSSShutDownList();
     215             :   }
     216             : 
     217         294 :   return !!singleton;
     218             : }
     219             : 
     220           1 : nsNSSActivityState::nsNSSActivityState()
     221             : :mNSSActivityStateLock("nsNSSActivityState.mNSSActivityStateLock"),
     222             :  mNSSActivityChanged(mNSSActivityStateLock,
     223             :                      "nsNSSActivityState.mNSSActivityStateLock"),
     224             :  mNSSActivityCounter(0),
     225           1 :  mNSSRestrictedThread(nullptr)
     226             : {
     227           1 : }
     228             : 
     229           0 : nsNSSActivityState::~nsNSSActivityState()
     230             : {
     231           0 : }
     232             : 
     233         277 : void nsNSSActivityState::enter()
     234             : {
     235         554 :   MutexAutoLock lock(mNSSActivityStateLock);
     236             : 
     237         277 :   while (mNSSRestrictedThread && mNSSRestrictedThread != PR_GetCurrentThread()) {
     238           0 :     mNSSActivityChanged.Wait();
     239             :   }
     240             : 
     241         277 :   ++mNSSActivityCounter;
     242         277 : }
     243             : 
     244         277 : void nsNSSActivityState::leave()
     245             : {
     246         554 :   MutexAutoLock lock(mNSSActivityStateLock);
     247             : 
     248         277 :   --mNSSActivityCounter;
     249             : 
     250         277 :   mNSSActivityChanged.NotifyAll();
     251         277 : }
     252             : 
     253           0 : PRStatus nsNSSActivityState::restrictActivityToCurrentThread()
     254             : {
     255           0 :   MutexAutoLock lock(mNSSActivityStateLock);
     256             : 
     257           0 :   while (mNSSActivityCounter > 0) {
     258           0 :     mNSSActivityChanged.Wait(PR_TicksPerSecond());
     259             :   }
     260             : 
     261           0 :   mNSSRestrictedThread = PR_GetCurrentThread();
     262             : 
     263           0 :   return PR_SUCCESS;
     264             : }
     265             : 
     266           0 : void nsNSSActivityState::releaseCurrentThreadActivityRestriction()
     267             : {
     268           0 :   MutexAutoLock lock(mNSSActivityStateLock);
     269             : 
     270           0 :   mNSSRestrictedThread = nullptr;
     271             : 
     272           0 :   mNSSActivityChanged.NotifyAll();
     273           0 : }
     274             : 
     275         277 : nsNSSShutDownPreventionLock::nsNSSShutDownPreventionLock()
     276             : {
     277         277 :   nsNSSShutDownList::enterActivityState();
     278         277 : }
     279             : 
     280         277 : nsNSSShutDownPreventionLock::~nsNSSShutDownPreventionLock()
     281             : {
     282         277 :   nsNSSShutDownList::leaveActivityState();
     283         277 : }
     284             : 
     285             : bool
     286         277 : nsNSSShutDownObject::isAlreadyShutDown() const
     287             : {
     288         277 :   return mAlreadyShutDown || sInShutdown;
     289             : }

Generated by: LCOV version 1.13