зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1382883 - Pass paths and open file handles to CDM host binaries on CDM startup. r=gerald
MozReview-Commit-ID: 9IhRqlFrNJf --HG-- extra : source : de04ea0a90ae935bbc1d0f730332b034b5514f17 extra : intermediate-source : b18daff94ad3d832fcbd601d219c6db2eae46f90
This commit is contained in:
Родитель
93ac0cd0e3
Коммит
0637427899
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ChromiumCDMAdapter.h"
|
||||
#include "content_decryption_module.h"
|
||||
#include "content_decryption_module_ext.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "gmp-api/gmp-entrypoints.h"
|
||||
#include "gmp-api/gmp-decryption.h"
|
||||
|
@ -12,12 +13,25 @@
|
|||
#include "gmp-api/gmp-platform.h"
|
||||
#include "WidevineUtils.h"
|
||||
#include "GMPLog.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#if defined(XP_MACOSX) || defined(XP_LINUX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
// Declared in WidevineAdapter.cpp.
|
||||
extern const GMPPlatformAPI* sPlatform;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
ChromiumCDMAdapter::ChromiumCDMAdapter(nsTArray<nsCString>&& aHostFilePaths)
|
||||
{
|
||||
PopulateHostFiles(Move(aHostFilePaths));
|
||||
}
|
||||
|
||||
void
|
||||
ChromiumCDMAdapter::SetAdaptee(PRLibrary* aLib)
|
||||
{
|
||||
|
@ -37,6 +51,14 @@ ChromiumCdmHost(int aHostInterfaceVersion, void* aUserData)
|
|||
#define STRINGIFY(s) _STRINGIFY(s)
|
||||
#define _STRINGIFY(s) #s
|
||||
|
||||
static cdm::HostFile
|
||||
TakeToCDMHostFile(HostFileData& aHostFileData)
|
||||
{
|
||||
return cdm::HostFile(aHostFileData.mBinary.Path().get(),
|
||||
aHostFileData.mBinary.TakePlatformFile(),
|
||||
aHostFileData.mSig.TakePlatformFile());
|
||||
}
|
||||
|
||||
GMPErr
|
||||
ChromiumCDMAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
|
||||
{
|
||||
|
@ -46,6 +68,19 @@ ChromiumCDMAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
|
|||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Note: we must call the VerifyCdmHost_0 function if it's present before
|
||||
// we call the initialize function.
|
||||
auto verify = reinterpret_cast<decltype(::VerifyCdmHost_0)*>(
|
||||
PR_FindFunctionSymbol(mLib, STRINGIFY(VerifyCdmHost_0)));
|
||||
if (verify) {
|
||||
nsTArray<cdm::HostFile> files;
|
||||
for (HostFileData& hostFile : mHostFiles) {
|
||||
files.AppendElement(TakeToCDMHostFile(hostFile));
|
||||
}
|
||||
bool result = verify(files.Elements(), files.Length());
|
||||
GMP_LOG("%s VerifyCdmHost_0 returned %d", __func__, result);
|
||||
}
|
||||
|
||||
auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>(
|
||||
PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE)));
|
||||
if (!init) {
|
||||
|
@ -130,4 +165,64 @@ ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
|
|||
aHostVersion == cdm::Host_8::kVersion;
|
||||
}
|
||||
|
||||
HostFile::HostFile(HostFile&& aOther)
|
||||
: mPath(aOther.mPath)
|
||||
, mFile(aOther.TakePlatformFile())
|
||||
{
|
||||
}
|
||||
|
||||
HostFile::~HostFile()
|
||||
{
|
||||
if (mFile != cdm::kInvalidPlatformFile) {
|
||||
#ifdef XP_WIN
|
||||
CloseHandle(mFile);
|
||||
#else
|
||||
close(mFile);
|
||||
#endif
|
||||
mFile = cdm::kInvalidPlatformFile;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
HostFile::HostFile(const nsCString& aPath)
|
||||
: mPath(NS_ConvertUTF8toUTF16(aPath))
|
||||
{
|
||||
HANDLE handle = CreateFileW(mPath.get(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
mFile = (handle == INVALID_HANDLE_VALUE) ? cdm::kInvalidPlatformFile : handle;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) || defined(XP_LINUX)
|
||||
HostFile::HostFile(const nsCString& aPath)
|
||||
: mPath(aPath)
|
||||
{
|
||||
// Note: open() returns -1 on failure; i.e. kInvalidPlatformFile.
|
||||
mFile = open(aPath.get(), O_RDONLY);
|
||||
}
|
||||
#endif
|
||||
|
||||
cdm::PlatformFile
|
||||
HostFile::TakePlatformFile()
|
||||
{
|
||||
cdm::PlatformFile f = mFile;
|
||||
mFile = cdm::kInvalidPlatformFile;
|
||||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
ChromiumCDMAdapter::PopulateHostFiles(nsTArray<nsCString>&& aHostFilePaths)
|
||||
{
|
||||
for (const nsCString& path : aHostFilePaths) {
|
||||
mHostFiles.AppendElement(
|
||||
HostFileData(mozilla::HostFile(path),
|
||||
mozilla::HostFile(path + NS_LITERAL_CSTRING(".sig"))));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -9,14 +9,59 @@
|
|||
#include "GMPLoader.h"
|
||||
#include "prlink.h"
|
||||
#include "GMPUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "content_decryption_module_ext.h"
|
||||
#include "nsString.h"
|
||||
|
||||
struct GMPPlatformAPI;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef nsString HostFileString;
|
||||
#else
|
||||
typedef nsCString HostFileString;
|
||||
#endif
|
||||
|
||||
class HostFile
|
||||
{
|
||||
public:
|
||||
explicit HostFile(const nsCString& aPath);
|
||||
HostFile(HostFile&& aOther);
|
||||
~HostFile();
|
||||
|
||||
const HostFileString& Path() const { return mPath; }
|
||||
cdm::PlatformFile TakePlatformFile();
|
||||
|
||||
private:
|
||||
const HostFileString mPath;
|
||||
cdm::PlatformFile mFile = cdm::kInvalidPlatformFile;
|
||||
};
|
||||
|
||||
struct HostFileData
|
||||
{
|
||||
HostFileData(HostFile&& aBinary, HostFile&& aSig)
|
||||
: mBinary(Move(aBinary))
|
||||
, mSig(Move(aSig))
|
||||
{
|
||||
}
|
||||
|
||||
HostFileData(HostFileData&& aOther)
|
||||
: mBinary(Move(aOther.mBinary))
|
||||
, mSig(Move(aOther.mSig))
|
||||
{
|
||||
}
|
||||
|
||||
~HostFileData() {}
|
||||
|
||||
HostFile mBinary;
|
||||
HostFile mSig;
|
||||
};
|
||||
|
||||
class ChromiumCDMAdapter : public gmp::GMPAdapter
|
||||
{
|
||||
public:
|
||||
explicit ChromiumCDMAdapter(nsTArray<nsCString>&& aHostFilePaths);
|
||||
|
||||
void SetAdaptee(PRLibrary* aLib) override;
|
||||
|
||||
|
@ -33,7 +78,10 @@ public:
|
|||
int32_t aHostVersion);
|
||||
|
||||
private:
|
||||
void PopulateHostFiles(nsTArray<nsCString>&& aHostFilePaths);
|
||||
|
||||
PRLibrary* mLib = nullptr;
|
||||
nsTArray<HostFileData> mHostFiles;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -22,13 +22,16 @@
|
|||
#include "GMPUtils.h"
|
||||
#include "prio.h"
|
||||
#include "base/task.h"
|
||||
#include "base/command_line.h"
|
||||
#include "widevine-adapter/WidevineAdapter.h"
|
||||
#include "ChromiumCDMAdapter.h"
|
||||
#include "GMPLog.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <stdlib.h> // for _exit()
|
||||
#include "WinUtils.h"
|
||||
#else
|
||||
#include <unistd.h> // for _exit()
|
||||
#endif
|
||||
|
@ -118,7 +121,6 @@ GetPluginFile(const nsAString& aPluginPath,
|
|||
return true;
|
||||
}
|
||||
|
||||
#if !defined(XP_MACOSX) || !defined(MOZ_GMP_SANDBOX)
|
||||
static bool
|
||||
GetPluginFile(const nsAString& aPluginPath,
|
||||
nsCOMPtr<nsIFile>& aLibFile)
|
||||
|
@ -126,7 +128,6 @@ GetPluginFile(const nsAString& aPluginPath,
|
|||
nsCOMPtr<nsIFile> unusedlibDir;
|
||||
return GetPluginFile(aPluginPath, unusedlibDir, aLibFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
static nsCString
|
||||
|
@ -296,6 +297,25 @@ GMPChild::RecvPreloadLibs(const nsCString& aLibs)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::ResolveLinks(nsCOMPtr<nsIFile>& aPath)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
return widget::WinUtils::ResolveJunctionPointsAndSymLinks(aPath);
|
||||
#elif defined(XP_MACOSX)
|
||||
nsCString targetPath = GetNativeTarget(aPath);
|
||||
nsCOMPtr<nsIFile> newFile;
|
||||
if (NS_FAILED(
|
||||
NS_NewNativeLocalFile(targetPath, true, getter_AddRefs(newFile)))) {
|
||||
return false;
|
||||
}
|
||||
aPath = newFile;
|
||||
return true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::GetUTF8LibPath(nsACString& aOutLibPath)
|
||||
{
|
||||
|
@ -325,6 +345,117 @@ GMPChild::GetUTF8LibPath(nsACString& aOutLibPath)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#define FIREFOX_FILE NS_LITERAL_STRING("firefox")
|
||||
#define XUL_LIB_FILE NS_LITERAL_STRING("XUL")
|
||||
#elif defined(XP_LINUX)
|
||||
#define FIREFOX_FILE NS_LITERAL_STRING("firefox")
|
||||
#define XUL_LIB_FILE NS_LITERAL_STRING("libxul.so")
|
||||
#elif defined(OS_WIN)
|
||||
#define FIREFOX_FILE NS_LITERAL_STRING("firefox.exe")
|
||||
#define XUL_LIB_FILE NS_LITERAL_STRING("xul.dll")
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
static bool
|
||||
GetFirefoxAppPath(nsCOMPtr<nsIFile> aPluginContainerPath,
|
||||
nsCOMPtr<nsIFile>& aOutFirefoxAppPath)
|
||||
{
|
||||
// aPluginContainerPath will end with something like:
|
||||
// xxxx/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container
|
||||
MOZ_ASSERT(aPluginContainerPath);
|
||||
nsCOMPtr<nsIFile> path = aPluginContainerPath;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
if (NS_FAILED(path->GetParent(getter_AddRefs(parent)))) {
|
||||
return false;
|
||||
}
|
||||
path = parent;
|
||||
}
|
||||
MOZ_ASSERT(path);
|
||||
aOutFirefoxAppPath = path;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsTArray<nsCString>
|
||||
GMPChild::MakeCDMHostVerificationPaths()
|
||||
{
|
||||
nsTArray<nsCString> paths;
|
||||
|
||||
// Plugin binary path.
|
||||
nsCOMPtr<nsIFile> path;
|
||||
nsString str;
|
||||
if (GetPluginFile(mPluginPath, path) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
paths.AppendElement(NS_ConvertUTF16toUTF8(str));
|
||||
}
|
||||
|
||||
// Plugin-container binary path.
|
||||
// Note: clang won't let us initialize an nsString from a wstring, so we
|
||||
// need to go through UTF8 to get to an nsString.
|
||||
const std::string pluginContainer =
|
||||
WideToUTF8(CommandLine::ForCurrentProcess()->program());
|
||||
path = nullptr;
|
||||
str = NS_ConvertUTF8toUTF16(nsDependentCString(pluginContainer.c_str()));
|
||||
if (NS_SUCCEEDED(NS_NewLocalFile(str,
|
||||
true, /* aFollowLinks */
|
||||
getter_AddRefs(path))) &&
|
||||
FileExists(path) && ResolveLinks(path) &&
|
||||
NS_SUCCEEDED(path->GetPath(str))) {
|
||||
paths.AppendElement(nsCString(NS_ConvertUTF16toUTF8(str)));
|
||||
} else {
|
||||
// Without successfully determining plugin-container's path, we can't
|
||||
// determine libxul's or Firefox's. So give up.
|
||||
return paths;
|
||||
}
|
||||
|
||||
// Firefox application binary path.
|
||||
nsCOMPtr<nsIFile> appDir;
|
||||
#if defined(XP_WIN) || defined(XP_LINUX)
|
||||
// Note: re-using 'path' var here, as on Windows/Linux we assume Firefox
|
||||
// executable is in the same directory as plugin-container.
|
||||
if (NS_SUCCEEDED(path->GetParent(getter_AddRefs(appDir))) &&
|
||||
NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
|
||||
NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
paths.AppendElement(NS_ConvertUTF16toUTF8(str));
|
||||
}
|
||||
#elif defined(XP_MACOSX)
|
||||
// On MacOS the firefox binary is a few parent directories up from
|
||||
// plugin-container.
|
||||
if (GetFirefoxAppPath(path, appDir) &&
|
||||
NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
|
||||
NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
paths.AppendElement(NS_ConvertUTF16toUTF8(str));
|
||||
}
|
||||
#endif
|
||||
// Libxul path. Note: re-using 'path' var here, as we assume libxul is in
|
||||
// the same directory as Firefox executable.
|
||||
appDir->GetPath(str);
|
||||
if (NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
|
||||
NS_SUCCEEDED(path->Append(XUL_LIB_FILE)) && FileExists(path) &&
|
||||
ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
|
||||
paths.AppendElement(NS_ConvertUTF16toUTF8(str));
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ToCString(const nsTArray<nsCString>& aStrings)
|
||||
{
|
||||
nsCString result;
|
||||
for (const nsCString& s : aStrings) {
|
||||
if (!result.IsEmpty()) {
|
||||
result.AppendLiteral(",");
|
||||
}
|
||||
result.Append(s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPChild::AnswerStartPlugin(const nsString& aAdapter)
|
||||
{
|
||||
|
@ -365,7 +496,9 @@ GMPChild::AnswerStartPlugin(const nsString& aAdapter)
|
|||
if (isWidevine) {
|
||||
adapter = new WidevineAdapter();
|
||||
} else if (isChromium) {
|
||||
adapter = new ChromiumCDMAdapter();
|
||||
nsTArray<nsCString> paths(MakeCDMHostVerificationPaths());
|
||||
GMP_LOG("%s CDM host paths=%s", __func__, ToCString(paths).get());
|
||||
adapter = new ChromiumCDMAdapter(Move(paths));
|
||||
}
|
||||
|
||||
if (!mGMPLoader->Load(libPath.get(),
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
private:
|
||||
friend class GMPContentChild;
|
||||
|
||||
bool ResolveLinks(nsCOMPtr<nsIFile>& aPath);
|
||||
|
||||
bool GetUTF8LibPath(nsACString& aOutLibPath);
|
||||
|
||||
mozilla::ipc::IPCResult AnswerStartPlugin(const nsString& aAdapter) override;
|
||||
|
@ -64,6 +66,8 @@ private:
|
|||
|
||||
GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI, uint32_t aDecryptorId = 0);
|
||||
|
||||
nsTArray<nsCString> MakeCDMHostVerificationPaths();
|
||||
|
||||
nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
|
||||
|
||||
RefPtr<GMPTimerChild> mTimerChild;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "ClearKeyCDM.h"
|
||||
#include "ClearKeySessionManager.h"
|
||||
|
@ -24,6 +25,13 @@
|
|||
// on Unix systems.
|
||||
#include "stddef.h"
|
||||
#include "content_decryption_module.h"
|
||||
#include "content_decryption_module_ext.h"
|
||||
|
||||
#if defined(XP_MACOSX) || defined(XP_LINUX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_WMF
|
||||
#include "WMFUtils.h"
|
||||
|
@ -36,6 +44,8 @@ void INITIALIZE_CDM_MODULE() {
|
|||
|
||||
}
|
||||
|
||||
static bool sCanReadHostVerificationFiles = false;
|
||||
|
||||
CDM_API
|
||||
void* CreateCdmInstance(int cdm_interface_version,
|
||||
const char* key_system,
|
||||
|
@ -53,6 +63,11 @@ void* CreateCdmInstance(int cdm_interface_version,
|
|||
}
|
||||
#endif
|
||||
|
||||
// Test that we're able to read the host files.
|
||||
if (!sCanReadHostVerificationFiles) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cdm::Host_8* host = static_cast<cdm::Host_8*>(
|
||||
get_cdm_host_func(cdm_interface_version, user_data));
|
||||
ClearKeyCDM* clearKey = new ClearKeyCDM(host);
|
||||
|
@ -61,4 +76,57 @@ void* CreateCdmInstance(int cdm_interface_version,
|
|||
|
||||
return clearKey;
|
||||
}
|
||||
|
||||
const size_t TEST_READ_SIZE = 16 * 1024;
|
||||
|
||||
bool
|
||||
CanReadSome(cdm::PlatformFile aFile)
|
||||
{
|
||||
vector<uint8_t> data;
|
||||
data.resize(TEST_READ_SIZE);
|
||||
#ifdef XP_WIN
|
||||
DWORD bytesRead = 0;
|
||||
return ReadFile(aFile, &data.front(), TEST_READ_SIZE, &bytesRead, nullptr) &&
|
||||
bytesRead > 0;
|
||||
#elif defined(XP_MACOSX) || defined(XP_LINUX)
|
||||
return read(aFile, &data.front(), TEST_READ_SIZE) > 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ClosePlatformFile(cdm::PlatformFile aFile)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
CloseHandle(aFile);
|
||||
#elif defined(XP_MACOSX) || defined(XP_LINUX)
|
||||
close(aFile);
|
||||
#endif
|
||||
}
|
||||
|
||||
CDM_API
|
||||
bool
|
||||
VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles)
|
||||
{
|
||||
// We expect 4 binaries: clearkey, libxul, plugin-container, and Firefox.
|
||||
bool rv = (aNumFiles == 4);
|
||||
// Verify that each binary is readable inside the sandbox,
|
||||
// and close the handle.
|
||||
for (uint32_t i = 0; i < aNumFiles; i++) {
|
||||
const cdm::HostFile& hostFile = aHostFiles[i];
|
||||
if (hostFile.file != cdm::kInvalidPlatformFile) {
|
||||
if (!CanReadSome(hostFile.file)) {
|
||||
rv = false;
|
||||
}
|
||||
ClosePlatformFile(hostFile.file);
|
||||
}
|
||||
if (hostFile.sig_file != cdm::kInvalidPlatformFile) {
|
||||
ClosePlatformFile(hostFile.sig_file);
|
||||
}
|
||||
}
|
||||
sCanReadHostVerificationFiles = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // extern "C".
|
||||
|
|
Загрузка…
Ссылка в новой задаче