Bug 1420836 - Part3 - Try to compute the storage id in GMP process and implement RequestStorageId for CDM. draft
authorJames Cheng <jacheng@mozilla.com>
Fri, 15 Dec 2017 14:57:48 -0600
changeset 712298 ac35e79343152d46308098cf6f4e226e4bb9ab9c
parent 712297 d077e22ab929af875cd74af6874df1af52f30969
child 744025 1d2a3280cb8f5b11a88c60d2034c9afe23104188
push id93304
push userbmo:jacheng@mozilla.com
push dateFri, 15 Dec 2017 22:09:01 +0000
bugs1420836
milestone59.0a1
Bug 1420836 - Part3 - Try to compute the storage id in GMP process and implement RequestStorageId for CDM. GMPParent has computed the origin salt so I try to pass it to GMPChild. Then, try to compute the storage id before sandboxing. Pass the storage id to ChromiumCDMChild by its Init function. MozReview-Commit-ID: HIur4dH9Hn8
dom/media/gmp/ChromiumCDMChild.cpp
dom/media/gmp/ChromiumCDMChild.h
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPChild.h
dom/media/gmp/GMPContentChild.cpp
dom/media/gmp/GMPParent.cpp
dom/media/gmp/PGMP.ipdl
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "ChromiumCDMChild.h"
+#include "CDMStorageIdProvider.h"
 #include "GMPContentChild.h"
 #include "WidevineUtils.h"
 #include "WidevineFileIO.h"
 #include "WidevineVideoFrame.h"
 #include "GMPLog.h"
 #include "GMPPlatform.h"
 #include "mozilla/Unused.h"
 #include "nsPrintfCString.h"
@@ -22,21 +23,23 @@ namespace gmp {
 ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
   : mPlugin(aPlugin)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild:: ctor this=%p", this);
 }
 
 void
-ChromiumCDMChild::Init(cdm::ContentDecryptionModule_9* aCDM)
+ChromiumCDMChild::Init(cdm::ContentDecryptionModule_9* aCDM,
+                       const nsCString& aStorageId)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   mCDM = aCDM;
   MOZ_ASSERT(mCDM);
+  mCurrentStorageId = aStorageId;
 }
 
 void
 ChromiumCDMChild::TimerExpired(void* aContext)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::TimerExpired(context=0x%p)", aContext);
   if (mCDM) {
@@ -471,16 +474,36 @@ ChromiumCDMChild::CreateFileIO(cdm::File
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::CreateFileIO()");
   if (!mPersistentStateAllowed) {
     return nullptr;
   }
   return new WidevineFileIO(aClient);
 }
 
+void
+ChromiumCDMChild::RequestStorageId(uint32_t aVersion)
+{
+  MOZ_ASSERT(IsOnMessageLoopThread());
+  GMP_LOG("ChromiumCDMChild::RequestStorageId() aVersion = %u", aVersion);
+  // aVersion >= 0x80000000 are reserved.
+  if (aVersion >= 0x80000000) {
+    mCDM->OnStorageId(aVersion, nullptr, 0);
+    return;
+  }
+  if (aVersion > CDMStorageIdProviderBase::kCurrentVersion) {
+    mCDM->OnStorageId(aVersion, nullptr, 0);
+    return;
+  }
+  // mCurrentStorageId will be empty if we compute storage failed.
+  mCDM->OnStorageId(CDMStorageIdProviderBase::kCurrentVersion,
+                    reinterpret_cast<const uint8_t*>(mCurrentStorageId.get()),
+                    mCurrentStorageId.Length());
+}
+
 ChromiumCDMChild::~ChromiumCDMChild()
 {
   GMP_LOG("ChromiumCDMChild:: dtor this=%p", this);
 }
 
 bool
 ChromiumCDMChild::IsOnMessageLoopThread()
 {
--- a/dom/media/gmp/ChromiumCDMChild.h
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -20,17 +20,17 @@ class ChromiumCDMChild : public PChromiu
                        , public cdm::Host_8
                        , public cdm::Host_9
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMChild);
 
   explicit ChromiumCDMChild(GMPContentChild* aPlugin);
 
-  void Init(cdm::ContentDecryptionModule_9* aCDM);
+  void Init(cdm::ContentDecryptionModule_9* aCDM, const nsCString& aStorageId);
 
   void TimerExpired(void* aContext);
 
   // cdm::Host_9 implementation
   cdm::Buffer* Allocate(uint32_t aCapacity) override;
   void SetTimer(int64_t aDelayMs, void* aContext) override;
   cdm::Time GetCurrentWallTime() override;
   // cdm::Host_9 interface
@@ -66,17 +66,17 @@ public:
                              uint32_t aServiceIdSize,
                              const char* aChallenge,
                              uint32_t aChallengeSize) override {}
   void EnableOutputProtection(uint32_t aDesiredProtectionMask) override {}
   void QueryOutputProtectionStatus() override {}
   void OnDeferredInitializationDone(cdm::StreamType aStreamType,
                                     cdm::Status aDecoderStatus) override {}
   // cdm::Host_9 interface
