summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/media/gmp/GMPLoader.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPLoader.cpp b/dom/media/gmp/GMPLoader.cpp
new file mode 100644
index 0000000000..9fa7756165
--- /dev/null
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=4 et :
+ * 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 "GMPLoader.h"
+#include <stdio.h>
+#include "mozilla/Attributes.h"
+#include "nsExceptionHandler.h"
+#include "gmp-entrypoints.h"
+#include "prlink.h"
+#include "prenv.h"
+#include "prerror.h"
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+# include "mozilla/sandboxTarget.h"
+# include "mozilla/sandboxing/SandboxInitialization.h"
+# include "mozilla/sandboxing/sandboxLogging.h"
+#endif
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+# include "mozilla/Sandbox.h"
+# include "mozilla/SandboxInfo.h"
+#endif
+
+#include <string>
+
+#ifdef XP_WIN
+# include <windows.h>
+#endif
+
+namespace mozilla::gmp {
+class PassThroughGMPAdapter : public GMPAdapter {
+ public:
+ ~PassThroughGMPAdapter() override {
+ // Ensure we're always shutdown, even if caller forgets to call
+ // GMPShutdown().
+ GMPShutdown();
+ }
+
+ void SetAdaptee(PRLibrary* aLib) override { mLib = aLib; }
+
+ GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override {
+ if (NS_WARN_IF(!mLib)) {
+ MOZ_CRASH("Missing library!");
+ return GMPGenericErr;
+ }
+ GMPInitFunc initFunc =
+ reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
+ if (!initFunc) {
+ MOZ_CRASH("Missing init method!");
+ return GMPNotImplementedErr;
+ }
+ return initFunc(aPlatformAPI);
+ }
+
+ GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI,
+ const nsACString& /* aKeySystem */) override {
+ if (!mLib) {
+ return GMPGenericErr;
+ }
+ GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>(
+ PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
+ if (!getapiFunc) {
+ return GMPNotImplementedErr;
+ }
+ return getapiFunc(aAPIName, aHostAPI, aPluginAPI);
+ }
+
+ void GMPShutdown() override {
+ if (mLib) {
+ GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(
+ PR_FindFunctionSymbol(mLib, "GMPShutdown"));
+ if (shutdownFunc) {
+ shutdownFunc();
+ }
+ PR_UnloadLibrary(mLib);
+ mLib = nullptr;
+ }
+ }
+
+ private:
+ PRLibrary* mLib = nullptr;
+};
+
+bool GMPLoader::Load(const char* aUTF8LibPath, uint32_t aUTF8LibPathLen,
+ const GMPPlatformAPI* aPlatformAPI, GMPAdapter* aAdapter) {
+ CrashReporter::AutoAnnotateCrashReport autoLibPath(
+ CrashReporter::Annotation::GMPLibraryPath,
+ nsDependentCString(aUTF8LibPath));
+
+ if (!getenv("MOZ_DISABLE_GMP_SANDBOX") && mSandboxStarter &&
+ !mSandboxStarter->Start(aUTF8LibPath)) {
+ MOZ_CRASH("Cannot start sandbox!");
+ return false;
+ }
+
+ // Load the GMP.
+ PRLibSpec libSpec;
+#ifdef XP_WIN
+ int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
+ if (pathLen == 0) {
+ MOZ_CRASH("Cannot get path length as wide char!");
+ return false;
+ }
+
+ auto widePath = MakeUnique<wchar_t[]>(pathLen);
+ if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath.get(),
+ pathLen) == 0) {
+ MOZ_CRASH("Cannot convert path to wide char!");
+ return false;
+ }
+
+ libSpec.value.pathname_u = widePath.get();
+ libSpec.type = PR_LibSpec_PathnameU;
+#else
+ libSpec.value.pathname = aUTF8LibPath;
+ libSpec.type = PR_LibSpec_Pathname;
+#endif
+ PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0);
+ if (!lib) {
+ MOZ_CRASH_UNSAFE_PRINTF("Cannot load plugin as library %d %d",
+ PR_GetError(), PR_GetOSError());
+ return false;
+ }
+
+ mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter);
+ mAdapter->SetAdaptee(lib);
+
+ if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) {
+ MOZ_CRASH("Cannot initialize plugin adapter!");
+ return false;
+ }
+
+ return true;
+}
+
+GMPErr GMPLoader::GetAPI(const char* aAPIName, void* aHostAPI,
+ void** aPluginAPI, const nsACString& aKeySystem) {
+ return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem);
+}
+
+void GMPLoader::Shutdown() {
+ if (mAdapter) {
+ mAdapter->GMPShutdown();
+ }
+}
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
+ public:
+ bool Start(const char* aLibPath) override {
+ // Cause advapi32 to load before the sandbox is turned on, as
+ // Widevine version 970 and later require it and the sandbox
+ // blocks it on Win7.
+ unsigned int dummy_rand;
+ rand_s(&dummy_rand);
+
+ mozilla::SandboxTarget::Instance()->StartSandbox();
+ return true;
+ }
+};
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+namespace {
+class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter {
+ private:
+ LinuxSandboxStarter() = default;
+ friend mozilla::detail::UniqueSelector<LinuxSandboxStarter>::SingleObject
+ mozilla::MakeUnique<LinuxSandboxStarter>();
+
+ public:
+ static UniquePtr<SandboxStarter> Make() {
+ if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
+ return MakeUnique<LinuxSandboxStarter>();
+ }
+ // Sandboxing isn't possible, but the parent has already
+ // checked that this plugin doesn't require it. (Bug 1074561)
+ return nullptr;
+ }
+ bool Start(const char* aLibPath) override {
+ mozilla::SetMediaPluginSandbox(aLibPath);
+ return true;
+ }
+};
+} // anonymous namespace
+#endif // XP_LINUX && MOZ_SANDBOX
+
+static UniquePtr<SandboxStarter> MakeSandboxStarter() {
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+ return mozilla::MakeUnique<WinSandboxStarter>();
+#elif defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ return LinuxSandboxStarter::Make();
+#else
+ return nullptr;
+#endif
+}
+
+GMPLoader::GMPLoader() : mSandboxStarter(MakeSandboxStarter()) {}
+
+bool GMPLoader::CanSandbox() const { return !!mSandboxStarter; }
+
+} // namespace mozilla::gmp