GMPLoader.cpp (5924B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=4 et : 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "GMPLoader.h" 8 9 #include "gmp-entrypoints.h" 10 #include "nsExceptionHandler.h" 11 #include "prenv.h" 12 #include "prerror.h" 13 #include "prlink.h" 14 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 15 # include "mozilla/sandboxTarget.h" 16 # include "mozilla/sandboxing/SandboxInitialization.h" 17 # include "mozilla/sandboxing/sandboxLogging.h" 18 #endif 19 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 20 # include "mozilla/Sandbox.h" 21 # include "mozilla/SandboxInfo.h" 22 # include "mozilla/SandboxProfilerObserver.h" 23 #endif 24 25 #ifdef XP_WIN 26 # include <windows.h> 27 #endif 28 29 namespace mozilla::gmp { 30 class PassThroughGMPAdapter : public GMPAdapter { 31 public: 32 ~PassThroughGMPAdapter() override { 33 // Ensure we're always shutdown, even if caller forgets to call 34 // GMPShutdown(). 35 GMPShutdown(); 36 } 37 38 void SetAdaptee(PRLibrary* aLib) override { mLib = aLib; } 39 40 GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override { 41 if (NS_WARN_IF(!mLib)) { 42 MOZ_CRASH("Missing library!"); 43 return GMPGenericErr; 44 } 45 GMPInitFunc initFunc = 46 reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit")); 47 if (!initFunc) { 48 MOZ_CRASH("Missing init method!"); 49 return GMPNotImplementedErr; 50 } 51 return initFunc(aPlatformAPI); 52 } 53 54 GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI, 55 const nsACString& /* aKeySystem */) override { 56 if (!mLib) { 57 return GMPGenericErr; 58 } 59 GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>( 60 PR_FindFunctionSymbol(mLib, "GMPGetAPI")); 61 if (!getapiFunc) { 62 return GMPNotImplementedErr; 63 } 64 return getapiFunc(aAPIName, aHostAPI, aPluginAPI); 65 } 66 67 void GMPShutdown() override { 68 if (mLib) { 69 GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>( 70 PR_FindFunctionSymbol(mLib, "GMPShutdown")); 71 if (shutdownFunc) { 72 shutdownFunc(); 73 } 74 PR_UnloadLibrary(mLib); 75 mLib = nullptr; 76 } 77 } 78 79 private: 80 PRLibrary* mLib = nullptr; 81 }; 82 83 bool GMPLoader::Load(const char* aUTF8LibPath, uint32_t aUTF8LibPathLen, 84 const GMPPlatformAPI* aPlatformAPI, GMPAdapter* aAdapter) { 85 CrashReporter::AutoRecordAnnotation autoLibPath( 86 CrashReporter::Annotation::GMPLibraryPath, 87 nsDependentCString(aUTF8LibPath)); 88 89 if (!getenv("MOZ_DISABLE_GMP_SANDBOX") && mSandboxStarter && 90 !mSandboxStarter->Start(aUTF8LibPath)) { 91 MOZ_CRASH("Cannot start sandbox!"); 92 return false; 93 } 94 95 // Load the GMP. 96 PRLibSpec libSpec; 97 #ifdef XP_WIN 98 int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0); 99 if (pathLen == 0) { 100 MOZ_CRASH("Cannot get path length as wide char!"); 101 return false; 102 } 103 104 auto widePath = MakeUnique<wchar_t[]>(pathLen); 105 if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath.get(), 106 pathLen) == 0) { 107 MOZ_CRASH("Cannot convert path to wide char!"); 108 return false; 109 } 110 111 libSpec.value.pathname_u = widePath.get(); 112 libSpec.type = PR_LibSpec_PathnameU; 113 #else 114 libSpec.value.pathname = aUTF8LibPath; 115 libSpec.type = PR_LibSpec_Pathname; 116 #endif 117 PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0); 118 if (!lib) { 119 MOZ_CRASH_UNSAFE_PRINTF("Cannot load plugin as library %d %d", 120 PR_GetError(), PR_GetOSError()); 121 return false; 122 } 123 124 mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter); 125 mAdapter->SetAdaptee(lib); 126 127 if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) { 128 MOZ_CRASH("Cannot initialize plugin adapter!"); 129 return false; 130 } 131 132 return true; 133 } 134 135 GMPErr GMPLoader::GetAPI(const char* aAPIName, void* aHostAPI, 136 void** aPluginAPI, const nsACString& aKeySystem) { 137 return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aKeySystem); 138 } 139 140 void GMPLoader::Shutdown() { 141 if (mAdapter) { 142 mAdapter->GMPShutdown(); 143 } 144 } 145 146 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 147 class WinSandboxStarter : public mozilla::gmp::SandboxStarter { 148 public: 149 bool Start(const char* aLibPath) override { 150 // Cause advapi32 to load before the sandbox is turned on, as 151 // Widevine version 970 and later require it and the sandbox 152 // blocks it on Win7. 153 unsigned int dummy_rand; 154 rand_s(&dummy_rand); 155 156 mozilla::SandboxTarget::Instance()->StartSandbox(); 157 return true; 158 } 159 }; 160 #endif 161 162 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 163 namespace { 164 class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter { 165 private: 166 LinuxSandboxStarter() = default; 167 friend std::unique_ptr<LinuxSandboxStarter> 168 std::make_unique<LinuxSandboxStarter>(); 169 170 public: 171 static UniquePtr<SandboxStarter> Make() { 172 if (mozilla::SandboxInfo::Get().CanSandboxMedia()) { 173 return MakeUnique<LinuxSandboxStarter>(); 174 } 175 // Sandboxing isn't possible, but the parent has already 176 // checked that this plugin doesn't require it. (Bug 1074561) 177 return nullptr; 178 } 179 bool Start(const char* aLibPath) override { 180 RegisterProfilerObserversForSandboxProfiler(); 181 mozilla::SetMediaPluginSandbox(aLibPath); 182 return true; 183 } 184 }; 185 } // anonymous namespace 186 #endif // XP_LINUX && MOZ_SANDBOX 187 188 static UniquePtr<SandboxStarter> MakeSandboxStarter() { 189 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 190 return mozilla::MakeUnique<WinSandboxStarter>(); 191 #elif defined(XP_LINUX) && defined(MOZ_SANDBOX) 192 return LinuxSandboxStarter::Make(); 193 #else 194 return nullptr; 195 #endif 196 } 197 198 GMPLoader::GMPLoader() : mSandboxStarter(MakeSandboxStarter()) {} 199 200 bool GMPLoader::CanSandbox() const { return !!mSandboxStarter; } 201 202 } // namespace mozilla::gmp