tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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