-  void RequestStorageId(uint32_t aVersion) override {}
+  void RequestStorageId(uint32_t aVersion) override;
   cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override;
 
   // cdm::Host_8 implementation
   void OnSessionMessage(const char* aSessionId,
                         uint32_t aSessionIdSize,
                         cdm::MessageType aMessageType,
                         const char* aMessage,
                         uint32_t aMessageSize,
@@ -157,14 +157,15 @@ protected:
   nsTArray<uint32_t> mLoadSessionPromiseIds;
 
   cdm::Size mCodedSize;
   nsTArray<ipc::Shmem> mBuffers;
 
   bool mDecoderInitialized = false;
   bool mPersistentStateAllowed = false;
   bool mDestroyed = false;
+  nsCString mCurrentStorageId;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // ChromiumCDMChild_h_
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "GMPChild.h"
+#include "CDMStorageIdProvider.h"
 #include "GMPContentChild.h"
 #include "GMPProcessChild.h"
 #include "GMPLoader.h"
 #include "GMPVideoDecoderChild.h"
 #include "GMPVideoEncoderChild.h"
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsExceptionHandler.h"
@@ -21,16 +22,20 @@
 #include "mozilla/ipc/ProcessChild.h"
 #include "GMPUtils.h"
 #include "prio.h"
 #include "base/task.h"
 #include "base/command_line.h"
 #include "ChromiumCDMAdapter.h"
 #include "GMPLog.h"
 
+#ifdef SUPPORT_STORAGE_ID
+#include "rlz/lib/machine_id.h"
+#endif
+
 using namespace mozilla::ipc;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #include "WinUtils.h"
 #else
 #include <unistd.h> // for _exit()
 #endif
@@ -249,16 +254,46 @@ GMPChild::Init(const nsAString& aPluginP
 
   CrashReporterClient::InitSingleton(this);
 
   mPluginPath = aPluginPath;
 
   return true;
 }
 
+mozilla::ipc::IPCResult
+GMPChild::RecvProvideOriginSalt(const nsCString& aOriginSalt)
+{
+  LOGD("%s", __FUNCTION__);
+
+  // Compute the current storage id here before starting gmp sandboxing.
+  // Store it and it will be passed to ChromiumCDMChild.
+  mCurrentStorageId = "";
+#ifdef SUPPORT_STORAGE_ID
+  std::string machineId;
+  if (!rlz_lib::GetMachineId(&machineId)) {
+    LOGD("%s get machineId failed.", __FUNCTION__);
+    return IPC_OK();
+  }
+  std::string originSalt(aOriginSalt.BeginReading(), aOriginSalt.Length());
+  auto provider = CDMStorageIdProviderBase::CreateProvider(CDMStorageIdProviderBase::kCDMRequestLatestVersion);
+  auto factors = MakePrerequisiteFactors(CDMStorageIdProviderBase::kCDMRequestLatestVersion,
+                                         machineId,
+                                         originSalt);
+
+  std::string storageId;
+  if (!provider->ComputeStorageId(storageId, *factors)) {
+    LOGD("%s failed to compute storage id.", __FUNCTION__);
+    return IPC_OK();
+  }
+  mCurrentStorageId = storageId.c_str();
+#endif
+  return IPC_OK();
+}
+
 GMPErr
 GMPChild::GetAPI(const char* aAPIName,
                  void* aHostAPI,
                  void** aPluginAPI,
                  uint32_t aDecryptorId)
 {
   if (!mGMPLoader) {
     return GMPGenericErr;
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -41,16 +41,17 @@ public:
 
 private:
   friend class GMPContentChild;
 
   bool ResolveLinks(nsCOMPtr<nsIFile>& aPath);
 
   bool GetUTF8LibPath(nsACString& aOutLibPath);
 
+  mozilla::ipc::IPCResult RecvProvideOriginSalt(const nsCString& aOriginSalt) override;
   mozilla::ipc::IPCResult AnswerStartPlugin(const nsString& aAdapter) override;
   mozilla::ipc::IPCResult RecvPreloadLibs(const nsCString& aLibs) override;
 
   PGMPTimerChild* AllocPGMPTimerChild() override;
   bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) override;
 
   PGMPStorageChild* AllocPGMPStorageChild() override;
   bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) override;
@@ -71,15 +72,16 @@ private:
 
   nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
 
   RefPtr<GMPTimerChild> mTimerChild;
   RefPtr<GMPStorageChild> mStorage;
 
   MessageLoop* mGMPMessageLoop;
   nsString mPluginPath;
+  nsCString mCurrentStorageId;
   UniquePtr<GMPLoader> mGMPLoader;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPChild_h_
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -300,17 +300,18 @@ GMPContentChild::RecvPChromiumCDMConstru
       return IPC_FAIL_NO_REASON(this);
     }
     cdm =
       new ChromiumCDM8BackwardsCompat(
         host9,
         static_cast<cdm::ContentDecryptionModule_8*>(cdm));
   }
 
