Bug 1373147 - Log and refuse to load GMP DLLs which contain Win32 manifests. ?bobowen draft
authorChris Pearce <cpearce@mozilla.com>
Thu, 15 Jun 2017 17:10:03 +1200
changeset 594551 9310a6431bb7534cbd537f13ffc491932b839be3
parent 592441 68ef406556087434fa12b72ae5ed5c2e1bce2b64
child 633449 302f83f15fef1415b9b63893ab218033822d0742
push id64056
push userbmo:cpearce@mozilla.com
push dateThu, 15 Jun 2017 05:25:36 +0000
bugs1373147
milestone55.0a1
Bug 1373147 - Log and refuse to load GMP DLLs which contain Win32 manifests. ?bobowen The Windows sandbox blocks loading of GMP/CDM DLLs which contain Win32 manifests under certain conditions. So to make detecting this problem easier to detect before we push out GMP/CDM updates, check when loading plugins whether they have manifests, and log and refuse to load them if so. This means we will detect GMP/CDM updates which regress (i.e. include a manifest) during testing the new GMP/CDM update before pushing them out. MozReview-Commit-ID: bfDY0MQ8lO
dom/media/gmp/GMPChild.cpp
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -319,26 +319,75 @@ GMPChild::GetUTF8LibPath(nsACString& aOu
   nsAutoString path;
   libFile->GetPath(path);
   aOutLibPath = NS_ConvertUTF16toUTF8(path);
 
   return true;
 #endif
 }
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+BOOL CALLBACK
+EnumResourceTypesCallback(HMODULE aModule, LPTSTR aResType, LONG_PTR aOutParam)
+{
+  MOZ_ASSERT(aOutParam);
+  bool* hasManifest = reinterpret_cast<bool*>(aOutParam);
+  if (aResType == RT_MANIFEST) {
+    *hasManifest = true;
+    return FALSE; // Stop iteration.
+  }
+  // Continue iterating.
+  return TRUE;
+}
+
+static bool
+HasWin32Manifest(nsString aDLLPath)
+{
+  // Iterate through all resources in the DLL, and see if there's a manifest.
+  HMODULE module =
+    ::LoadLibraryExW(aDLLPath.get(),
+                     NULL,
+                     LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
+  MOZ_ASSERT(module);
+  if (module == NULL) {
+    return false;
+  }
+
+  bool hasManifest = false;
+  EnumResourceTypes(module,
+                    &EnumResourceTypesCallback,
+                    reinterpret_cast<LONG_PTR>(&hasManifest));
+
+  ::FreeLibrary(module);
+  return hasManifest;
+}
+#endif
+
 mozilla::ipc::IPCResult
 GMPChild::AnswerStartPlugin(const nsString& aAdapter)
 {
   LOGD("%s", __FUNCTION__);
 
   nsCString libPath;
   if (!GetUTF8LibPath(libPath)) {
     return IPC_FAIL_NO_REASON(this);
   }
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  {
+    // The Windows sandbox blocks loading of the plugin DLL if it contains
+    // a manifest under some conditions. So explicitly check for this and
+    // fail, so that it's detectable up front when testing new plugin updates.
+    if (HasWin32Manifest(NS_ConvertUTF8toUTF16(libPath))) {
+      LOGD("Can't load %s as it hass a Win32 Manifest.", libPath.get());
+      return IPC_FAIL_NO_REASON(this);
+    }
+  }
+#endif
+
   auto platformAPI = new GMPPlatformAPI();
   InitPlatformAPI(*platformAPI, this);
 
   mGMPLoader = MakeUnique<GMPLoader>();
 #if defined(MOZ_GMP_SANDBOX)
   if (!mGMPLoader->CanSandbox()) {
     LOGD("%s Can't sandbox GMP, failing", __FUNCTION__);
     delete platformAPI;