bug 1066326. Pre-load (load before starting sandbox) DLLs that are specified in the plugin info file and that are in a pre-approved whitelist. r=jesup, r=cpearce, r=bobowen
authorTim Abraldes <tabraldes@mozilla.com>
Thu, 09 Oct 2014 08:45:22 -0700
changeset 232796 842efe1a471bc81a0722ff34722f6a368504e036
parent 232795 9bdba7a66515c4a620e296e89c9c00814a795b6e
child 232797 199775c34d695ce8dc85d9eb99bb2f264c78eef0
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersjesup, cpearce, bobowen
bugs1066326
milestone35.0a1
bug 1066326. Pre-load (load before starting sandbox) DLLs that are specified in the plugin info file and that are in a pre-approved whitelist. r=jesup, r=cpearce, r=bobowen
content/media/gmp/GMPChild.cpp
content/media/gmp/GMPChild.h
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -11,16 +11,20 @@
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/dom/CrashReporterChild.h"
+#ifdef XP_WIN
+#include <fstream>
+#include "nsCRT.h"
+#endif
 
 using mozilla::dom::CrashReporterChild;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
@@ -46,63 +50,95 @@ GMPChild::GMPChild()
   nsDebugImpl::SetMultiprocessMode("GMP");
 }
 
 GMPChild::~GMPChild()
 {
 }
 
 static bool
-GetPluginFile(const std::string& aPluginPath,
+GetFileBase(const std::string& aPluginPath,
 #if defined(XP_MACOSX)
-              nsCOMPtr<nsIFile>& aLibDirectory,
+            nsCOMPtr<nsIFile>& aLibDirectory,
 #endif
-              nsCOMPtr<nsIFile>& aLibFile)
+            nsCOMPtr<nsIFile>& aFileBase,
+            nsAutoString& aBaseName)
 {
   nsDependentCString pluginPath(aPluginPath.c_str());
 
   nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(pluginPath),
-                                true, getter_AddRefs(aLibFile));
+                                true, getter_AddRefs(aFileBase));
   if (NS_FAILED(rv)) {
     return false;
   }
 
 #if defined(XP_MACOSX)
-  if (NS_FAILED(aLibFile->Clone(getter_AddRefs(aLibDirectory)))) {
+  if (NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory)))) {
     return false;
   }
 #endif
 
   nsCOMPtr<nsIFile> parent;
-  rv = aLibFile->GetParent(getter_AddRefs(parent));
+  rv = aFileBase->GetParent(getter_AddRefs(parent));
   if (NS_FAILED(rv)) {
     return false;
   }
 
   nsAutoString parentLeafName;
   rv = parent->GetLeafName(parentLeafName);
   if (NS_FAILED(rv)) {
     return false;
   }
 
-  nsAutoString baseName(Substring(parentLeafName, 4, parentLeafName.Length() - 1));
+  aBaseName = Substring(parentLeafName,
+                        4,
+                        parentLeafName.Length() - 1);
+  return true;
+}
+
+static bool
+GetPluginFile(const std::string& aPluginPath,
+#if defined(XP_MACOSX)
+              nsCOMPtr<nsIFile>& aLibDirectory,
+#endif
+              nsCOMPtr<nsIFile>& aLibFile)
+{
+  nsAutoString baseName;
+#ifdef XP_MACOSX
+  GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
+#else
+  GetFileBase(aPluginPath, aLibFile, baseName);
+#endif
 
 #if defined(XP_MACOSX)
   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".dylib");
 #elif defined(OS_POSIX)
   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".so");
 #elif defined(XP_WIN)
   nsAutoString binaryName =                            baseName + NS_LITERAL_STRING(".dll");
 #else
 #error not defined
 #endif
   aLibFile->AppendRelativePath(binaryName);
   return true;
 }
 
