Bug 1530245 - Launch sandbox from new remote sandbox broker process. r=jld,bobowen

Depends on D22051

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Chris Pearce 2019-03-13 09:24:52 +00:00
parent f4c9b88845
commit de686d23c1
26 changed files with 844 additions and 55 deletions

View File

@ -46,6 +46,13 @@ int content_process_main(mozilla::Bootstrap* bootstrap, int argc,
bootstrap->XRE_SetProcessType(argv[--argc]);
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
if (bootstrap->XRE_GetProcessType() == GeckoProcessType_RemoteSandboxBroker) {
childData.sandboxBrokerServices =
mozilla::sandboxing::GetInitializedBrokerServices();
}
#endif
nsresult rv = bootstrap->XRE_InitChildProcess(argc, argv, &childData);
return NS_FAILED(rv);
}

View File

@ -44,9 +44,12 @@ static_assert(nsICrashService::PROCESS_TYPE_RDD == (int)GeckoProcessType_RDD,
static_assert(nsICrashService::PROCESS_TYPE_SOCKET ==
(int)GeckoProcessType_Socket,
"GeckoProcessType enum is out of sync with nsICrashService!");
static_assert(nsICrashService::PROCESS_TYPE_SANDBOX_BROKER ==
(int)GeckoProcessType_RemoteSandboxBroker,
"GeckoProcessType enum is out of sync with nsICrashService!");
// Add new static asserts here if you add more process types.
// Update this static assert as well.
static_assert(nsICrashService::PROCESS_TYPE_SOCKET + 1 ==
static_assert(nsICrashService::PROCESS_TYPE_SANDBOX_BROKER + 1 ==
(int)GeckoProcessType_End,
"GeckoProcessType enum is out of sync with nsICrashService!");

View File

@ -56,6 +56,9 @@
# include "mozilla/Preferences.h"
# include "mozilla/sandboxing/sandboxLogging.h"
# include "WinUtils.h"
# if defined(_ARM64_)
# include "mozilla/remoteSandboxBroker.h"
# endif
# endif
#endif
@ -103,7 +106,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
mGroupId(u"-"),
#endif
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
mSandboxBroker(new SandboxBroker()),
mEnableSandboxLogging(false),
mSandboxLevel(0),
#endif
@ -151,6 +153,12 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
mChildProcessHandle);
#endif
}
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
if (mSandboxBroker) {
mSandboxBroker->Shutdown();
mSandboxBroker = nullptr;
}
#endif
}
void GeckoChildProcessHost::Destroy() {
@ -1020,19 +1028,22 @@ bool GeckoChildProcessHost::PerformAsyncLaunch(
FilePath exePath;
BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
# if defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
# if defined(MOZ_SANDBOX) || defined(_ARM64_)
const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
const bool isWidevine = isGMP && Contains(aExtraOpts, "gmp-widevinecdm");
# if defined(_ARM64_) && defined(XP_WIN)
# if defined(_ARM64_)
const bool isClearKey = isGMP && Contains(aExtraOpts, "gmp-clearkey");
if (isGMP && (isClearKey || isWidevine)) {
// On Windows on ARM64 for ClearKey and Widevine, we want to run the
// x86 plugin-container.exe in the "i686" subdirectory, instead of the
// aarch64 plugin-container.exe. So insert "i686" into the exePath.
const bool isSandboxBroker =
mProcessType == GeckoProcessType_RemoteSandboxBroker;
if (isClearKey || isWidevine || isSandboxBroker) {
// On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
// launcher process, we want to run the x86 plugin-container.exe in
// the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
// So insert "i686" into the exePath.
exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
}
# endif
# endif // defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
# endif // if defined(_ARM64_)
# endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
CommandLine cmdLine(exePath.ToWStringHack());
@ -1064,6 +1075,13 @@ bool GeckoChildProcessHost::PerformAsyncLaunch(
}
# if defined(MOZ_SANDBOX)
# if defined(_ARM64_)
if (isClearKey || isWidevine)
mSandboxBroker = new RemoteSandboxBroker();
else
# endif // if defined(_ARM64_)
mSandboxBroker = new SandboxBroker();
bool shouldSandboxCurrentProcess = false;
// XXX: Bug 1124167: We should get rid of the process specific logic for
@ -1136,6 +1154,9 @@ bool GeckoChildProcessHost::PerformAsyncLaunch(
case GeckoProcessType_Socket:
// TODO - setup sandboxing for the socket process.
break;
case GeckoProcessType_RemoteSandboxBroker:
// We don't sandbox the sandbox launcher...
break;
case GeckoProcessType_Default:
default:
MOZ_CRASH("Bad process type in GeckoChildProcessHost");
@ -1208,7 +1229,7 @@ bool GeckoChildProcessHost::PerformAsyncLaunch(
// No handle duplication necessary.
break;
default:
if (!mSandboxBroker->AddTargetPeer(process)) {
if (!SandboxBroker::AddTargetPeer(process)) {
NS_WARNING("Failed to add child process as target peer.");
}
break;

View File

@ -1059,3 +1059,5 @@ description =
description = bug 1363126
[PClientSource::WorkerSyncPing]
description = Synchronous ping allowing worker thread to confirm actor is created. Necessary to avoid racing with ClientHandle actors on main thread.
[PRemoteSandboxBroker::LaunchApp]
description = Synchronous launch of a child process that in turn launches and sandboxes another process. Called on a dedicated thread and targets a dedicated process, so this shouldn't block anything.

View File

@ -20,6 +20,7 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
FORCE_STATIC_LIB = True
DIRS += [
'win/src/remotesandboxbroker',
'win/src/sandboxbroker',
'win/src/sandboxpermissions',
'win/src/sandboxtarget',

View File

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
namespace mozilla {
struct EnvVar {
nsString name;
nsString value;
};
struct LaunchParameters {
nsString path;
nsString args;
EnvVar[] env;
uint32_t processType;
uint32_t sandboxLevel;
nsString[] allowedReadFiles;
uint64_t[] shareHandles;
bool enableLogging;
};
intr protocol PRemoteSandboxBroker
{
parent:
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
child:
intr LaunchApp(LaunchParameters params)
returns (bool ok, uint64_t handle);
};
} // namespace mozilla

View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "RemoteSandboxBrokerChild.h"
#include "mozilla/ipc/CrashReporterClient.h"
#include "nsDebugImpl.h"
#include "mozilla/ipc/CrashReporterClient.h"
#include "RemoteSandboxBrokerProcessChild.h"
using namespace mozilla::ipc;
namespace mozilla {
RemoteSandboxBrokerChild::RemoteSandboxBrokerChild() {
nsDebugImpl::SetMultiprocessMode("RemoteSandboxBroker");
}
RemoteSandboxBrokerChild::~RemoteSandboxBrokerChild() {}
bool RemoteSandboxBrokerChild::Init(base::ProcessId aParentPid,
MessageLoop* aIOLoop,
IPC::Channel* aChannel) {
if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
return false;
}
CrashReporterClient::InitSingleton(this);
return true;
}
void RemoteSandboxBrokerChild::ActorDestroy(ActorDestroyReason aWhy) {
if (AbnormalShutdown == aWhy) {
NS_WARNING("Abnormal shutdown of GMP process!");
ipc::ProcessChild::QuickExit();
}
CrashReporterClient::DestroySingleton();
XRE_ShutdownChildProcess();
}
mozilla::ipc::IPCResult RemoteSandboxBrokerChild::AnswerLaunchApp(
LaunchParameters&& aParams, bool* aOutOk, uint64_t* aOutHandle) {
auto towstring = [](const nsString& s) {
return std::wstring(s.get(), s.Length());
};
base::EnvironmentMap envmap;
for (const EnvVar& env : aParams.env()) {
envmap[towstring(env.name())] = towstring(env.value());
}
if (!mSandboxBroker.SetSecurityLevelForGMPlugin(
AbstractSandboxBroker::SandboxLevel(aParams.sandboxLevel()))) {
*aOutOk = false;
return IPC_OK();
}
for (const auto& path : aParams.allowedReadFiles()) {
if (!mSandboxBroker.AllowReadFile(path.get())) {
*aOutOk = false;
return IPC_OK();
}
}
for (const auto& handle : aParams.shareHandles()) {
mSandboxBroker.AddHandleToShare(HANDLE(handle));
}
HANDLE p;
*aOutOk =
mSandboxBroker.LaunchApp(aParams.path().get(), aParams.args().get(),
envmap, GeckoProcessType(aParams.processType()),
aParams.enableLogging(), (void**)&p);
if (*aOutOk) {
*aOutHandle = uint64_t(p);
}
for (const auto& handle : aParams.shareHandles()) {
CloseHandle(HANDLE(handle));
}
return IPC_OK();
}
} // namespace mozilla

View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef RemoteSandboxBrokerChild_h_
#define RemoteSandboxBrokerChild_h_
#include "mozilla/PRemoteSandboxBrokerChild.h"
#include "sandboxBroker.h"
namespace mozilla {
class RemoteSandboxBrokerChild : public PRemoteSandboxBrokerChild {
friend class PRemoteSandboxBrokerChild;
public:
RemoteSandboxBrokerChild();
virtual ~RemoteSandboxBrokerChild();
bool Init(base::ProcessId aParentPid, MessageLoop* aIOLoop,
IPC::Channel* aChannel);
private:
mozilla::ipc::IPCResult AnswerLaunchApp(LaunchParameters&& aParams,
bool* aOutOk, uint64_t* aOutHandle);
void ActorDestroy(ActorDestroyReason aWhy);
SandboxBroker mSandboxBroker;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "RemoteSandboxBrokerParent.h"
#include "RemoteSandboxBrokerProcessParent.h"
#include "mozilla/Telemetry.h"
#include <windows.h>
namespace mozilla {
RefPtr<GenericPromise> RemoteSandboxBrokerParent::Launch(
const nsTArray<uint64_t>& aHandlesToShare) {
MOZ_ASSERT(!mProcess);
if (mProcess) {
// Don't re-init.
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
mProcess = new RemoteSandboxBrokerProcessParent();
for (uint64_t handle : aHandlesToShare) {
mProcess->AddHandleToShare(HANDLE(handle));
}
// Note: we rely on the caller to keep this instance alive while we launch
// the process, so that these closures point to valid memory.
auto resolve = [this](base::ProcessHandle handle) {
mOpened = Open(mProcess->GetChannel(), base::GetProcId(handle));
if (!mOpened) {
mProcess->Destroy();
mProcess = nullptr;
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
return GenericPromise::CreateAndResolve(true, __func__);
};
auto reject = [this]() {
NS_ERROR("failed to launch child in the parent");
if (mProcess) {
mProcess->Destroy();
mProcess = nullptr;
}
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
};
return mProcess->AsyncLaunch()->Then(GetCurrentThreadSerialEventTarget(),
__func__, std::move(resolve),
std::move(reject));
}
bool RemoteSandboxBrokerParent::DuplicateFromLauncher(HANDLE aLauncherHandle,
LPHANDLE aOurHandle) {
return ::DuplicateHandle(mProcess->GetChildProcessHandle(), aLauncherHandle,
::GetCurrentProcess(), aOurHandle, 0, false,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
}
void RemoteSandboxBrokerParent::ActorDestroy(ActorDestroyReason aWhy) {
if (AbnormalShutdown == aWhy) {
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
NS_LITERAL_CSTRING("sandboxbroker"), 1);
if (mCrashReporter) {
mCrashReporter->GenerateCrashReport(OtherPid());
mCrashReporter = nullptr;
}
}
Shutdown();
}
void RemoteSandboxBrokerParent::Shutdown() {
if (mOpened) {
mOpened = false;
Close();
}
if (mProcess) {
mProcess->Destroy();
mProcess = nullptr;
}
}
mozilla::ipc::IPCResult RemoteSandboxBrokerParent::RecvInitCrashReporter(
Shmem&& aShmem, const NativeThreadId& aThreadId) {
mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
GeckoProcessType_RemoteSandboxBroker, aShmem, aThreadId);
return IPC_OK();
}
} // namespace mozilla

View File

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef RemoteSandboxBrokerParent_h_
#define RemoteSandboxBrokerParent_h_
#include "mozilla/PRemoteSandboxBrokerParent.h"
#include "RemoteSandboxBrokerProcessParent.h"
#include "mozilla/ipc/CrashReporterHost.h"
namespace mozilla {
class RemoteSandboxBrokerParent : public PRemoteSandboxBrokerParent {
friend class PRemoteSandboxBrokerParent;
public:
bool DuplicateFromLauncher(HANDLE aLauncherHandle, LPHANDLE aOurHandle);
void Shutdown();
// Asynchronously launches the launcher process.
// Note: we rely on the caller to keep this instance alive
// until this promise resolves.
RefPtr<GenericPromise> Launch(const nsTArray<uint64_t>& aHandlesToShare);
private:
mozilla::ipc::IPCResult RecvInitCrashReporter(
Shmem&& aShmem, const NativeThreadId& aThreadId);
void ActorDestroy(ActorDestroyReason aWhy) override;
RemoteSandboxBrokerProcessParent* mProcess = nullptr;
bool mOpened = false;
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
};
} // namespace mozilla
#endif // RemoteSandboxBrokerParent_h_

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "RemoteSandboxBrokerProcessChild.h"
#include "mozilla/ipc/IOThreadChild.h"
#include "mozilla/BackgroundHangMonitor.h"
using mozilla::ipc::IOThreadChild;
namespace mozilla {
RemoteSandboxBrokerProcessChild::RemoteSandboxBrokerProcessChild(
ProcessId aParentPid)
: ProcessChild(aParentPid) {}
RemoteSandboxBrokerProcessChild::~RemoteSandboxBrokerProcessChild() {}
bool RemoteSandboxBrokerProcessChild::Init(int aArgc, char* aArgv[]) {
BackgroundHangMonitor::Startup();
return mSandboxBrokerChild.Init(ParentPid(), IOThreadChild::message_loop(),
IOThreadChild::channel());
}
void RemoteSandboxBrokerProcessChild::CleanUp() {
BackgroundHangMonitor::Shutdown();
}
} // namespace mozilla

View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef RemoteSandboxBrokerProcessChild_h_
#define RemoteSandboxBrokerProcessChild_h_
#include "mozilla/ipc/ProcessChild.h"
#include "RemoteSandboxBrokerChild.h"
namespace mozilla {
class RemoteSandboxBrokerProcessChild final
: public mozilla::ipc::ProcessChild {
protected:
typedef mozilla::ipc::ProcessChild ProcessChild;
public:
explicit RemoteSandboxBrokerProcessChild(ProcessId aParentPid);
~RemoteSandboxBrokerProcessChild();
bool Init(int aArgc, char* aArgv[]) override;
void CleanUp() override;
private:
RemoteSandboxBrokerChild mSandboxBrokerChild;
DISALLOW_COPY_AND_ASSIGN(RemoteSandboxBrokerProcessChild);
};
} // namespace mozilla
#endif // GMPProcessChild_h_

View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "RemoteSandboxBrokerProcessParent.h"
#include "nsIRunnable.h"
#include <windows.h>
using mozilla::ipc::GeckoChildProcessHost;
namespace mozilla {
RemoteSandboxBrokerProcessParent::RemoteSandboxBrokerProcessParent()
: GeckoChildProcessHost(GeckoProcessType_RemoteSandboxBroker) {
MOZ_COUNT_CTOR(RemoteSandboxBrokerProcessParent);
}
RemoteSandboxBrokerProcessParent::~RemoteSandboxBrokerProcessParent() {
MOZ_COUNT_DTOR(RemoteSandboxBrokerProcessParent);
}
RefPtr<RemoteSandboxBrokerProcessParent::HandlePromise>
RemoteSandboxBrokerProcessParent::AsyncLaunch() {
if (!GeckoChildProcessHost::AsyncLaunch()) {
return HandlePromise::CreateAndReject(GeckoChildProcessHost::LaunchError{},
__func__);
}
return WhenProcessHandleReady();
}
} // namespace mozilla

View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef RemoteSandboxBrokerProcessParent_h_
#define RemoteSandboxBrokerProcessParent_h_
#include "mozilla/Attributes.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/thread.h"
#include "chrome/common/child_process_host.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
class nsIRunnable;
namespace mozilla {
class RemoteSandboxBrokerProcessParent final
: public mozilla::ipc::GeckoChildProcessHost {
public:
using LaunchError = GeckoChildProcessHost::LaunchError;
using LaunchPromise = GeckoChildProcessHost::LaunchPromise<bool>;
RemoteSandboxBrokerProcessParent();
using GeckoChildProcessHost::HandlePromise;
RefPtr<HandlePromise> AsyncLaunch();
bool CanShutdown() override { return true; }
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
private:
~RemoteSandboxBrokerProcessParent();
DISALLOW_COPY_AND_ASSIGN(RemoteSandboxBrokerProcessParent);
};
} // namespace mozilla
#endif // ifndef GMPProcessParent_h

View File

@ -0,0 +1,35 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'remoteSandboxBroker.cpp',
'RemoteSandboxBrokerChild.cpp',
'RemoteSandboxBrokerParent.cpp',
'RemoteSandboxBrokerProcessChild.cpp',
'RemoteSandboxBrokerProcessParent.cpp',
]
EXPORTS.mozilla += [
'remoteSandboxBroker.h',
'RemoteSandboxBrokerChild.h',
'RemoteSandboxBrokerParent.h',
'RemoteSandboxBrokerProcessChild.h',
'RemoteSandboxBrokerProcessParent.h',
]
for var in ('UNICODE', '_UNICODE'):
DEFINES[var] = True
FINAL_LIBRARY = 'xul'
if CONFIG['CC_TYPE'] == 'clang-cl':
AllowCompilerWarnings() # workaround for bug 1090497
IPDL_SOURCES += [
'PRemoteSandboxBroker.ipdl'
]
include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "remoteSandboxBroker.h"
namespace mozilla {
RemoteSandboxBroker::RemoteSandboxBroker() {}
RemoteSandboxBroker::~RemoteSandboxBroker() {
MOZ_ASSERT(
mShutdown,
"Shutdown must be called on RemoteSandboxBroker before destruction!");
}
void RemoteSandboxBroker::Shutdown() {
MOZ_ASSERT(!mShutdown, "Don't call Shutdown() twice!");
mShutdown = true;
if (!mIPCLaunchThread) {
// Can't have launched child process, nothing to shutdown.
return;
}
RefPtr<RemoteSandboxBroker> self = this;
mIPCLaunchThread->Dispatch(
NS_NewRunnableFunction("Remote Sandbox Launch", [self, this]() {
// Note: `self` here should be the last reference to this instance.
mParent.Shutdown();
mIPCLaunchThread = nullptr;
}));
}
bool RemoteSandboxBroker::LaunchApp(const wchar_t *aPath,
const wchar_t *aArguments,
base::EnvironmentMap &aEnvironment,
GeckoProcessType aProcessType,
const bool aEnableLogging,
void **aProcessHandle) {
// Note: we expect to be called on the IPC launch thread from
// GeckoChildProcesHost while it's launching a child process. We can't
// run a synchronous launch here as that blocks the calling thread while
// it dispatches a task to the IPC launch thread to spawn the process.
// Since our calling thread is the IPC launch thread, we'd then be
// deadlocked. So instead we do an async launch, and spin the event
// loop until the process launch succeeds.
// We should be on the IPC launch thread. We're shutdown on the IO thread,
// so save a ref to the IPC launch thread here, so we can close the channel
// on the IPC launch thread on shutdown.
mIPCLaunchThread = GetCurrentThreadEventTarget();
mParameters.path() = nsDependentString(aPath);
mParameters.args() = nsDependentString(aArguments);
auto toNsString = [](const std::wstring &s) {
return nsDependentString(s.c_str());
};
for (auto itr : aEnvironment) {
mParameters.env().AppendElement(
EnvVar(toNsString(itr.first), toNsString(itr.second)));
}
mParameters.processType() = uint32_t(aProcessType);
mParameters.enableLogging() = aEnableLogging;
enum Result { Pending, Succeeded, Failed };
Result res = Pending;
auto resolve = [&](bool ok) {
res = Succeeded;
return GenericPromise::CreateAndResolve(ok, __func__);
};
auto reject = [&](nsresult) {
res = Failed;
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
};
mParent.Launch(mParameters.shareHandles())
->Then(GetCurrentThreadSerialEventTarget(), __func__, std::move(resolve),
std::move(reject));
// Spin the event loop while the sandbox launcher process launches.
SpinEventLoopUntil([&]() { return res != Pending; });
if (res == Failed) {
return false;
}
uint64_t handle = 0;
bool ok = false;
bool rv = mParent.CallLaunchApp(std::move(mParameters), &ok, &handle) && ok;
mParameters.shareHandles().Clear();
if (!rv) {
return false;
}
// Duplicate the handle of the child process that the launcher launched from
// the launcher process's space into this process' space.
HANDLE ourChildHandle = 0;
bool dh = mParent.DuplicateFromLauncher((HANDLE)handle, &ourChildHandle);
if (!dh) {
return false;
}
*aProcessHandle = (void **)(ourChildHandle);
base::ProcessHandle process = *aProcessHandle;
SandboxBroker::AddTargetPeer(process);
return true;
}
bool RemoteSandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel) {
mParameters.sandboxLevel() = uint32_t(aLevel);
return true;
}
bool RemoteSandboxBroker::AllowReadFile(wchar_t const *aFile) {
mParameters.allowedReadFiles().AppendElement(nsDependentString(aFile));
return true;
}
void RemoteSandboxBroker::AddHandleToShare(HANDLE aHandle) {
mParameters.shareHandles().AppendElement(uint64_t(aHandle));
}
#ifdef MOZ_CONTENT_SANDBOX
void RemoteSandboxBroker::SetSecurityLevelForContentProcess(
int32_t aSandboxLevel, bool aIsFileProcess) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForContentProcess not Implemented");
}
#endif
void RemoteSandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForGPUProcess not Implemented");
}
bool RemoteSandboxBroker::SetSecurityLevelForRDDProcess() {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForRDDProcess not Implemented");
}
bool RemoteSandboxBroker::SetSecurityLevelForPluginProcess(
int32_t aSandboxLevel) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForPluginProcess not Implemented");
}
AbstractSandboxBroker *CreateRemoteSandboxBroker() {
return new RemoteSandboxBroker();
}
} // namespace mozilla

View File

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef __REMOTE_SANDBOXBROKER_H__
#define __REMOTE_SANDBOXBROKER_H__
#include "sandboxBroker.h"
#include "RemoteSandboxBrokerParent.h"
namespace mozilla {
// To make sandboxing an x86 plugin-container process on Windows on ARM64,
// we launch an x86 child process which in turn launches and sandboxes the x86
// plugin-container child. This means the sandbox broker (in the remote
// x86 sandbox launcher process) can be same-arch with the process that it's
// sandboxing, which means all the sandbox's assumptions about things being
// same arch still hold.
class RemoteSandboxBroker : public AbstractSandboxBroker {
public:
RemoteSandboxBroker();
void Shutdown() override;
// Note: This should be called on the IPC launch thread, and this spins
// the event loop. So this means potentially another IPC launch could occur
// re-entrantly while calling this.
bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
base::EnvironmentMap &aEnvironment,
GeckoProcessType aProcessType, const bool aEnableLogging,
void **aProcessHandle) override;
// Security levels for different types of processes
#if defined(MOZ_CONTENT_SANDBOX)
void SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
bool aIsFileProcess) override;
#endif
void SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) override;
bool SetSecurityLevelForRDDProcess() override;
bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel) override;
bool SetSecurityLevelForGMPlugin(SandboxLevel aLevel) override;
bool AllowReadFile(wchar_t const *file) override;
void AddHandleToShare(HANDLE aHandle) override;
private:
virtual ~RemoteSandboxBroker();
// Parameters that we use to launch the child process.
LaunchParameters mParameters;
RemoteSandboxBrokerParent mParent;
// We bind the RemoteSandboxBrokerParent to the IPC launch thread.
// As such, we must close its channel on the same thread. So we save
// a reference to the IPC launch thread here.
nsCOMPtr<nsIEventTarget> mIPCLaunchThread;
// True if we've been shutdown.
bool mShutdown = false;
};
} // namespace mozilla
#endif // __REMOTE_SANDBOXBROKER_H__

