Bug 1184333 - Handle UTF8 paths as input for GMP loading. r=bobowen, a=lmandel
authorChris Pearce <cpearce@mozilla.com>
Fri, 17 Jul 2015 11:09:49 +1200
changeset 275389 088c2c8e4beccb3c09f3e6c22543beabbc3a3d9f
parent 275388 c8499fa138a9b7eac6b03d4509302a8a05fef5ac
child 275390 e549349b8d6659c2db0355450d86298773bcb81f
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen, lmandel
bugs1184333
milestone40.0
Bug 1184333 - Handle UTF8 paths as input for GMP loading. r=bobowen, a=lmandel
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPChild.h
dom/media/gmp/GMPLoader.cpp
dom/media/gmp/GMPLoader.h
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -51,16 +51,23 @@ extern PRLogModuleInfo* GetGMPLog();
 #define LOGD(x, ...) LOG(PR_LOG_DEBUG, "GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), ##__VA_ARGS__)
 #else
 #define LOG(level, x, ...)
 #define LOGD(x, ...)
 #endif
 
 namespace gmp {
 
+static bool
+FileExists(nsIFile* aFile)
+{
+  bool exists = false;
+  return aFile && NS_SUCCEEDED(aFile->Exists(&exists)) && exists;
+}
+
 GMPChild::GMPChild()
   : mAsyncShutdown(nullptr)
   , mGMPMessageLoop(MessageLoop::current())
   , mGMPLoader(nullptr)
 {
   LOGD("GMPChild ctor");
   nsDebugImpl::SetMultiprocessMode("GMP");
 }
@@ -269,17 +276,17 @@ GMPChild::Init(const std::string& aPlugi
     return false;
   }
 
 #ifdef MOZ_CRASHREPORTER
   SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
 #endif
 
   mPluginPath = aPluginPath;
-  mVoucherPath = aVoucherPath;
+  mSandboxVoucherPath = aVoucherPath;
   return true;
 }
 
 bool
 GMPChild::RecvSetNodeId(const nsCString& aNodeId)
 {
   LOGD("%s nodeId=%s", __FUNCTION__, aNodeId.Data());
 
@@ -323,16 +330,17 @@ GMPChild::PreLoadLibraries(const std::st
   nsCOMPtr<nsIFile> infoFile;
   GetInfoFile(aPluginPath, infoFile);
 
   nsString path;
   infoFile->GetPath(path);
 
   std::ifstream stream;
 #ifdef _MSC_VER
+  // Must use UTF16 for Windows for paths for non-Latin characters.
   stream.open(static_cast<const wchar_t*>(path.get()));
 #else
   stream.open(NS_ConvertUTF16toUTF8(path).get());
 #endif
   if (!stream.good()) {
     NS_WARNING("Failure opening info file for required DLLs");
     return false;
   }
@@ -363,47 +371,60 @@ GMPChild::PreLoadLibraries(const std::st
     }
   } while (!stream.eof());
 
   return true;
 }
 #endif
 
 bool
-GMPChild::GetLibPath(nsACString& aOutLibPath)
+GMPChild::GetUTF8LibPath(nsACString& aOutLibPath)
 {
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   nsAutoCString pluginDirectoryPath, pluginFilePath;
   if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
     MOZ_CRASH("Error scanning plugin path");
   }
   aOutLibPath.Assign(pluginFilePath);
   return true;
 #else
   nsCOMPtr<nsIFile> libFile;
   if (!GetPluginFile(mPluginPath, libFile)) {
     return false;
   }
