Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gmp/GMPLoader.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: sw=4 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
#include <stdio.h>
9
#include "mozilla/Attributes.h"
10
#include "gmp-entrypoints.h"
11
#include "prlink.h"
12
#include "prenv.h"
13
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
14
#include "mozilla/sandboxTarget.h"
15
#include "mozilla/sandboxing/SandboxInitialization.h"
16
#include "mozilla/sandboxing/sandboxLogging.h"
17
#endif
18
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
19
#include "mozilla/Sandbox.h"
20
#include "mozilla/SandboxInfo.h"
21
#endif
22
23
#include <string>
24
25
#ifdef XP_WIN
26
#include "windows.h"
27
#endif
28
29
namespace mozilla {
30
namespace gmp {
31
class PassThroughGMPAdapter : public GMPAdapter {
32
public:
33
0
  ~PassThroughGMPAdapter() override {
34
0
    // Ensure we're always shutdown, even if caller forgets to call GMPShutdown().
35
0
    GMPShutdown();
36
0
  }
37
38
  void SetAdaptee(PRLibrary* aLib) override
39
0
  {
40
0
    mLib = aLib;
41
0
  }
42
43
  GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override
44
0
  {
45
0
    if (!mLib) {
46
0
      return GMPGenericErr;
47
0
    }
48
0
    GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
49
0
    if (!initFunc) {
50
0
      return GMPNotImplementedErr;
51
0
    }
52
0
    return initFunc(aPlatformAPI);
53
0
  }
54
55
  GMPErr GMPGetAPI(const char* aAPIName,
56
                   void* aHostAPI,
57
                   void** aPluginAPI,
58
                   uint32_t aDecryptorId) override
59
0
  {
60
0
    if (!mLib) {
61
0
      return GMPGenericErr;
62
0
    }
63
0
    GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
64
0
    if (!getapiFunc) {
65
0
      return GMPNotImplementedErr;
66
0
    }
67
0
    return getapiFunc(aAPIName, aHostAPI, aPluginAPI);
68
0
  }
69
70
  void GMPShutdown() override
71
0
  {
72
0
    if (mLib) {
73
0
      GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
74
0
      if (shutdownFunc) {
75
0
        shutdownFunc();
76
0
      }
77
0
      PR_UnloadLibrary(mLib);
78
0
      mLib = nullptr;
79
0
    }
80
0
  }
81
82
private:
83
  PRLibrary* mLib = nullptr;
84
};
85
86
bool
87
GMPLoader::Load(const char* aUTF8LibPath,
88
                uint32_t aUTF8LibPathLen,
89
                const GMPPlatformAPI* aPlatformAPI,
90
                GMPAdapter* aAdapter)
91
0
{
92
0
  if (!getenv("MOZ_DISABLE_GMP_SANDBOX") && mSandboxStarter &&
93
0
      !mSandboxStarter->Start(aUTF8LibPath)) {
94
0
    return false;
95
0
  }
96
0
97
0
  // Load the GMP.
98
0
  PRLibSpec libSpec;
99
#ifdef XP_WIN
100
  int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
101
  if (pathLen == 0) {
102
    return false;
103
  }
104
105
  auto widePath = MakeUnique<wchar_t[]>(pathLen);
106
  if (MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, widePath.get(), pathLen) == 0) {
107
    return false;
108
  }
109
110
  libSpec.value.pathname_u = widePath.get();
111
  libSpec.type = PR_LibSpec_PathnameU;
112
#else
113
  libSpec.value.pathname = aUTF8LibPath;
114
0
  libSpec.type = PR_LibSpec_Pathname;
115
0
#endif
116
0
  PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0);
117
0
  if (!lib) {
118
0
    return false;
119
0
  }
120
0
121
0
  mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter);
122
0
  mAdapter->SetAdaptee(lib);
123
0
124
0
  if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) {
125
0
    return false;
126
0
  }
127
0
128
0
  return true;
129
0
}
130
131
GMPErr
132
GMPLoader::GetAPI(const char* aAPIName,
133
                  void* aHostAPI,
134
                  void** aPluginAPI,
135
                  uint32_t aDecryptorId)
136
0
{
137
0
  return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
138
0
}
139
140
void
141
GMPLoader::Shutdown()
142
0
{
143
0
  if (mAdapter) {
144
0
    mAdapter->GMPShutdown();
145
0
  }
146
0
}
147
148
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
149
void
150
GMPLoader::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
151
{
152
  if (mSandboxStarter) {
153
    mSandboxStarter->SetSandboxInfo(aSandboxInfo);
154
  }
155
}
156
#endif
157
158
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
159
class WinSandboxStarter : public mozilla::gmp::SandboxStarter
160
{
161
public:
162
  bool Start(const char *aLibPath) override
163
  {
164
    // Cause advapi32 to load before the sandbox is turned on, as
165
    // Widevine version 970 and later require it and the sandbox
166
    // blocks it on Win7.
167
    unsigned int dummy_rand;
168
    rand_s(&dummy_rand);
169
170
    mozilla::SandboxTarget::Instance()->StartSandbox();
171
    return true;
172
  }
173
};
174
#endif
175
176
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
177
class MacSandboxStarter : public mozilla::gmp::SandboxStarter
178
{
179
public:
180
  bool Start(const char *aLibPath) override
181
  {
182
    std::string err;
183
    bool rv = mozilla::StartMacSandbox(mInfo, err);
184
    if (!rv) {
185
      fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
186
    }
187
    return rv;
188
  }
189
  void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override
190
  {
191
    mInfo = *aSandboxInfo;
192
  }
193
private:
194
  MacSandboxInfo mInfo;
195
};
196
#endif
197
198
#if defined (XP_LINUX) && defined(MOZ_GMP_SANDBOX)
199
namespace {
200
class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter
201
{
202
private:
203
0
  LinuxSandboxStarter() { }
204
  friend mozilla::detail::UniqueSelector<LinuxSandboxStarter>::SingleObject mozilla::MakeUnique<LinuxSandboxStarter>();
205
206
public:
207
  static UniquePtr<SandboxStarter> Make()
208
0
  {
209
0
    if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
210
0
      return MakeUnique<LinuxSandboxStarter>();
211
0
    }
212
0
    // Sandboxing isn't possible, but the parent has already
213
0
    // checked that this plugin doesn't require it.  (Bug 1074561)
214
0
    return nullptr;
215
0
  }
216
  bool Start(const char *aLibPath) override
217
0
  {
218
0
    mozilla::SetMediaPluginSandbox(aLibPath);
219
0
    return true;
220
0
  }
221
};
222
} // anonymous namespace
223
#endif // XP_LINUX && MOZ_GMP_SANDBOX
224
225
static UniquePtr<SandboxStarter>
226
MakeSandboxStarter()
227
0
{
228
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
229
  return mozilla::MakeUnique<WinSandboxStarter>();
230
#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
231
  return mozilla::MakeUnique<MacSandboxStarter>();
232
#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
233
  return LinuxSandboxStarter::Make();
234
#else
235
  return nullptr;
236
#endif
237
}
238
239
GMPLoader::GMPLoader()
240
  : mSandboxStarter(MakeSandboxStarter())
241
0
{
242
0
}
243
244
bool
245
GMPLoader::CanSandbox() const
246
0
{
247
0
  return !!mSandboxStarter;
248
0
}
249
250
} // namespace gmp
251
} // namespace mozilla