mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
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:
parent
5cc3212784
commit
af97210807
@ -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);
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -33,6 +33,7 @@ struct SandboxReport {
|
||||
CONTENT,
|
||||
FILE,
|
||||
MEDIA_PLUGIN,
|
||||
RDD,
|
||||
};
|
||||
|
||||
// The syscall number and arguments are usually `unsigned long`, but
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user