-  child->Init(static_cast<cdm::ContentDecryptionModule_9*>(cdm));
+  child->Init(static_cast<cdm::ContentDecryptionModule_9*>(cdm),
+              mGMPChild->mCurrentStorageId);
 
   return IPC_OK();
 }
 
 void
 GMPContentChild::CloseActive()
 {
   // Invalidate and remove any remaining API objects.
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -170,16 +170,24 @@ GMPParent::LoadProcess()
     if (!opened) {
       LOGD("%s: Failed to open channel to new child process", __FUNCTION__);
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
     LOGD("%s: Opened channel to new child process", __FUNCTION__);
 
+
+    bool ok = SendProvideOriginSalt(mNodeId);
+    if (!ok) {
+      LOGD("%s: Failed to send origin salt to child process", __FUNCTION__);
+      return NS_ERROR_FAILURE;
+    }
+    LOGD("%s: Sent origin salt to child process", __FUNCTION__);
+
 #ifdef XP_WIN
     if (!mLibs.IsEmpty()) {
       bool ok = SendPreloadLibs(mLibs);
       if (!ok) {
         LOGD("%s: Failed to send preload-libs to child process", __FUNCTION__);
         return NS_ERROR_FAILURE;
       }
       LOGD("%s: Sent preload-libs ('%s') to child process", __FUNCTION__, mLibs.get());
--- a/dom/media/gmp/PGMP.ipdl
+++ b/dom/media/gmp/PGMP.ipdl
@@ -22,15 +22,16 @@ parent:
   async PGMPTimer();
   async PGMPStorage();
 
   async PGMPContentChildDestroyed();
 
 child:
   async CrashPluginNow();
   intr StartPlugin(nsString adapter);
+  async ProvideOriginSalt(nsCString originSalt);
   async PreloadLibs(nsCString libs);
   async CloseActive();
   async InitGMPContentChild(Endpoint<PGMPContentChild> endpoint);
 };
 
 } // namespace gmp
 } // namespace mozilla