View File

@ -97,43 +97,54 @@ static void CacheDirAndAutoClear(nsIProperties* aDirSvc, const char* aDirKey,
void SandboxBroker::GeckoDependentInitialize() {
MOZ_ASSERT(NS_IsMainThread());
// Cache directory paths for use in policy rules, because the directory
// service must be called on the main thread.
nsresult rv;
nsCOMPtr<nsIProperties> dirSvc =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
MOZ_ASSERT(
false,
"Failed to get directory service, cannot cache directories for rules.");
LOG_E(
"Failed to get directory service, cannot cache directories for rules.");
return;
}
bool haveXPCOM = XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker;
if (haveXPCOM) {
// Cache directory paths for use in policy rules, because the directory
// service must be called on the main thread.
nsresult rv;
nsCOMPtr<nsIProperties> dirSvc =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
MOZ_ASSERT(false,
"Failed to get directory service, cannot cache directories "
"for rules.");
LOG_E(
"Failed to get directory service, cannot cache directories for "
"rules.");
return;
}
CacheDirAndAutoClear(dirSvc, NS_GRE_DIR, &sBinDir);
CacheDirAndAutoClear(dirSvc, NS_APP_USER_PROFILE_50_DIR, &sProfileDir);
CacheDirAndAutoClear(dirSvc, NS_APP_CONTENT_PROCESS_TEMP_DIR,
&sContentTempDir);
CacheDirAndAutoClear(dirSvc, NS_APP_PLUGIN_PROCESS_TEMP_DIR, &sPluginTempDir);
CacheDirAndAutoClear(dirSvc, NS_WIN_APPDATA_DIR, &sRoamingAppDataDir);
CacheDirAndAutoClear(dirSvc, NS_WIN_LOCAL_APPDATA_DIR, &sLocalAppDataDir);
CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DEV_DIR,
&sUserExtensionsDevDir);
CacheDirAndAutoClear(dirSvc, NS_GRE_DIR, &sBinDir);
CacheDirAndAutoClear(dirSvc, NS_APP_USER_PROFILE_50_DIR, &sProfileDir);
CacheDirAndAutoClear(dirSvc, NS_APP_CONTENT_PROCESS_TEMP_DIR,
&sContentTempDir);
CacheDirAndAutoClear(dirSvc, NS_APP_PLUGIN_PROCESS_TEMP_DIR,
&sPluginTempDir);
CacheDirAndAutoClear(dirSvc, NS_WIN_APPDATA_DIR, &sRoamingAppDataDir);
CacheDirAndAutoClear(dirSvc, NS_WIN_LOCAL_APPDATA_DIR, &sLocalAppDataDir);
CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DEV_DIR,
&sUserExtensionsDevDir);
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DIR, &sUserExtensionsDir);
CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DIR,
&sUserExtensionsDir);
#endif
}
// Create sLaunchErrors up front because ClearOnShutdown must be called on the
// main thread.
sLaunchErrors = MakeUnique<nsTHashtable<nsCStringHashKey>>();
ClearOnShutdown(&sLaunchErrors);
// Cache prefs that are needed off main thread.
Preferences::AddBoolVarCache(&sRddWin32kDisable,
"security.sandbox.rdd.win32k-disable");
Preferences::AddBoolVarCache(&sGmpWin32kDisable,
"security.sandbox.gmp.win32k-disable");
if (haveXPCOM) {
// Cache prefs that are needed off main thread.
Preferences::AddBoolVarCache(&sRddWin32kDisable,
"security.sandbox.rdd.win32k-disable");
Preferences::AddBoolVarCache(&sGmpWin32kDisable,
"security.sandbox.gmp.win32k-disable");
} else {
sRddWin32kDisable = false;
sGmpWin32kDisable = false;
}
}
SandboxBroker::SandboxBroker() {
@ -1164,6 +1175,7 @@ bool SandboxBroker::AllowReadFile(wchar_t const* file) {
return true;
}
/* static */
bool SandboxBroker::AddTargetPeer(HANDLE aPeerProcess) {
if (!sBrokerService) {
return false;
@ -1204,4 +1216,22 @@ SandboxBroker::~SandboxBroker() {
}
}
#ifdef _ARM64_
// We can't include remoteSandboxBroker.h here directly, as it includes
// IPDL headers, which include a different copy of the chromium base
// libraries, which leads to conflicts.
extern AbstractSandboxBroker* CreateRemoteSandboxBroker();
#endif
// static
AbstractSandboxBroker* AbstractSandboxBroker::Create(
GeckoProcessType aProcessType) {
#ifdef _ARM64_
if (aProcessType == GeckoProcessType_GMPlugin) {
return CreateRemoteSandboxBroker();
}
#endif
return new SandboxBroker();
}
} // namespace mozilla

View File

@ -26,6 +26,9 @@ class AbstractSandboxBroker {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractSandboxBroker)
static AbstractSandboxBroker *Create(GeckoProcessType aProcessType);
virtual void Shutdown() = 0;
virtual bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
base::EnvironmentMap &aEnvironment,
GeckoProcessType aProcessType,
@ -47,12 +50,6 @@ class AbstractSandboxBroker {
// File system permissions
virtual bool AllowReadFile(wchar_t const *file) = 0;
/**
* Exposes AddTargetPeer from broker services, so that non-sandboxed
* processes can be added as handle duplication targets.
*/
virtual bool AddTargetPeer(HANDLE aPeerProcess) = 0;
/**
* Share a HANDLE with the child process. The HANDLE will be made available
* in the child process at the memory address
@ -71,6 +68,8 @@ class SandboxBroker : public AbstractSandboxBroker {
static void Initialize(sandbox::BrokerServices *aBrokerServices);
void Shutdown() override {}
/**
* Do initialization that depends on parts of the Gecko machinery having been
* created first.
@ -102,7 +101,7 @@ class SandboxBroker : public AbstractSandboxBroker {
* Exposes AddTargetPeer from broker services, so that non-sandboxed
* processes can be added as handle duplication targets.
*/
bool AddTargetPeer(HANDLE aPeerProcess) override;
static bool AddTargetPeer(HANDLE aPeerProcess);
/**
* Share a HANDLE with the child process. The HANDLE will be made available

View File

@ -4,7 +4,7 @@
#include "nsISupports.idl"
[scriptable, uuid(f60d76e5-62c3-4f58-89f6-b726c2b7bc20)]
[scriptable, uuid(70bd93ff-88fa-4600-8af8-57c8d002dbac)]
interface nsICrashService : nsISupports
{
/**
@ -30,6 +30,7 @@ interface nsICrashService : nsISupports
const long PROCESS_TYPE_VR = 6;
const long PROCESS_TYPE_RDD = 7;
const long PROCESS_TYPE_SOCKET = 8;
const long PROCESS_TYPE_SANDBOX_BROKER = 9;
// New process types should be added at the end of the above list.
const long CRASH_TYPE_CRASH = 0;

View File

@ -631,9 +631,10 @@ SYNC_ENUMS(GPU, GPU)
SYNC_ENUMS(VR, VR)
SYNC_ENUMS(RDD, RDD)
SYNC_ENUMS(SOCKET, Socket)
SYNC_ENUMS(SANDBOX_BROKER, RemoteSandboxBroker)
// .. and ensure that that is all of them:
static_assert(GeckoProcessType_Socket + 1 == GeckoProcessType_End,
static_assert(GeckoProcessType_RemoteSandboxBroker + 1 == GeckoProcessType_End,
"Did not find the final GeckoProcessType");
NS_IMETHODIMP
@ -1535,11 +1536,11 @@ static const char kShieldPrefName[] = "app.shield.optoutstudies.enabled";
static void OnLauncherPrefChanged(const char* aPref, void* aData) {
const bool kLauncherPrefDefaultValue =
# if defined(NIGHTLY_BUILD) || (MOZ_UPDATE_CHANNEL == beta)
true
true
# else
false
false
# endif // defined(NIGHTLY_BUILD) || (MOZ_UPDATE_CHANNEL == beta)
;
;
bool prefVal = Preferences::GetBool(kShieldPrefName, false) &&
Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED,
kLauncherPrefDefaultValue);

View File

@ -91,6 +91,7 @@
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
# include "mozilla/sandboxTarget.h"
# include "mozilla/sandboxing/loggingCallbacks.h"
# include "mozilla/RemoteSandboxBrokerProcessChild.h"
#endif
#if defined(MOZ_CONTENT_SANDBOX)
@ -123,6 +124,11 @@ using mozilla::_ipdltest::IPDLUnitTestProcessChild;
# include "jprof.h"
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
# include "mozilla/sandboxing/SandboxInitialization.h"
# include "mozilla/sandboxing/sandboxLogging.h"
#endif
#include "VRProcessChild.h"
using namespace mozilla;
@ -646,6 +652,7 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
break;
case GeckoProcessType_GMPlugin:
case GeckoProcessType_RemoteSandboxBroker:
uiLoopType = MessageLoop::TYPE_DEFAULT;
break;
default:
@ -653,6 +660,13 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
break;
}
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
if (aChildData->sandboxBrokerServices) {
SandboxBroker::Initialize(aChildData->sandboxBrokerServices);
SandboxBroker::GeckoDependentInitialize();
}
#endif
// If we are recording or replaying, initialize state and update arguments
// according to those which were captured by the MiddlemanProcessChild in the
// middleman process. No argument manipulation should happen between this
@ -715,6 +729,11 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
process = new net::SocketProcessImpl(parentPID);
break;
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
case GeckoProcessType_RemoteSandboxBroker:
process = new RemoteSandboxBrokerProcessChild(parentPID);
break;
#endif
default:
MOZ_CRASH("Unknown main thread class");
}
@ -736,10 +755,13 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
mozilla::sandboxing::InitLoggingIfRequired(
aChildData->ProvideLogFunction);
#endif
mozilla::FilePreferences::InitDirectoriesWhitelist();
mozilla::FilePreferences::InitPrefs();
OverrideDefaultLocaleIfNeeded();
if (XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker) {
// Remote sandbox launcher process doesn't have prerequisites for
// these...
mozilla::FilePreferences::InitDirectoriesWhitelist();
mozilla::FilePreferences::InitPrefs();
OverrideDefaultLocaleIfNeeded();
}
#if defined(MOZ_CONTENT_SANDBOX)
AddContentSandboxLevelAnnotation();

View File

@ -28,3 +28,4 @@ GECKO_PROCESS_TYPE(VR, "vr", VR)
GECKO_PROCESS_TYPE(RDD, "rdd", RDD)
// Socket process
GECKO_PROCESS_TYPE(Socket, "socket", Socket)
GECKO_PROCESS_TYPE(RemoteSandboxBroker, "sandbox", RemoteSandboxBroker)

View File

@ -31,6 +31,12 @@ struct XREChildData {
* Function to provide a logging function to the chromium sandbox code.
*/
mozilla::sandboxing::ProvideLogFunctionCb ProvideLogFunction = nullptr;
/**
* Chromium sandbox broker services; needed by the remote sandbox
* launcher process.
*/
sandbox::BrokerServices* sandboxBrokerServices = nullptr;
#endif
};

View File

@ -512,6 +512,7 @@ nsresult nsComponentManagerImpl::Init() {
// We are going to assume that only a select few (see below) process types
// want to load chrome manifests, and that any new process types will not
// want to load them, because they're not going to be executing JS.
case GeckoProcessType_RemoteSandboxBroker:
default:
loadChromeManifests = false;
break;

View File

@ -79,6 +79,7 @@ interface nsIXULRuntime : nsISupports
const unsigned long PROCESS_TYPE_VR = 6;
const unsigned long PROCESS_TYPE_RDD = 7;
const unsigned long PROCESS_TYPE_SOCKET = 8;
const unsigned long PROCESS_TYPE_SANDBOX_BROKER = 9;
/**
* The type of the caller's process. Returns one of the values above.