Bug 1228215 - Store each GMP's storage and nodeId salt in separate directories. r=jwwang

This commit is contained in:
Chris Pearce 2015-11-27 10:53:32 +13:00
Родитель 3da2dc5dd2
Коммит 537e205dfc
4 изменённых файлов: 120 добавлений и 82 удалений

Просмотреть файл

@ -291,8 +291,8 @@ GeckoMediaPluginServiceParent::InitStorage()
return rv;
}
// Prior to 42, GMP storage was stored in $profile/gmp/. After 42, it's
// stored in $profile/gmp/$platform/. So we must migrate any old records
// Prior to 42, GMP storage was stored in $profileDir/gmp/. After 42, it's
// stored in $profileDir/gmp/$platform/. So we must migrate any old records
// from the old location to the new location, for forwards compatibility.
MigratePreGecko42StorageDir(gmpDirWithoutPlatform, mStorageBaseDir);
@ -1245,11 +1245,12 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
HashString(aTopLevelOrigin));
if (aInPrivateBrowsing) {
// For PB mode, we store the node id, indexed by the origin pair,
// so that if the same origin pair is opened in this session, it gets
// the same node id.
// For PB mode, we store the node id, indexed by the origin pair and GMP name,
// so that if the same origin pair is opened for the same GMP in this session,
// it gets the same node id.
const uint32_t pbHash = AddToHash(HashString(aGMPName), hash);
nsCString* salt = nullptr;
if (!(salt = mTempNodeIds.Get(hash))) {
if (!(salt = mTempNodeIds.Get(pbHash))) {
// No salt stored, generate and temporarily store some for this id.
nsAutoCString newSalt;
rv = GenerateRandomPathName(newSalt, NodeIdSaltLength);
@ -1257,7 +1258,7 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
return rv;
}
salt = new nsCString(newSalt);
mTempNodeIds.Put(hash, salt);
mTempNodeIds.Put(pbHash, salt);
mPersistentStorageAllowed.Put(*salt, false);
}
aOutId = *salt;
@ -1266,18 +1267,29 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
// Otherwise, try to see if we've previously generated and stored salt
// for this origin pair.
nsCOMPtr<nsIFile> path; // $profileDir/gmp/
nsCOMPtr<nsIFile> path; // $profileDir/gmp/$platform/
rv = GetStorageDir(getter_AddRefs(path));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = path->Append(aGMPName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// $profileDir/gmp/$platform/$gmpName/
rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = path->AppendNative(NS_LITERAL_CSTRING("id"));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// $profileDir/gmp/id/
// $profileDir/gmp/$platform/$gmpName/id/
rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -1286,7 +1298,7 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
nsAutoCString hashStr;
hashStr.AppendInt((int64_t)hash);
// $profileDir/gmp/id/$hash
// $profileDir/gmp/$platform/$gmpName/id/$hash
rv = path->AppendNative(hashStr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -1323,13 +1335,13 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
}
MOZ_ASSERT(salt.Length() == NodeIdSaltLength);
// $profileDir/gmp/id/$hash/salt
// $profileDir/gmp/$platform/$gmpName/id/$hash/salt
rv = WriteToFile(path, NS_LITERAL_CSTRING("salt"), salt);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// $profileDir/gmp/id/$hash/origin
// $profileDir/gmp/$platform/$gmpName/id/$hash/origin
rv = WriteToFile(path,
NS_LITERAL_CSTRING("origin"),
NS_ConvertUTF16toUTF8(aOrigin));
@ -1337,7 +1349,7 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
return rv;
}
// $profileDir/gmp/id/$hash/topLevelOrigin
// $profileDir/gmp/$platform/$gmpName/id/$hash/topLevelOrigin
rv = WriteToFile(path,
NS_LITERAL_CSTRING("topLevelOrigin"),
NS_ConvertUTF16toUTF8(aTopLevelOrigin));
@ -1483,25 +1495,37 @@ private:
void
GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(DirectoryFilter& aFilter)
{
nsresult rv;
// $profileDir/gmp/$platform/
nsCOMPtr<nsIFile> path;
// $profileDir/gmp/
rv = GetStorageDir(getter_AddRefs(path));
nsresult rv = GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return;
}
// $profileDir/gmp/id/
rv = path->AppendNative(NS_LITERAL_CSTRING("id"));
if (NS_FAILED(rv)) {
// Iterate all sub-folders of $profileDir/gmp/$platform/, i.e. the dirs in which
// specific GMPs store their data.
DirectoryEnumerator iter(path, DirectoryEnumerator::DirsOnly);
for (nsCOMPtr<nsIFile> pluginDir; (pluginDir = iter.Next()) != nullptr;) {
ClearNodeIdAndPlugin(pluginDir, aFilter);
}
}
void
GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir,
DirectoryFilter& aFilter)
{
// $profileDir/gmp/$platform/$gmpName/id/
nsCOMPtr<nsIFile> path = CloneAndAppend(aPluginStorageDir, NS_LITERAL_STRING("id"));
if (!path) {
return;
}
// Iterate all sub-folders of $profileDir/gmp/id/
// Iterate all sub-folders of $profileDir/gmp/$platform/$gmpName/id/
nsTArray<nsCString> nodeIDsToClear;
DirectoryEnumerator iter(path, DirectoryEnumerator::DirsOnly);
for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) {
// dirEntry is the hash of origins, i.e.:
// $profileDir/gmp/$platform/$gmpName/id/$originHash/
if (!aFilter(dirEntry)) {
continue;
}
@ -1518,28 +1542,23 @@ GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(DirectoryFilter& aFilter)
}
}
// Kill plugins that have node IDs to be cleared.
// Kill plugin instances that have node IDs being cleared.
KillPlugins(mPlugins, mMutex, NodeFilter(nodeIDsToClear));
// Clear all matching $profileDir/gmp/storage/$nodeId/
rv = GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
// Clear all storage in $profileDir/gmp/$platform/$gmpName/storage/$nodeId/
path = CloneAndAppend(aPluginStorageDir, NS_LITERAL_STRING("storage"));
if (!path) {
return;
}
rv = path->AppendNative(NS_LITERAL_CSTRING("storage"));
if (NS_FAILED(rv)) {
return;
}
for (size_t i = 0; i < nodeIDsToClear.Length(); i++) {
for (const nsCString& nodeId : nodeIDsToClear) {
nsCOMPtr<nsIFile> dirEntry;
rv = path->Clone(getter_AddRefs(dirEntry));
nsresult rv = path->Clone(getter_AddRefs(dirEntry));
if (NS_FAILED(rv)) {
continue;
}
rv = dirEntry->AppendNative(nodeIDsToClear[i]);
rv = dirEntry->AppendNative(nodeId);
if (NS_FAILED(rv)) {
continue;
}
@ -1574,16 +1593,9 @@ GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread(PRTime aSince)
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: since=%lld", __CLASS__, __FUNCTION__, (int64_t)aSince));
nsCOMPtr<nsIFile> storagePath;
nsCOMPtr<nsIFile> temp;
if (NS_SUCCEEDED(GetStorageDir(getter_AddRefs(temp))) &&
NS_SUCCEEDED(temp->AppendNative(NS_LITERAL_CSTRING("storage")))) {
storagePath = temp.forget();
}
struct MTimeFilter : public DirectoryFilter {
explicit MTimeFilter(PRTime aSince, already_AddRefed<nsIFile> aPath)
: mSince(aSince), mStoragePath(aPath) {}
explicit MTimeFilter(PRTime aSince)
: mSince(aSince) {}
// Return true if any files under aPath is modified after |mSince|.
bool IsModifiedAfter(nsIFile* aPath) {
@ -1601,36 +1613,38 @@ GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread(PRTime aSince)
return false;
}
// |aPath| is $profileDir/gmp/id/$hash
// |aPath| is $profileDir/gmp/$platform/$gmpName/id/$originHash/
virtual bool operator()(nsIFile* aPath) {
if (IsModifiedAfter(aPath)) {
return true;
}
nsAutoCString salt;
nsresult rv = ReadSalt(aPath, salt);
if (NS_FAILED(rv)) {
if (NS_FAILED(ReadSalt(aPath, salt))) {
return false;
}
// $profileDir/gmp/storage/
if (!mStoragePath) {
// $profileDir/gmp/$platform/$gmpName/id/
nsCOMPtr<nsIFile> idDir;
if (NS_FAILED(aPath->GetParent(getter_AddRefs(idDir)))) {
return false;
}
// $profileDir/gmp/storage/$nodeId/
nsCOMPtr<nsIFile> path;
rv = mStoragePath->Clone(getter_AddRefs(path));
if (NS_FAILED(rv)) {
// $profileDir/gmp/$platform/$gmpName/
nsCOMPtr<nsIFile> temp;
if (NS_FAILED(idDir->GetParent(getter_AddRefs(temp)))) {
return false;
}
rv = path->AppendNative(salt);
return NS_SUCCEEDED(rv) && IsModifiedAfter(path);
// $profileDir/gmp/$platform/$gmpName/storage/
if (NS_FAILED(temp->Append(NS_LITERAL_STRING("storage")))) {
return false;
}
// $profileDir/gmp/$platform/$gmpName/storage/$originSalt
return NS_SUCCEEDED(temp->AppendNative(salt)) && IsModifiedAfter(temp);
}
private:
const PRTime mSince;
const nsCOMPtr<nsIFile> mStoragePath;
} filter(aSince, storagePath.forget());
} filter(aSince);
ClearNodeIdAndPlugin(filter);
@ -1659,7 +1673,7 @@ GeckoMediaPluginServiceParent::ClearStorage()
// Kill plugins with valid nodeIDs.
KillPlugins(mPlugins, mMutex, &IsNodeIdValid);
nsCOMPtr<nsIFile> path; // $profileDir/gmp/
nsCOMPtr<nsIFile> path; // $profileDir/gmp/$platform/
nsresult rv = GetStorageDir(getter_AddRefs(path));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;

Просмотреть файл

@ -97,7 +97,8 @@ private:
~DirectoryFilter() {}
};
void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir,
DirectoryFilter& aFilter);
void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
void ClearRecentHistoryOnGMPThread(PRTime aSince);

Просмотреть файл

@ -32,10 +32,12 @@ extern LogModule* GetGMPLog();
namespace gmp {
// We store the records in files in the profile dir.
// $profileDir/gmp/storage/$nodeId/
// We store the records for a given GMP as files in the profile dir.
// $profileDir/gmp/$platform/$gmpName/storage/$nodeId/
static nsresult
GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
GetGMPStorageDir(nsIFile** aTempDir,
const nsString& aGMPName,
const nsCString& aNodeId)
{
if (NS_WARN_IF(!aTempDir)) {
return NS_ERROR_INVALID_ARG;
@ -53,6 +55,16 @@ GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
return rv;
}
rv = tmpFile->Append(aGMPName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage"));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -87,8 +99,10 @@ GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
// record bytes (entire remainder of file)
class GMPDiskStorage : public GMPStorage {
public:
explicit GMPDiskStorage(const nsCString& aNodeId)
explicit GMPDiskStorage(const nsCString& aNodeId,
const nsString& aGMPName)
: mNodeId(aNodeId)
, mGMPName(aGMPName)
{
}
@ -106,7 +120,7 @@ public:
nsresult Init() {
// Build our index of records on disk.
nsCOMPtr<nsIFile> storageDir;
nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId);
nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
@ -318,7 +332,7 @@ private:
nsString& aOutFilename)
{
nsCOMPtr<nsIFile> storageDir;
nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId);
nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -363,7 +377,7 @@ private:
MOZ_ASSERT(aOutFD);
nsCOMPtr<nsIFile> f;
nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mNodeId);
nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -440,7 +454,7 @@ private:
nsresult RemoveStorageFile(const nsString& aFilename)
{
nsCOMPtr<nsIFile> f;
nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mNodeId);
nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -469,6 +483,7 @@ private:
// Hash record name to record data.
nsClassHashtable<nsCStringHashKey, Record> mRecords;
const nsAutoCString mNodeId;
const nsString mGMPName;
};
class GMPMemoryStorage : public GMPStorage {
@ -576,7 +591,8 @@ GMPStorageParent::Init()
return NS_ERROR_FAILURE;
}
if (persistent) {
UniquePtr<GMPDiskStorage> storage = MakeUnique<GMPDiskStorage>(mNodeId);
UniquePtr<GMPDiskStorage> storage =
MakeUnique<GMPDiskStorage>(mNodeId, mPlugin->GetPluginBaseName());
if (NS_FAILED(storage->Init())) {
NS_WARNING("Failed to initialize on disk GMP storage");
return NS_ERROR_FAILURE;

Просмотреть файл

@ -273,7 +273,7 @@ EnumerateDir(nsIFile* aPath, T&& aDirIter)
}
/**
* Enumerate files under $profileDir/gmp/$aDir/ (non-recursive).
* Enumerate files under $profileDir/gmp/$platform/gmp-fake/$aDir/ (non-recursive).
*/
template<typename T>
static nsresult
@ -283,14 +283,21 @@ EnumerateGMPStorageDir(const nsACString& aDir, T&& aDirIter)
GeckoMediaPluginServiceParent::GetSingleton();
MOZ_ASSERT(service);
// $profileDir/gmp/
// $profileDir/gmp/$platform/
nsCOMPtr<nsIFile> path;
nsresult rv = service->GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return rv;
}
// $profileDir/gmp/$aDir/
// $profileDir/gmp/$platform/gmp-fake/
rv = path->Append(NS_LITERAL_STRING("gmp-fake"));
if (NS_FAILED(rv)) {
return rv;
}
// $profileDir/gmp/$platform/gmp-fake/$aDir/
rv = path->AppendNative(aDir);
if (NS_FAILED(rv)) {
return rv;
@ -821,10 +828,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/id/.
* 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/id/.
* 3. Pass |t| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage are removed.
* 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
* $profileDir/gmp/$platform/gmp-fake/storage are removed.
*/
void TestClearRecentHistory1() {
AssertIsOnGMPThread();
@ -843,10 +850,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/storage/.
* 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/.
* 3. Pass |t| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage are removed.
* 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
* $profileDir/gmp/$platform/gmp-fake/storage are removed.
*/
void TestClearRecentHistory2() {
AssertIsOnGMPThread();
@ -865,10 +872,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/storage/.
* 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/.
* 3. Pass |t+1| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage remain unchanged.
* 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
* $profileDir/gmp/$platform/gmp-fake/storage remain unchanged.
*/
void TestClearRecentHistory3() {
AssertIsOnGMPThread();
@ -949,13 +956,13 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
FileCounter c1;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be no files under $profileDir/gmp/id/
// There should be no files under $profileDir/gmp/$platform/gmp-fake/id/
EXPECT_EQ(c1.GetCount(), 0);
FileCounter c2;
rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be no files under $profileDir/gmp/storage/
// There should be no files under $profileDir/gmp/$platform/gmp-fake/storage/
EXPECT_EQ(c2.GetCount(), 0);
SetFinished();
@ -965,13 +972,13 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
FileCounter c1;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be one directory under $profileDir/gmp/id/
// There should be one directory under $profileDir/gmp/$platform/gmp-fake/id/
EXPECT_EQ(c1.GetCount(), 1);
FileCounter c2;
rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be one directory under $profileDir/gmp/storage/
// There should be one directory under $profileDir/gmp/$platform/gmp-fake/storage/
EXPECT_EQ(c2.GetCount(), 1);
SetFinished();