+#ifdef XP_WIN
+static bool
+GetInfoFile(const std::string& aPluginPath,
+            nsCOMPtr<nsIFile>& aInfoFile)
+{
+  nsAutoString baseName;
+  GetFileBase(aPluginPath, aInfoFile, baseName);
+  nsAutoString infoFileName = baseName + NS_LITERAL_STRING(".info");
+  aInfoFile->AppendRelativePath(infoFileName);
+  return true;
+}
+#endif
+
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
 static bool
 GetPluginPaths(const std::string& aPluginPath,
                nsCString &aPluginDirectoryPath,
                nsCString &aPluginFilePath)
 {
   nsCOMPtr<nsIFile> libDirectory, libFile;
   if (!GetPluginFile(aPluginPath, libDirectory, libFile)) {
@@ -232,23 +268,87 @@ GMPChild::Init(const std::string& aPlugi
   SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   mPluginPath = aPluginPath;
   return true;
 #endif
 
+#ifdef XP_WIN
+  PreLoadLibraries(aPluginPath);
+#endif
+
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
   mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 
   return LoadPluginLibrary(aPluginPath);
 }
 
+#ifdef XP_WIN
+// Pre-load DLLs that need to be used by the EME plugin but that can't be
+// loaded after the sandbox has started
+bool
+GMPChild::PreLoadLibraries(const std::string& aPluginPath)
+{
+  // This must be in sorted order and lowercase!
+  static const char* whitelist[] =
+    {
+       "d3d9.dll", // Create an `IDirect3D9` to get adapter information
+       "dxva2.dll", // Get monitor information
+       "msauddecmft.dll", // H.264 decoder
+       "msmpeg2adec.dll", // AAC decoder (on Windows 7)
+       "msmpeg2vdec.dll", // AAC decoder (on Windows 8)
+    };
+  static const int whitelistLen = sizeof(whitelist) / sizeof(whitelist[0]);
+
+  nsCOMPtr<nsIFile> infoFile;
+  GetInfoFile(aPluginPath, infoFile);
+
+  nsString path;
+  infoFile->GetPath(path);
+
+  std::ifstream stream;
+  stream.open(path.get());
+  if (!stream.good()) {
+    NS_WARNING("Failure opening info file for required DLLs");
+    return false;
+  }
+
+  do {
+    std::string line;
+    getline(stream, line);
+    if (stream.fail()) {
+      NS_WARNING("Failure reading info file for required DLLs");
+      return false;
+    }
+    std::transform(line.begin(), line.end(), line.begin(), tolower);
+    static const char* prefix = "libraries:";
+    static const int prefixLen = strlen(prefix);
+    if (0 == line.compare(0, prefixLen, prefix)) {
+      char* lineCopy = strdup(line.c_str() + prefixLen);
+      char* start = lineCopy;
+      while (char* tok = nsCRT::strtok(start, ", ", &start)) {
+        for (int i = 0; i < whitelistLen; i++) {
+          if (0 == strcmp(whitelist[i], tok)) {
+            LoadLibraryA(tok);
+            break;
+          }
+        }
+      }
+      free(lineCopy);
+      break;
+    }
+  } while (!stream.eof());
+
+  return true;
+}
+#endif
+
 bool
 GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
 {
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   nsAutoCString nativePath;
   nativePath.Assign(mPluginBinaryPath);
 
   mLib = PR_LoadLibrary(nativePath.get());
--- a/content/media/gmp/GMPChild.h
+++ b/content/media/gmp/GMPChild.h
@@ -29,16 +29,19 @@ public:
   void OnChannelConnected(int32_t aPid);
 #endif
 
   bool Init(const std::string& aPluginPath,
             base::ProcessHandle aParentProcessHandle,
             MessageLoop* aIOLoop,
             IPC::Channel* aChannel);
   bool LoadPluginLibrary(const std::string& aPluginPath);
+#ifdef XP_WIN
+  bool PreLoadLibraries(const std::string& aPluginPath);
+#endif
   MessageLoop* GMPMessageLoop();
 
   // Main thread only.
   GMPTimerChild* GetGMPTimers();
   GMPStorageChild* GetGMPStorage();
 
   // GMPSharedMem
   virtual void CheckThread() MOZ_OVERRIDE;