Bug 1528661 - Pass paths to i686 xul and plugin-container binaries to CDM in host verification paths. r=bryce
authorChris Pearce <cpearce@mozilla.com>
Fri, 15 Feb 2019 21:27:01 +1300
changeset 519965 b8397ea9e6b82c9c0ba8bcd02b832d8d131b77a1
parent 519796 e097bf9457c31adfe082dd38397f0794a674a746
child 519966 6ca1d074411757bb68d1cebae1f547313e8c62b2
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce
bugs1528661
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1528661 - Pass paths to i686 xul and plugin-container binaries to CDM in host verification paths. r=bryce On Windows on ARM64 we will run the x86 Widevine DLL in an x86 plugin-container.exe with an x86 xul.dll. We therefore should also pass the paths to these binaries to the CDM in the host files instead of the aarch64 plugin-container.exe. We should still pass the aarch64 xul.dll to the CDM, as that's in use by the aarch64 firefox.exe. Differential Revision: https://phabricator.services.mozilla.com/D21507
dom/media/gmp/GMPChild.cpp
media/gmp-clearkey/0.1/gmp-clearkey.cpp
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -326,46 +326,86 @@ bool GMPChild::GetUTF8LibPath(nsACString
   nsAutoString path;
   libFile->GetPath(path);
   aOutLibPath = NS_ConvertUTF16toUTF8(path);
 
   return true;
 #endif
 }
 
+static nsCOMPtr<nsIFile> AppendFile(nsCOMPtr<nsIFile>&& aFile,
+                                    const nsString& aStr) {
+  return (aFile && NS_SUCCEEDED(aFile->Append(aStr))) ? aFile : nullptr;
+}
+
+static nsCOMPtr<nsIFile> CloneFile(const nsCOMPtr<nsIFile>& aFile) {
+  nsCOMPtr<nsIFile> clone;
+  return (aFile && NS_SUCCEEDED(aFile->Clone(getter_AddRefs(clone)))) ? clone
+                                                                      : nullptr;
+}
+
+static nsCOMPtr<nsIFile> GetParentFile(const nsCOMPtr<nsIFile>& aFile) {
+  nsCOMPtr<nsIFile> parent;
+  return (aFile && NS_SUCCEEDED(aFile->GetParent(getter_AddRefs(parent))))
+             ? parent
+             : nullptr;
+}
+
+#if defined(XP_WIN)
+static bool IsFileLeafEqualToASCII(const nsCOMPtr<nsIFile>& aFile,
+                                   const char* aStr) {
+  nsAutoString leafName;
+  return aFile && NS_SUCCEEDED(aFile->GetLeafName(leafName)) &&
+         leafName.EqualsASCII(aStr);
+}
+#endif
+
 #if defined(XP_WIN)
 #  define FIREFOX_FILE NS_LITERAL_STRING("firefox.exe")
 #  define XUL_LIB_FILE NS_LITERAL_STRING("xul.dll")
 #elif defined(XP_MACOSX)
 #  define FIREFOX_FILE NS_LITERAL_STRING("firefox")
 #  define XUL_LIB_FILE NS_LITERAL_STRING("XUL")
 #else
 #  define FIREFOX_FILE NS_LITERAL_STRING("firefox")
 #  define XUL_LIB_FILE NS_LITERAL_STRING("libxul.so")
 #endif
 
