Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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"
#include "RemoteSandboxBrokerParent.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsIThread.h"
namespace mozilla {
RemoteSandboxBroker::RemoteSandboxBroker(uint32_t aLaunchArch)
: mParent(new RemoteSandboxBrokerParent), mLaunchArch(aLaunchArch) {}
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;
}));
}
Result<Ok, mozilla::ipc::LaunchError> RemoteSandboxBroker::LaunchApp(
const wchar_t* aPath, const wchar_t* aArguments,
base::EnvironmentMap& aEnvironment, GeckoProcessType aProcessType,
const bool aEnableLogging, const IMAGE_THUNK_DATA*, void** aProcessHandle) {
// Note: we expect to be called on the IPC launch thread from
// GeckoChildProcesHost while it's launching a child process. The IPC launch
// thread is a TaskQueue. 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 = GetCurrentSerialEventTarget();
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__);
};
// We need to wait on the current thread for the process to launch which will
// block the running IPC Launch taskqueue. We cannot use
// GetCurrentSerialEventTarget() (as this returns the currently running
// TaskQueue) to resolve our promise as it will be blocked until we return
// from this function.
nsCOMPtr<nsISerialEventTarget> target = NS_GetCurrentThread();
mParent->Launch(mLaunchArch, mParameters.shareHandles(), target)
->Then(target, __func__, std::move(resolve), std::move(reject));
// Spin the event loop while the sandbox launcher process launches.
SpinEventLoopUntil("RemoteSandboxBroker::LaunchApp"_ns,
[&]() { return res != Pending; });
if (res == Failed) {
return Err(mozilla::ipc::LaunchError("RSB::LaunchApp"));
}
uint64_t handle = 0;
bool ok = false;
bool rv = mParent->SendLaunchApp(std::move(mParameters), &ok, &handle) && ok;
mParameters.shareHandles().Clear();
if (!rv) {
mParent->Shutdown();
return Err(mozilla::ipc::LaunchError("RSB::SendLaunchApp"));
}
// 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) {
mParent->Shutdown();
return Err(mozilla::ipc::LaunchError("RSB::DuplicateFromLauncher"));
}
*aProcessHandle = (void**)(ourChildHandle);
return Ok();
}
bool RemoteSandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
bool aIsRemoteLaunch) {
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));
}
void RemoteSandboxBroker::SetSecurityLevelForContentProcess(
int32_t aSandboxLevel, bool aIsFileProcess) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForContentProcess not Implemented");
}
void RemoteSandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForGPUProcess not Implemented");
}
bool RemoteSandboxBroker::SetSecurityLevelForRDDProcess() {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForRDDProcess not Implemented");
}
bool RemoteSandboxBroker::SetSecurityLevelForSocketProcess() {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForSocketProcess not Implemented");
}
bool RemoteSandboxBroker::SetSecurityLevelForUtilityProcess(
mozilla::ipc::SandboxingKind aSandbox) {
MOZ_CRASH(
"RemoteSandboxBroker::SetSecurityLevelForUtilityProcess not Implemented");
}
} // namespace mozilla