From 49884777a415cb21924fabf356d573cabc06ae91 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 30 Oct 2015 15:30:00 -0400 Subject: [PATCH] Bug 1215723 - Part 2: Initialize DataStorage items in the content process from the data in the parent; r=keeler --- dom/ipc/ContentParent.cpp | 10 ++ dom/ipc/ContentParent.h | 3 + dom/ipc/PContent.ipdl | 10 ++ security/manager/ssl/DataStorage.cpp | 127 ++++++++++++++++----- security/manager/ssl/DataStorage.h | 14 +++ security/manager/ssl/DataStorageIPCUtils.h | 21 ++++ security/manager/ssl/moz.build | 4 + 7 files changed, 161 insertions(+), 28 deletions(-) create mode 100644 security/manager/ssl/DataStorageIPCUtils.h diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 0560dc5fe44..3063984505a 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -35,6 +35,7 @@ #include "imgIContainer.h" #include "mozIApplication.h" #include "mozilla/ClearOnShutdown.h" +#include "mozilla/DataStorage.h" #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h" #include "mozilla/docshell/OfflineCacheUpdateParent.h" #include "mozilla/dom/DataStoreService.h" @@ -2673,6 +2674,15 @@ ContentParent::RecvReadFontList(InfallibleTArray* retValue) return true; } +bool +ContentParent::RecvReadDataStorageArray(const nsString& aFilename, + InfallibleTArray* aValues) +{ + RefPtr storage = DataStorage::Get(aFilename); + storage->GetAll(aValues); + return true; +} + bool ContentParent::RecvReadPermissions(InfallibleTArray* aPermissions) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 393913dd026..03447594ae5 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -742,6 +742,9 @@ private: virtual bool RecvReadPrefsArray(InfallibleTArray* aPrefs) override; virtual bool RecvReadFontList(InfallibleTArray* retValue) override; + virtual bool RecvReadDataStorageArray(const nsString& aFilename, + InfallibleTArray* aValues) override; + virtual bool RecvReadPermissions(InfallibleTArray* aPermissions) override; virtual bool RecvSetClipboard(const IPCDataTransfer& aDataTransfer, diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 93fb0580e95..3495585199e 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -91,6 +91,7 @@ using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h"; using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h"; using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h"; +using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h"; union ChromeRegistryItem { @@ -324,6 +325,12 @@ struct PrefSetting { MaybePrefValue userValue; }; +struct DataStorageItem { + nsCString key; + nsCString value; + DataStorageType type; +}; + struct DataStoreSetting { nsString name; nsString originURL; @@ -829,6 +836,9 @@ parent: sync ReadFontList() returns (FontListEntry[] retValue); + sync ReadDataStorageArray(nsString aFilename) + returns (DataStorageItem[] retValue); + sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal) returns (StructuredCloneData[] retval); diff --git a/security/manager/ssl/DataStorage.cpp b/security/manager/ssl/DataStorage.cpp index 2909ac4cde9..074a19f9e82 100644 --- a/security/manager/ssl/DataStorage.cpp +++ b/security/manager/ssl/DataStorage.cpp @@ -7,6 +7,8 @@ #include "DataStorage.h" #include "mozilla/ClearOnShutdown.h" +#include "mozilla/dom/PContent.h" +#include "mozilla/dom/ContentChild.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" @@ -42,6 +44,7 @@ DataStorage::DataStorage(const nsString& aFilename) : mMutex("DataStorage::mMutex") , mPendingWrite(false) , mShuttingDown(false) + , mInitCalled(false) , mReadyMonitor("DataStorage::mReadyMonitor") , mReady(false) , mFilename(aFilename) @@ -80,15 +83,41 @@ DataStorage::Init(bool& aDataWillPersist) MutexAutoLock lock(mMutex); - nsresult rv; - rv = NS_NewThread(getter_AddRefs(mWorkerThread)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + // Ignore attempts to initialize several times. + if (mInitCalled) { + return NS_OK; } - rv = AsyncReadData(aDataWillPersist, lock); - if (NS_FAILED(rv)) { - return rv; + mInitCalled = true; + + nsresult rv; + if (XRE_IsParentProcess()) { + rv = NS_NewThread(getter_AddRefs(mWorkerThread)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = AsyncReadData(aDataWillPersist, lock); + if (NS_FAILED(rv)) { + return rv; + } + } else { + // In the child process, we ask the parent process for the data. + MOZ_ASSERT(XRE_IsContentProcess()); + aDataWillPersist = false; + InfallibleTArray items; + dom::ContentChild::GetSingleton()-> + SendReadDataStorageArray(mFilename, &items); + for (auto& item : items) { + Entry entry; + entry.mValue = item.value(); + rv = PutInternal(item.key(), entry, item.type(), lock); + if (NS_FAILED(rv)) { + return rv; + } + } + mReady = true; + NotifyObservers("data-storage-ready"); } nsCOMPtr os = services::GetObserverService(); @@ -337,6 +366,7 @@ nsresult DataStorage::AsyncReadData(bool& aHaveProfileDir, const MutexAutoLock& /*aProofOfLock*/) { + MOZ_ASSERT(XRE_IsParentProcess()); aHaveProfileDir = false; // Allocate a Reader so that even if it isn't dispatched, // the data-storage-ready notification will be fired and Get @@ -425,6 +455,34 @@ DataStorage::GetTableForType(DataStorageType aType, MOZ_CRASH("given bad DataStorage storage type"); } +void +DataStorage::ReadAllFromTable(DataStorageType aType, + InfallibleTArray* aItems, + const MutexAutoLock& aProofOfLock) +{ + for (auto iter = GetTableForType(aType, aProofOfLock).Iter(); + !iter.Done(); iter.Next()) { + DataStorageItem* item = aItems->AppendElement(); + item->key() = iter.Key(); + item->value() = iter.Data().mValue; + item->type() = aType; + } +} + +void +DataStorage::GetAll(InfallibleTArray* aItems) +{ + WaitForReady(); + MutexAutoLock lock(mMutex); + + aItems->SetCapacity(mPersistentDataTable.Count() + + mTemporaryDataTable.Count() + + mPrivateDataTable.Count()); + ReadAllFromTable(DataStorage_Persistent, aItems, lock); + ReadAllFromTable(DataStorage_Temporary, aItems, lock); + ReadAllFromTable(DataStorage_Private, aItems, lock); +} + // Limit the number of entries per table. This is to prevent unbounded // resource use. The eviction strategy is as follows: // - An entry's score is incremented once for every day it is accessed. @@ -591,6 +649,8 @@ DataStorage::Writer::Run() nsresult DataStorage::AsyncWriteData(const MutexAutoLock& /*aProofOfLock*/) { + MOZ_ASSERT(XRE_IsParentProcess()); + if (mShuttingDown || !mBackingFile) { return NS_OK; } @@ -627,12 +687,14 @@ DataStorage::Clear() mTemporaryDataTable.Clear(); mPrivateDataTable.Clear(); - // Asynchronously clear the file. This is similar to the permission manager - // in that it doesn't wait to synchronously remove the data from its backing - // storage either. - nsresult rv = AsyncWriteData(lock); - if (NS_FAILED(rv)) { - return rv; + if (XRE_IsParentProcess()) { + // Asynchronously clear the file. This is similar to the permission manager + // in that it doesn't wait to synchronously remove the data from its backing + // storage either. + nsresult rv = AsyncWriteData(lock); + if (NS_FAILED(rv)) { + return rv; + } } return NS_OK; } @@ -641,6 +703,8 @@ DataStorage::Clear() void DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure) { + MOZ_ASSERT(XRE_IsParentProcess()); + RefPtr aDataStorage = (DataStorage*)aClosure; MutexAutoLock lock(aDataStorage->mMutex); Unused << aDataStorage->AsyncWriteData(lock); @@ -651,7 +715,7 @@ DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure) nsresult DataStorage::AsyncSetTimer(const MutexAutoLock& /*aProofOfLock*/) { - if (mShuttingDown) { + if (mShuttingDown || !XRE_IsParentProcess()) { return NS_OK; } @@ -669,6 +733,8 @@ void DataStorage::SetTimer() { MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(XRE_IsParentProcess()); + MutexAutoLock lock(mMutex); nsresult rv; @@ -702,6 +768,8 @@ DataStorage::NotifyObservers(const char* aTopic) nsresult DataStorage::DispatchShutdownTimer(const MutexAutoLock& /*aProofOfLock*/) { + MOZ_ASSERT(XRE_IsParentProcess()); + nsCOMPtr job = NS_NewRunnableMethod(this, &DataStorage::ShutdownTimer); nsresult rv = mWorkerThread->Dispatch(job, NS_DISPATCH_NORMAL); @@ -714,6 +782,7 @@ DataStorage::DispatchShutdownTimer(const MutexAutoLock& /*aProofOfLock*/) void DataStorage::ShutdownTimer() { + MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(!NS_IsMainThread()); MutexAutoLock lock(mMutex); nsresult rv = mTimer->Cancel(); @@ -740,22 +809,24 @@ DataStorage::Observe(nsISupports* aSubject, const char* aTopic, MutexAutoLock lock(mMutex); mPrivateDataTable.Clear(); } else if (strcmp(aTopic, "profile-before-change") == 0) { - { - MutexAutoLock lock(mMutex); - rv = AsyncWriteData(lock); - mShuttingDown = true; - Unused << NS_WARN_IF(NS_FAILED(rv)); - if (mTimer) { - rv = DispatchShutdownTimer(lock); + if (XRE_IsParentProcess()) { + { + MutexAutoLock lock(mMutex); + rv = AsyncWriteData(lock); + mShuttingDown = true; Unused << NS_WARN_IF(NS_FAILED(rv)); + if (mTimer) { + rv = DispatchShutdownTimer(lock); + Unused << NS_WARN_IF(NS_FAILED(rv)); + } + } + // Run the thread to completion and prevent any further events + // being scheduled to it. The thread may need the lock, so we can't + // hold it here. + rv = mWorkerThread->Shutdown(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } - } - // Run the thread to completion and prevent any further events - // being scheduled to it. The thread may need the lock, so we can't - // hold it here. - rv = mWorkerThread->Shutdown(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; } sDataStorages->Clear(); diff --git a/security/manager/ssl/DataStorage.h b/security/manager/ssl/DataStorage.h index 963c54b100a..4152be506a4 100644 --- a/security/manager/ssl/DataStorage.h +++ b/security/manager/ssl/DataStorage.h @@ -20,6 +20,10 @@ namespace mozilla { +namespace dom { +class DataStorageItem; +} + /** * DataStorage is a threadsafe, generic, narrow string-based hash map that * persists data on disk and additionally handles temporary and private data. @@ -83,6 +87,8 @@ enum DataStorageType { class DataStorage : public nsIObserver { + typedef dom::DataStorageItem DataStorageItem; + public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVER @@ -109,6 +115,9 @@ public: // Removes all entries of all types of data. nsresult Clear(); + // Read all of the data items. + void GetAll(InfallibleTArray* aItems); + private: explicit DataStorage(const nsString& aFilename); virtual ~DataStorage(); @@ -162,6 +171,10 @@ private: DataStorageTable& GetTableForType(DataStorageType aType, const MutexAutoLock& aProofOfLock); + void ReadAllFromTable(DataStorageType aType, + InfallibleTArray* aItems, + const MutexAutoLock& aProofOfLock); + Mutex mMutex; // This mutex protects access to the following members: DataStorageTable mPersistentDataTable; DataStorageTable mTemporaryDataTable; @@ -172,6 +185,7 @@ private: uint32_t mTimerDelay; // in milliseconds bool mPendingWrite; // true if a write is needed but hasn't been dispatched bool mShuttingDown; + bool mInitCalled; // Indicates that Init() has been called. // (End list of members protected by mMutex) Monitor mReadyMonitor; // Do not acquire this at the same time as mMutex. diff --git a/security/manager/ssl/DataStorageIPCUtils.h b/security/manager/ssl/DataStorageIPCUtils.h new file mode 100644 index 00000000000..cab159e6029 --- /dev/null +++ b/security/manager/ssl/DataStorageIPCUtils.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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 ipc_DataStorageIPCUtils_h +#define ipc_DataStorageIPCUtils_h + +#include "ipc/IPCMessageUtils.h" +#include "mozilla/DataStorage.h" + +namespace IPC { + template<> + struct ParamTraits : + public ContiguousEnumSerializer {}; +} // namespace IPC + +#endif // mozilla_DataStorageIPCUtils_hh diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build index 66639347aed..083442a5ed3 100644 --- a/security/manager/ssl/moz.build +++ b/security/manager/ssl/moz.build @@ -75,6 +75,10 @@ EXPORTS.mozilla.psm += [ 'PSMContentListener.h', ] +EXPORTS.ipc += [ + 'DataStorageIPCUtils.h', +] + UNIFIED_SOURCES += [ 'CertBlocklist.cpp', 'CryptoTask.cpp',