+static nsCOMPtr<nsIFile> GetFirefoxAppPath(
+    nsCOMPtr<nsIFile> aPluginContainerPath) {
+  MOZ_ASSERT(aPluginContainerPath);
 #if defined(XP_MACOSX)
-static bool GetFirefoxAppPath(nsCOMPtr<nsIFile> aPluginContainerPath,
-                              nsCOMPtr<nsIFile>& aOutFirefoxAppPath) {
+  // On MacOS the firefox binary is a few parent directories up from
+  // plugin-container.
   // aPluginContainerPath will end with something like:
   // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container
-  MOZ_ASSERT(aPluginContainerPath);
   nsCOMPtr<nsIFile> path = aPluginContainerPath;
   for (int i = 0; i < 4; i++) {
     nsCOMPtr<nsIFile> parent;
     if (NS_WARN_IF(NS_FAILED(path->GetParent(getter_AddRefs(parent))))) {
-      return false;
+      return nullptr;
     }
     path = parent;
   }
   MOZ_ASSERT(path);
-  aOutFirefoxAppPath = path;
-  return true;
+  return aOutFirefoxAppPath
+#else
+  nsCOMPtr<nsIFile> parent = GetParentFile(aPluginContainerPath);
+#  if XP_WIN
+  if (IsFileLeafEqualToASCII(parent, "i686")) {
+    // We must be on Windows on ARM64, where the plugin-container path will
+    // be in the 'i686' subdir. The firefox.exe is in the parent directory.
+    parent = GetParentFile(parent);
+  }
+#  endif
+  return parent;
+#endif
 }
 
+#if defined(XP_MACOSX)
 static bool GetSigPath(const int aRelativeLayers,
                        const nsString& aTargetSigFileName,
                        nsCOMPtr<nsIFile> aExecutablePath,
                        nsCOMPtr<nsIFile>& aOutSigPath) {
   // The sig file will be located in
   // xxxx/NightlyDebug.app/Contents/Resources/XUL.sig
   // xxxx/NightlyDebug.app/Contents/Resources/firefox.sig
   // xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/Resources/plugin-container.sig
@@ -433,57 +473,66 @@ nsTArray<Pair<nsCString, nsCString>> GMP
 #endif
     paths.AppendElement(MakePair(std::move(filePath), std::move(sigFilePath)));
   } else {
     // Without successfully determining plugin-container's path, we can't
     // determine libxul's or Firefox's. So give up.
     return paths;
   }
 
+#if defined(XP_WIN)
+  // On Windows on ARM64, we should also append the x86 plugin-container's
+  // xul.dll.
+  const bool isWindowsOnARM64 =
+      IsFileLeafEqualToASCII(GetParentFile(path), "i686");
+  if (isWindowsOnARM64) {
+    nsCOMPtr<nsIFile> x86XulPath =
+        AppendFile(GetParentFile(path), XUL_LIB_FILE);
+    if (FileExists(x86XulPath) && ResolveLinks(x86XulPath) &&
+        NS_SUCCEEDED(x86XulPath->GetPath(str))) {
+      nsCString filePath = NS_ConvertUTF16toUTF8(str);
+      nsCString sigFilePath = filePath + NS_LITERAL_CSTRING(".sig");
+      paths.AppendElement(
+          MakePair(std::move(filePath), std::move(sigFilePath)));
+    }
+  }
+#endif
+
   // Firefox application binary path.
-  nsCOMPtr<nsIFile> appDir;
+  nsCOMPtr<nsIFile> appDir = GetFirefoxAppPath(path);
+  path = AppendFile(CloneFile(appDir), FIREFOX_FILE);
+  if (FileExists(path) && ResolveLinks(path) &&
+      NS_SUCCEEDED(path->GetPath(str))) {
 #if defined(XP_MACOSX)
-  // On MacOS the firefox binary is a few parent directories up from
-  // plugin-container.
-  if (GetFirefoxAppPath(path, appDir) &&
-      NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
-      NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
-      ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
     nsCString filePath = NS_ConvertUTF16toUTF8(str);
     nsCString sigFilePath;
     nsCOMPtr<nsIFile> sigFile;
     if (GetSigPath(2, NS_LITERAL_STRING("firefox.sig"), path, sigFile) &&
         NS_SUCCEEDED(sigFile->GetPath(str))) {
       sigFilePath = NS_ConvertUTF16toUTF8(str);
     } else {
       // Cannot successfully get the sig file path.
       // Assume it is located at the same place as firefox alternatively.
       sigFilePath =
           nsCString(NS_ConvertUTF16toUTF8(str) + NS_LITERAL_CSTRING(".sig"));
     }
     paths.AppendElement(MakePair(std::move(filePath), std::move(sigFilePath)));
-  }
 #else
-  // Note: re-using 'path' var here, as on Windows/Linux we assume Firefox
-  // executable is in the same directory as plugin-container.
-  if (NS_SUCCEEDED(path->GetParent(getter_AddRefs(appDir))) &&
-      NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
-      NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
-      ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
     paths.AppendElement(MakePair(
         nsCString(NS_ConvertUTF16toUTF8(str)),
         nsCString(NS_ConvertUTF16toUTF8(str) + NS_LITERAL_CSTRING(".sig"))));
+#endif
   }
-#endif
+
   // Libxul path. Note: re-using 'path' var here, as we assume libxul is in
   // the same directory as Firefox executable.
   appDir->GetPath(str);
-  if (NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
-      NS_SUCCEEDED(path->Append(XUL_LIB_FILE)) && FileExists(path) &&
-      ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
+  path = AppendFile(CloneFile(appDir), XUL_LIB_FILE);
+  if (FileExists(path) && ResolveLinks(path) &&
+      NS_SUCCEEDED(path->GetPath(str))) {
     nsCString filePath = NS_ConvertUTF16toUTF8(str);
     nsCString sigFilePath;
 #if defined(XP_MACOSX)
     nsCOMPtr<nsIFile> sigFile;
     if (GetSigPath(2, NS_LITERAL_STRING("XUL.sig"), path, sigFile) &&
         NS_SUCCEEDED(sigFile->GetPath(str))) {
       sigFilePath = NS_ConvertUTF16toUTF8(str);
     } else {
--- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp
+++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp
@@ -13,16 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <vector>
+#include <string>
 
 #include "ClearKeyCDM.h"
 #include "ClearKeySessionManager.h"
 // This include is required in order for content_decryption_module to work
 // on Unix systems.
 #include "stddef.h"
 #include "content_decryption_module.h"
 #include "content_decryption_module_ext.h"
@@ -97,20 +98,50 @@ bool CanReadSome(cdm::PlatformFile aFile
 void ClosePlatformFile(cdm::PlatformFile aFile) {
 #ifdef XP_WIN
   CloseHandle(aFile);
 #else
   close(aFile);
 #endif
 }
 
+static uint32_t NumExpectedHostFiles(const cdm::HostFile* aHostFiles,
+                                     uint32_t aNumFiles) {
+#if !defined(XP_WIN)
+  // We expect 4 binaries: clearkey, libxul, plugin-container, and Firefox.
+  return 4;
+#else
+  // Windows running x64 or x86 natively should also have 4 as above.
+  // For Windows on ARM64, we run an x86 plugin-contianer process under
+  // emulation, and so we expect one additional binary; the x86
+  // xul.dll used by plugin-container.exe.
+  bool i686underAArch64 = false;
+  // Assume that we're running under x86 emulation on an aarch64 host if
+  // one of the paths ends with the x86 plugin-container path we'd expect.
+  const std::wstring plugincontainer = L"i686\\plugin-container.exe";
+  for (uint32_t i = 0; i < aNumFiles; i++) {
+    const cdm::HostFile& hostFile = aHostFiles[i];
+    if (hostFile.file != cdm::kInvalidPlatformFile) {
+      std::wstring path = hostFile.file_path;
+      auto offset = path.find(plugincontainer);
+      if (offset != std::string::npos &&
+          offset == path.size() - plugincontainer.size()) {
+        i686underAArch64 = true;
+        break;
+      }
+    }
+  }
+  return i686underAArch64 ? 5 : 4;
+#endif
+}
+
 CDM_API
 bool VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles) {
-  // We expect 4 binaries: clearkey, libxul, plugin-container, and Firefox.
-  bool rv = (aNumFiles == 4);
+  // Check that we've received the expected number of host files.
+  bool rv = (aNumFiles == NumExpectedHostFiles(aHostFiles, aNumFiles));
   // Verify that each binary is readable inside the sandbox,
   // and close the handle.
   for (uint32_t i = 0; i < aNumFiles; i++) {
     const cdm::HostFile& hostFile = aHostFiles[i];
     if (hostFile.file != cdm::kInvalidPlatformFile) {
       if (!CanReadSome(hostFile.file)) {
         rv = false;
       }