-  return NS_SUCCEEDED(libFile->GetNativePath(aOutLibPath));
+
+  if (!FileExists(libFile)) {
+    NS_WARNING("Can't find GMP library file!");
+    return false;
+  }
+
+  nsAutoString path;
+  libFile->GetPath(path);
+  aOutLibPath = NS_ConvertUTF16toUTF8(path);
+
+  return true;
 #endif
 }
 
 bool
 GMPChild::RecvStartPlugin()
 {
   LOGD("%s", __FUNCTION__);
 
 #if defined(XP_WIN)
   PreLoadLibraries(mPluginPath);
 #endif
-  PreLoadPluginVoucher(mPluginPath);
+  if (!PreLoadPluginVoucher(mPluginPath)) {
+    NS_WARNING("Plugin voucher failed to load!");
+    return false;
+  }
   PreLoadSandboxVoucher();
 
   nsCString libPath;
-  if (!GetLibPath(libPath)) {
+  if (!GetUTF8LibPath(libPath)) {
     return false;
   }
 
   auto platformAPI = new GMPPlatformAPI();
   InitPlatformAPI(*platformAPI, this);
 
   mGMPLoader = GMPProcessChild::GetGMPLoader();
   if (!mGMPLoader) {
@@ -609,21 +630,30 @@ GetPluginVoucherFile(const std::string& 
 }
 
 bool
 GMPChild::PreLoadPluginVoucher(const std::string& aPluginPath)
 {
   nsCOMPtr<nsIFile> voucherFile;
   GetPluginVoucherFile(aPluginPath, voucherFile);
 
+  if (!FileExists(voucherFile)) {
+    return true;
+  }
+
   nsString path;
   voucherFile->GetPath(path);
 
   std::ifstream stream;
+  #ifdef _MSC_VER
+  // Must use UTF16 for Windows for paths for non-Latin characters.
+  stream.open(static_cast<const wchar_t*>(path.get()), std::ios::binary);
+  #else
   stream.open(NS_ConvertUTF16toUTF8(path).get(), std::ios::binary);
+  #endif
   if (!stream.good()) {
     return false;
   }
 
   std::streampos start = stream.tellg();
   stream.seekg (0, std::ios::end);
   std::streampos end = stream.tellg();
   stream.seekg (0, std::ios::beg);
@@ -642,17 +672,25 @@ GMPChild::PreLoadPluginVoucher(const std
 
   return true;
 }
 
 void
 GMPChild::PreLoadSandboxVoucher()
 {
   std::ifstream stream;
-  stream.open(mVoucherPath.c_str(), std::ios::binary);
+  #ifdef _MSC_VER
+  // Must use UTF16 for Windows for paths for non-Latin characters.
+  nsDependentCString utf8Path(mSandboxVoucherPath.c_str(),
+                              mSandboxVoucherPath.size());
+  NS_ConvertUTF8toUTF16 utf16Path(utf8Path);
+  stream.open(static_cast<const wchar_t*>(utf16Path.get()), std::ios::binary);
+  #else
+  stream.open(mSandboxVoucherPath.c_str(), std::ios::binary);
+  #endif
   if (!stream.good()) {
     NS_WARNING("PreLoadSandboxVoucher can't find sandbox voucher file!");
     return;
   }
 
   std::streampos start = stream.tellg();
   stream.seekg (0, std::ios::end);
   std::streampos end = stream.tellg();
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -48,17 +48,17 @@ public:
 #endif
 
 private:
   friend class GMPContentChild;
 
   bool PreLoadPluginVoucher(const std::string& aPluginPath);
   void PreLoadSandboxVoucher();
 
-  bool GetLibPath(nsACString& aOutLibPath);
+  bool GetUTF8LibPath(nsACString& aOutLibPath);
 
   virtual bool RecvSetNodeId(const nsCString& aNodeId) override;
   virtual bool RecvStartPlugin() override;
 
   virtual PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) override;
   virtual bool DeallocPCrashReporterChild(PCrashReporterChild*) override;
 
   virtual PGMPTimerChild* AllocPGMPTimerChild() override;
@@ -83,17 +83,17 @@ private:
   nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
 
   GMPAsyncShutdown* mAsyncShutdown;
   nsRefPtr<GMPTimerChild> mTimerChild;
   nsRefPtr<GMPStorageChild> mStorage;
 
   MessageLoop* mGMPMessageLoop;
   std::string mPluginPath;
-  std::string mVoucherPath;
+  std::string mSandboxVoucherPath;
   std::string mNodeId;
   GMPLoader* mGMPLoader;
   nsTArray<uint8_t> mPluginVoucher;
   nsTArray<uint8_t> mSandboxVoucher;
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -4,16 +4,17 @@
  * 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 "GMPLoader.h"
 #include <stdio.h>
 #include "mozilla/Attributes.h"
 #include "gmp-entrypoints.h"
 #include "prlink.h"
+#include "nsAutoPtr.h"
 
 #include <string>
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "mozilla/Scoped.h"
 #include "windows.h"
 #include <intrin.h>
 #include <assert.h>
@@ -63,18 +64,18 @@ namespace gmp {
 
 class GMPLoaderImpl : public GMPLoader {
 public:
   explicit GMPLoaderImpl(SandboxStarter* aStarter)
     : mSandboxStarter(aStarter)
   {}
   virtual ~GMPLoaderImpl() {}
 
-  virtual bool Load(const char* aLibPath,
-                    uint32_t aLibPathLen,
+  virtual bool Load(const char* aUTF8LibPath,
+                    uint32_t aUTF8LibPathLen,
                     char* aOriginSalt,
                     uint32_t aOriginSaltLen,
                     const GMPPlatformAPI* aPlatformAPI) override;
 
   virtual GMPErr GetAPI(const char* aAPIName,
                         void* aHostAPI,
                         void** aPluginAPI) override;
 
@@ -127,18 +128,18 @@ GetStackAfterCurrentFrame(uint8_t** aOut
   }
   *aOutTop = top;
   *aOutBottom = bottom;
   return true;
 }
 #endif
 
 bool
-GMPLoaderImpl::Load(const char* aLibPath,
-                    uint32_t aLibPathLen,
+GMPLoaderImpl::Load(const char* aUTF8LibPath,
+                    uint32_t aUTF8LibPathLen,
                     char* aOriginSalt,
                     uint32_t aOriginSaltLen,
                     const GMPPlatformAPI* aPlatformAPI)
 {
   std::string nodeId;
 #ifdef HASH_NODE_ID_WITH_DEVICE_ID
   if (aOriginSaltLen > 0) {
     string16 deviceId;
@@ -191,46 +192,49 @@ GMPLoaderImpl::Load(const char* aLibPath
     nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   // If the GMP DLL is a side-by-side assembly with static imports then the DLL
   // loader will attempt to create an activation context which will fail because
   // of the sandbox. If we create an activation context before we start the
   // sandbox then this one will get picked up by the DLL loader.
-  int pathLen = MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, nullptr, 0);
+  int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
   if (pathLen == 0) {
     return false;
   }
 
-  wchar_t* widePath = new wchar_t[pathLen];
-  if (MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, widePath, pathLen) == 0) {
-    delete[] widePath;
+  nsAutoArrayPtr<wchar_t> widePath(new wchar_t[pathLen]);
+  if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath, pathLen) == 0) {
     return false;
   }
 
   ACTCTX actCtx = { sizeof(actCtx) };
   actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
   actCtx.lpSource = widePath;
   actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
   ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx));
-  delete[] widePath;
 #endif
 
   // Start the sandbox now that we've generated the device bound node id.
   // This must happen after the node id is bound to the device id, as
   // generating the device id requires privileges.
-  if (mSandboxStarter && !mSandboxStarter->Start(aLibPath)) {
+  if (mSandboxStarter && !mSandboxStarter->Start(aUTF8LibPath)) {
     return false;
   }
 
   // Load the GMP.
   PRLibSpec libSpec;
-  libSpec.value.pathname = aLibPath;
+#ifdef XP_WIN
+  libSpec.value.pathname_u = widePath;
+  libSpec.type = PR_LibSpec_PathnameU;
+#else
+  libSpec.value.pathname = aUTF8LibPath;
   libSpec.type = PR_LibSpec_Pathname;
+#endif
   mLib = PR_LoadLibraryWithFlags(libSpec, 0);
   if (!mLib) {
     return false;
   }
 
   GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
   if (!initFunc) {
     return false;
--- a/dom/media/gmp/GMPLoader.h
+++ b/dom/media/gmp/GMPLoader.h
@@ -47,17 +47,17 @@ public:
 // per child process (so the GMPLoader only loads one GMP).
 class GMPLoader {
 public:
   virtual ~GMPLoader() {}
 
   // Calculates the device-bound node id, then activates the sandbox,
   // then loads the GMP library and (if applicable) passes the bound node id
   // to the GMP.
-  virtual bool Load(const char* aLibPath,
+  virtual bool Load(const char* aUTF8LibPath,
                     uint32_t aLibPathLen,
                     char* aOriginSalt,
                     uint32_t aOriginSaltLen,
                     const GMPPlatformAPI* aPlatformAPI) = 0;
 
   // Retrieves an interface pointer from the GMP.
   virtual GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) = 0;