Bug 1506291 - Add Linux sandboxing for the RDD (media decoder) process. r=gcp,mjf,flod

The seccomp-bpf policy is currently just the "common" policy with no
additions (but with the fixes in bug 1511560 to enable shared memory
creation).  The file broker policy allows shared memory creation and
nothing else.  The namespace setup is the same as for GMP (i.e., as
restrictive as we currently can be).

The sandbox can be turned off for troubleshooting by setting the
environment variable MOZ_DISABLE_RDD_SANDBOX, similarly to the other
process types.

Tested against https://demo.bitmovin.com/public/firefox/av1/ with the
necessary prefs set.

Depends on D20895

Differential Revision: https://phabricator.services.mozilla.com/D14525

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jed Davis 2019-02-27 20:14:54 +00:00
parent 5cc3212784
commit af97210807
18 changed files with 137 additions and 18 deletions

View File

@ -21,7 +21,7 @@ protocol PRDD
parent:
// args TBD, sent by UI process to initiate core settings
async Init();
async Init(MaybeFileDesc sandboxBroker);
async InitProfiler(Endpoint<PProfilerChild> endpoint);

View File

@ -8,6 +8,11 @@
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/ipc/CrashReporterHost.h"
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
# include "mozilla/SandboxBroker.h"
# include "mozilla/SandboxBrokerPolicyFactory.h"
#endif
#ifdef MOZ_GECKO_PROFILER
# include "ProfilerParent.h"
#endif
@ -23,12 +28,31 @@ RDDChild::RDDChild(RDDProcessHost* aHost) : mHost(aHost), mRDDReady(false) {
RDDChild::~RDDChild() { MOZ_COUNT_DTOR(RDDChild); }
void RDDChild::Init() {
SendInit();
bool RDDChild::Init() {
MaybeFileDesc brokerFd = void_t();
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
auto policy = SandboxBrokerPolicyFactory::GetUtilityPolicy(OtherPid());
if (policy != nullptr) {
brokerFd = FileDescriptor();
mSandboxBroker =
SandboxBroker::Create(std::move(policy), OtherPid(), brokerFd);
// This is unlikely to fail and probably indicates OS resource
// exhaustion, but we can at least try to recover.
if (NS_WARN_IF(mSandboxBroker == nullptr)) {
return false;
}
MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
}
#endif // XP_LINUX && MOZ_SANDBOX
SendInit(brokerFd);
#ifdef MOZ_GECKO_PROFILER
Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
#endif
return true;
}
bool RDDChild::EnsureRDDReady() {

View File

@ -12,6 +12,10 @@
namespace mozilla {
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
class SandboxBroker;
#endif
namespace ipc {
class CrashReporterHost;
} // namespace ipc
@ -28,7 +32,7 @@ class RDDChild final : public PRDDChild {
explicit RDDChild(RDDProcessHost* aHost);
~RDDChild();
void Init();
bool Init();
bool EnsureRDDReady();
@ -53,6 +57,9 @@ class RDDChild final : public PRDDChild {
RDDProcessHost* mHost;
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
UniquePtr<SandboxBroker> mSandboxBroker;
#endif
bool mRDDReady;
};

View File

@ -19,6 +19,10 @@
#include "mozilla/ipc/CrashReporterClient.h"
#include "mozilla/ipc/ProcessChild.h"
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
# include "mozilla/Sandbox.h"
#endif
#ifdef MOZ_GECKO_PROFILER
# include "ChildProfilerController.h"
#endif
@ -123,12 +127,19 @@ static void StartRDDMacSandbox() {
}
#endif
mozilla::ipc::IPCResult RDDParent::RecvInit() {
mozilla::ipc::IPCResult RDDParent::RecvInit(const MaybeFileDesc& aBrokerFd) {
Unused << SendInitComplete();
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
#if defined(MOZ_SANDBOX)
# if defined(XP_MACOSX)
StartRDDMacSandbox();
#endif
# elif defined(XP_LINUX)
int fd = -1;
if (aBrokerFd.type() == MaybeFileDesc::TFileDescriptor) {
fd = aBrokerFd.get_FileDescriptor().ClonePlatformHandle().release();
}
SetRemoteDataDecoderSandbox(fd);
# endif // XP_MACOSX/XP_LINUX
#endif // MOZ_SANDBOX
return IPC_OK();
}

View File

@ -24,7 +24,7 @@ class RDDParent final : public PRDDParent {
bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
MessageLoop* aIOLoop, IPC::Channel* aChannel);
mozilla::ipc::IPCResult RecvInit();
mozilla::ipc::IPCResult RecvInit(const MaybeFileDesc& aBrokerFd);
mozilla::ipc::IPCResult RecvInitProfiler(
Endpoint<PProfilerChild>&& aEndpoint);

View File

@ -128,7 +128,9 @@ void RDDProcessHost::InitAfterConnect(bool aSucceeded) {
mRDDChild->Open(GetChannel(), base::GetProcId(GetChildProcessHandle()));
MOZ_ASSERT(rv);
mRDDChild->Init();
if (!mRDDChild->Init()) {
KillHard("ActorInitFailed");
}
}
if (mListener) {

View File

@ -653,4 +653,24 @@ void SetMediaPluginSandbox(const char* aFilePath) {
}
#endif // MOZ_GMP_SANDBOX
void SetRemoteDataDecoderSandbox(int aBroker) {
if (PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX") != nullptr) {
if (aBroker >= 0) {
close(aBroker);
}
return;
}
gSandboxReporterClient =
new SandboxReporterClient(SandboxReport::ProcType::RDD);
// FIXME(bug 1513773): merge this with the one for content?
static SandboxBrokerClient* sBroker;
if (aBroker >= 0) {
sBroker = new SandboxBrokerClient(aBroker);
}
SetCurrentProcessSandbox(GetDecoderSandboxPolicy(sBroker));
}
} // namespace mozilla

View File

@ -62,6 +62,8 @@ MOZ_EXPORT bool SetContentProcessSandbox(ContentProcessSandboxParams&& aParams);
MOZ_EXPORT void SetMediaPluginSandbox(const char* aFilePath);
#endif
MOZ_EXPORT void SetRemoteDataDecoderSandbox(int aBroker);
} // namespace mozilla
#endif // mozilla_Sandbox_h

View File

@ -1400,4 +1400,23 @@ UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(
#endif // MOZ_GMP_SANDBOX
// The policy for the data decoder process is similar to the one for
// media plugins, but the codec code is all in-tree so it's better
// behaved and doesn't need special exceptions (or the ability to load
// a plugin file). However, it does directly create shared memory
// segments, so it may need file brokering.
class RDDSandboxPolicy final : public SandboxPolicyCommon {
public:
explicit RDDSandboxPolicy(SandboxBrokerClient* aBroker)
: SandboxPolicyCommon(aBroker) {}
// Pass through EvaluateSyscall.
};
UniquePtr<sandbox::bpf_dsl::Policy> GetDecoderSandboxPolicy(
SandboxBrokerClient* aMaybeBroker) {
return UniquePtr<sandbox::bpf_dsl::Policy>(
new RDDSandboxPolicy(aMaybeBroker));
}
} // namespace mozilla

View File

@ -19,9 +19,9 @@ class Policy;
} // namespace sandbox
namespace mozilla {
class SandboxBrokerClient;
#ifdef MOZ_CONTENT_SANDBOX
class SandboxBrokerClient;
struct ContentProcessSandboxParams;
UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy(
@ -36,6 +36,9 @@ UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(
const SandboxOpenedFiles* aFiles);
#endif
UniquePtr<sandbox::bpf_dsl::Policy> GetDecoderSandboxPolicy(
SandboxBrokerClient* aMaybeBroker);
} // namespace mozilla
#endif

View File

@ -111,6 +111,8 @@ class SandboxBroker final : private SandboxBrokerCommon,
return Lookup(nsDependentCString(aPath));
}
bool IsEmpty() const { return mMap.Count() == 0; }
private:
// ValidatePath checks |path| and returns true if these conditions are met
// * Greater than 0 length

View File

@ -193,6 +193,13 @@ static void AddLdconfigPaths(SandboxBroker::Policy* aPolicy) {
AddPathsFromFile(aPolicy, ldconfigPath);
}
static void AddSharedMemoryPaths(SandboxBroker::Policy* aPolicy, pid_t aPid) {
std::string shmPath("/dev/shm");
if (base::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
aPolicy->AddPrefix(rdwrcr, shmPath.c_str());
}
}
SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory() {
// Policy entries that are the same in every process go here, and
// are cached over the lifetime of the factory.
@ -524,10 +531,7 @@ UniquePtr<SandboxBroker::Policy> SandboxBrokerPolicyFactory::GetContentPolicy(
if (allowPulse) {
policy->AddDir(rdwrcr, "/dev/shm");
} else {
std::string shmPath("/dev/shm");
if (base::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
policy->AddPrefix(rdwrcr, shmPath.c_str());
}
AddSharedMemoryPaths(policy.get(), aPid);
}
# ifdef MOZ_WIDGET_GTK
@ -581,5 +585,17 @@ void SandboxBrokerPolicyFactory::AddDynamicPathList(
}
}
/* static */ UniquePtr<SandboxBroker::Policy>
SandboxBrokerPolicyFactory::GetUtilityPolicy(int aPid) {
auto policy = MakeUnique<SandboxBroker::Policy>();
AddSharedMemoryPaths(policy.get(), aPid);
if (policy->IsEmpty()) {
policy = nullptr;
}
return policy;
}
#endif // MOZ_CONTENT_SANDBOX
} // namespace mozilla

View File

@ -20,6 +20,8 @@ class SandboxBrokerPolicyFactory {
bool aFileProcess);
#endif
static UniquePtr<SandboxBroker::Policy> GetUtilityPolicy(int aPid);
private:
UniquePtr<const SandboxBroker::Policy> mCommonContentPolicy;
static void AddDynamicPathList(SandboxBroker::Policy* policy,

View File

@ -228,6 +228,8 @@ static int GetEffectiveSandboxLevel(GeckoProcessType aType) {
}
return 0;
#endif
case GeckoProcessType_RDD:
return PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX") == nullptr ? 1 : 0;
default:
return 0;
}
@ -277,12 +279,13 @@ void SandboxLaunchPrepare(GeckoProcessType aType,
switch (aType) {
#ifdef MOZ_GMP_SANDBOX
case GeckoProcessType_GMPlugin:
#endif
case GeckoProcessType_RDD:
if (level >= 1) {
canChroot = true;
flags |= CLONE_NEWNET | CLONE_NEWIPC;
}
break;
#endif
#ifdef MOZ_CONTENT_SANDBOX
case GeckoProcessType_Content:
if (level >= 4) {

View File

@ -126,11 +126,14 @@ static void SubmitToTelemetry(const SandboxReport& aReport) {
case SandboxReport::ProcType::CONTENT:
key.AppendLiteral("content");
break;
case SandboxReport::ProcType::FILE:
key.AppendLiteral("file");
break;
case SandboxReport::ProcType::MEDIA_PLUGIN:
key.AppendLiteral("gmp");
break;
case SandboxReport::ProcType::FILE:
key.AppendLiteral("file");
case SandboxReport::ProcType::RDD:
key.AppendLiteral("rdd");
break;
default:
MOZ_ASSERT(false);

View File

@ -33,6 +33,7 @@ struct SandboxReport {
CONTENT,
FILE,
MEDIA_PLUGIN,
RDD,
};
// The syscall number and arguments are usually `unsigned long`, but

View File

@ -76,6 +76,9 @@ NS_IMETHODIMP SandboxReportWrapper::GetProcType(nsACString& aProcType) {
case SandboxReport::ProcType::MEDIA_PLUGIN:
aProcType.AssignLiteral("mediaPlugin");
return NS_OK;
case SandboxReport::ProcType::RDD:
aProcType.AssignLiteral("dataDecoder");
return NS_OK;
default:
MOZ_ASSERT(false);
return NS_ERROR_UNEXPECTED;

View File

@ -260,6 +260,7 @@ effective-content-sandbox-level = Effective Content Process Sandbox Level
sandbox-proc-type-content = content
sandbox-proc-type-file = file content
sandbox-proc-type-media-plugin = media plugin
sandbox-proc-type-data-decoder = data decoder
launcher-process-status-0 = Enabled
launcher-process-status-1 = Disabled due to failure