Bug 1126437 - Reorganize content sandbox params extracted from libxul APIs. r=gcp
The end goal is to allow the seccomp-bpf policy to vary based on the
content sandbox level.
Rather than add yet another parameter to SetContentProcessSandbox to
pass down the sandbox level, this collects the values that have to be
computed in libxul into a struct, and moves the code that computes it so
it's not cluttering up ContentChild.
MozReview-Commit-ID: L0dyQwHQKhc
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1661,49 +1661,24 @@ StartMacOSContentSandbox()
mozilla::ipc::IPCResult
ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker)
{
// We may want to move the sandbox initialization somewhere else
// at some point; see bug 880808.
#if defined(MOZ_CONTENT_SANDBOX)
bool sandboxEnabled = true;
#if defined(XP_LINUX)
- // Otherwise, sandboxing is best-effort.
+ // On Linux, we have to support systems that can't use any sandboxing.
if (!SandboxInfo::Get().CanSandboxContent()) {
sandboxEnabled = false;
}
if (sandboxEnabled) {
- int brokerFd = -1;
- if (aBroker.type() == MaybeFileDesc::TFileDescriptor) {
- auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle();
- brokerFd = fd.release();
- // brokerFd < 0 means to allow direct filesystem access, so
- // make absolutely sure that doesn't happen if the parent
- // didn't intend it.
- MOZ_RELEASE_ASSERT(brokerFd >= 0);
- }
- // Allow user overrides of seccomp-bpf syscall filtering
- std::vector<int> syscallWhitelist;
- nsAutoCString extraSyscalls;
- nsresult rv =
- Preferences::GetCString("security.sandbox.content.syscall_whitelist",
- extraSyscalls);
- if (NS_SUCCEEDED(rv)) {
- for (const nsACString& callNrString : extraSyscalls.Split(',')) {
- int callNr = PromiseFlatCString(callNrString).ToInteger(&rv);
- if (NS_SUCCEEDED(rv)) {
- syscallWhitelist.push_back(callNr);
- }
- }
- }
- ContentChild* cc = ContentChild::GetSingleton();
- bool isFileProcess = cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE);
- sandboxEnabled = SetContentProcessSandbox(brokerFd, isFileProcess,
- syscallWhitelist);
+ sandboxEnabled =
+ SetContentProcessSandbox(ContentProcessSandboxParams::ForThisProcess(aBroker));
}
#elif defined(XP_WIN)
mozilla::SandboxTarget::Instance()->StartSandbox();
#elif defined(XP_MACOSX)
sandboxEnabled = StartMacOSContentSandbox();
#endif
CrashReporter::AnnotateCrashReport(
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -592,39 +592,40 @@ SetCurrentProcessSandbox(UniquePtr<sandb
#ifdef MOZ_CONTENT_SANDBOX
/**
* Starts the seccomp sandbox for a content process. Should be called
* only once, and before any potentially harmful content is loaded.
*
* Will normally make the process exit on failure.
*/
bool
-SetContentProcessSandbox(int aBrokerFd, bool aFileProcess,
- std::vector<int>& aSyscallWhitelist)
+SetContentProcessSandbox(ContentProcessSandboxParams&& aParams)
{
+ int brokerFd = aParams.mBrokerFd;
+ aParams.mBrokerFd = -1;
+
if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForContent)) {
- if (aBrokerFd >= 0) {
- close(aBrokerFd);
+ if (brokerFd >= 0) {
+ close(brokerFd);
}
return false;
}
- auto procType = aFileProcess
+ auto procType = aParams.mFileProcess
? SandboxReport::ProcType::FILE
: SandboxReport::ProcType::CONTENT;
gSandboxReporterClient = new SandboxReporterClient(procType);
// This needs to live until the process exits.
static SandboxBrokerClient* sBroker;
- if (aBrokerFd >= 0) {
- sBroker = new SandboxBrokerClient(aBrokerFd);
+ if (brokerFd >= 0) {
+ sBroker = new SandboxBrokerClient(brokerFd);
}
- SetCurrentProcessSandbox(GetContentSandboxPolicy(sBroker,
- aSyscallWhitelist));
+ SetCurrentProcessSandbox(GetContentSandboxPolicy(sBroker, Move(aParams)));
return true;
}
#endif // MOZ_CONTENT_SANDBOX
#ifdef MOZ_GMP_SANDBOX
/**
* Starts the seccomp sandbox for a media plugin process. Should be
* called only once, and before any potentially harmful content is
--- a/security/sandbox/linux/Sandbox.h
+++ b/security/sandbox/linux/Sandbox.h
@@ -12,29 +12,51 @@
#include <vector>
// This defines the entry points for a content process to start
// sandboxing itself. See also SandboxInfo.h for what parts of
// sandboxing are enabled/supported.
namespace mozilla {
+namespace dom {
+class MaybeFileDesc;
+} // namespace dom
+
// This must be called early, before glib creates any worker threads.
// (See bug 1176099.)
MOZ_EXPORT void SandboxEarlyInit();
#ifdef MOZ_CONTENT_SANDBOX
+// A collection of sandbox parameters that have to be extracted from
+// prefs or other libxul facilities and passed down, because
+// libmozsandbox can't link against the APIs to read them.
+struct ContentProcessSandboxParams {
+ // Content sandbox level; see also GetEffectiveSandboxLevel in
+ // SandboxSettings.h and the comments for the Linux version of
+ // "security.sandbox.content.level" in browser/app/profile/firefox.js
+ int mLevel = 0;
+ // The filesystem broker client file descriptor, or -1 to allow
+ // direct filesystem access. (Warning: this is not a RAII class and
+ // will not close the fd on destruction.)
+ int mBrokerFd = -1;
+ // Determines whether we allow reading all files, for processes that
+ // render file:/// URLs.
+ bool mFileProcess = false;
+ // Syscall numbers to allow even if the seccomp-bpf policy otherwise
+ // wouldn't.
+ std::vector<int> mSyscallWhitelist;
+
+ static ContentProcessSandboxParams ForThisProcess(const dom::MaybeFileDesc& aBroker);
+};
+
// Call only if SandboxInfo::CanSandboxContent() returns true.
// (No-op if the sandbox is disabled.)
-// aBrokerFd is the filesystem broker client file descriptor,
-// or -1 to allow direct filesystem access.
// isFileProcess determines whether we allow system wide file reads.
-MOZ_EXPORT bool SetContentProcessSandbox(int aBrokerFd,
- bool aFileProcess,
- std::vector<int>& aSyscallWhitelist);
+MOZ_EXPORT bool SetContentProcessSandbox(ContentProcessSandboxParams&& aParams);
#endif
#ifdef MOZ_GMP_SANDBOX
// Call only if SandboxInfo::CanSandboxMedia() returns true.
// (No-op if MOZ_DISABLE_GMP_SANDBOX is set.)
// aFilePath is the path to the plugin file.
MOZ_EXPORT void SetMediaPluginSandbox(const char *aFilePath);
#endif
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -2,16 +2,17 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#include "SandboxFilter.h"
#include "SandboxFilterUtil.h"
+#include "Sandbox.h" // for ContentProcessSandboxParams
#include "SandboxBrokerClient.h"
#include "SandboxInfo.h"
#include "SandboxInternal.h"
#include "SandboxLogging.h"
#ifdef MOZ_GMP_SANDBOX
#include "SandboxOpenedFiles.h"
#endif
#include "mozilla/PodOperations.h"
@@ -368,17 +369,17 @@ public:
// The seccomp-bpf filter for content processes is not a true sandbox
// on its own; its purpose is attack surface reduction and syscall
// interception in support of a semantic sandboxing layer. On B2G
// this is the Android process permission model; on desktop,
// namespaces and chroot() will be used.
class ContentSandboxPolicy : public SandboxPolicyCommon {
private:
SandboxBrokerClient* mBroker;
- std::vector<int> mSyscallWhitelist;
+ ContentProcessSandboxParams mParams;
// Trap handlers for filesystem brokering.
// (The amount of code duplication here could be improved....)
#ifdef __NR_open
static intptr_t OpenTrap(ArgsRef aArgs, void* aux) {
auto broker = static_cast<SandboxBrokerClient*>(aux);
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
auto flags = static_cast<int>(aArgs.args[1]);
@@ -573,21 +574,24 @@ private:
rv = -ENOSYS;
}
close(fd);
return rv;
}
public:
- explicit ContentSandboxPolicy(SandboxBrokerClient* aBroker,
- const std::vector<int>& aSyscallWhitelist)
- : mBroker(aBroker),
- mSyscallWhitelist(aSyscallWhitelist) {}
+ ContentSandboxPolicy(SandboxBrokerClient* aBroker,
+ ContentProcessSandboxParams&& aParams)
+ : mBroker(aBroker)
+ , mParams(Move(aParams))
+ { }
+
~ContentSandboxPolicy() override = default;
+
Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
switch(aCall) {
case SYS_RECVFROM:
case SYS_SENDTO:
case SYS_SENDMMSG: // libresolv via libasyncns; see bug 1355274
return Some(Allow());
case SYS_SOCKETPAIR: {
@@ -653,18 +657,19 @@ public:
Arg<int> op(0);
return If(op == PR_GET_NAME, Allow())
.Else(SandboxPolicyCommon::PrctlPolicy());
}
#endif
ResultExpr EvaluateSyscall(int sysno) const override {
// Straight allow for anything that got overriden via prefs
- if (std::find(mSyscallWhitelist.begin(), mSyscallWhitelist.end(), sysno)
- != mSyscallWhitelist.end()) {
+ const auto& whitelist = mParams.mSyscallWhitelist;
+ if (std::find(whitelist.begin(), whitelist.end(), sysno)
+ != whitelist.end()) {
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
SANDBOX_LOG_ERROR("Allowing syscall nr %d via whitelist", sysno);
}
return Allow();
}
if (mBroker) {
// Have broker; route the appropriate syscalls to it.
switch (sysno) {
@@ -998,19 +1003,19 @@ public:
default:
return SandboxPolicyCommon::EvaluateSyscall(sysno);
}
}
};
UniquePtr<sandbox::bpf_dsl::Policy>
GetContentSandboxPolicy(SandboxBrokerClient* aMaybeBroker,
- const std::vector<int>& aSyscallWhitelist)
+ ContentProcessSandboxParams&& aParams)
{
- return MakeUnique<ContentSandboxPolicy>(aMaybeBroker, aSyscallWhitelist);
+ return MakeUnique<ContentSandboxPolicy>(aMaybeBroker, Move(aParams));
}
#endif // MOZ_CONTENT_SANDBOX
#ifdef MOZ_GMP_SANDBOX
// Unlike for content, the GeckoMediaPlugin seccomp-bpf policy needs
// to be an effective sandbox by itself, because we allow GMP on Linux
// systems where that's the only sandboxing mechanism we can use.
--- a/security/sandbox/linux/SandboxFilter.h
+++ b/security/sandbox/linux/SandboxFilter.h
@@ -17,19 +17,20 @@ namespace bpf_dsl {
class Policy;
}
}
namespace mozilla {
#ifdef MOZ_CONTENT_SANDBOX
class SandboxBrokerClient;
+struct ContentProcessSandboxParams;
UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy(SandboxBrokerClient* aMaybeBroker,
- const std::vector<int>& aSyscallWhitelist);
+ ContentProcessSandboxParams&& aParams);
#endif
#ifdef MOZ_GMP_SANDBOX
class SandboxOpenedFiles;
// The SandboxOpenedFiles object must live until the process exits.
UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(const SandboxOpenedFiles* aFiles);
#endif
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/glue/SandboxPrefBridge.cpp
@@ -0,0 +1,51 @@
+/* -*- 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 http://mozilla.org/MPL/2.0/. */
+
+#include "Sandbox.h"
+
+#include "mozilla/Preferences.h"
+#include "mozilla/SandboxSettings.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h" // for FILE_REMOTE_TYPE
+
+namespace mozilla {
+
+/* static */ ContentProcessSandboxParams
+ContentProcessSandboxParams::ForThisProcess(const dom::MaybeFileDesc& aBroker)
+{
+ ContentProcessSandboxParams params;
+ params.mLevel = GetEffectiveContentSandboxLevel();
+
+ if (aBroker.type() == dom::MaybeFileDesc::TFileDescriptor) {
+ auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle();
+ params.mBrokerFd = fd.release();
+ // brokerFd < 0 means to allow direct filesystem access, so
+ // make absolutely sure that doesn't happen if the parent
+ // didn't intend it.
+ MOZ_RELEASE_ASSERT(params.mBrokerFd >= 0);
+ }
+ // (Otherwise, mBrokerFd will remain -1 from the default ctor.)
+
+ auto* cc = dom::ContentChild::GetSingleton();
+ params.mFileProcess = cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE);
+
+ nsAutoCString extraSyscalls;
+ nsresult rv =
+ Preferences::GetCString("security.sandbox.content.syscall_whitelist",
+ extraSyscalls);
+ if (NS_SUCCEEDED(rv)) {
+ for (const nsACString& callNrString : extraSyscalls.Split(',')) {
+ int callNr = PromiseFlatCString(callNrString).ToInteger(&rv);
+ if (NS_SUCCEEDED(rv)) {
+ params.mSyscallWhitelist.push_back(callNr);
+ }
+ }
+ }
+
+ return params;
+}
+
+} // namespace mozilla
--- a/security/sandbox/linux/glue/moz.build
+++ b/security/sandbox/linux/glue/moz.build
@@ -3,23 +3,29 @@
# 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 += [
'../../chromium/base/strings/safe_sprintf.cc',
'../SandboxLogging.cpp',
'SandboxCrash.cpp',
+ 'SandboxPrefBridge.cpp',
]
# Avoid Chromium logging dependency, because this is going into
# libxul. See also the comment in SandboxLogging.h.
SOURCES['../../chromium/base/strings/safe_sprintf.cc'].flags += ['-DNDEBUG']
+# Need this for mozilla::ipc::FileDescriptor etc.
+include('/ipc/chromium/chromium-config.mozbuild')
+
LOCAL_INCLUDES += [
+ # Need this for safe_sprintf.h used by SandboxLogging.h,
+ # but it has to be after ipc/chromium/src.
'/security/sandbox/chromium',
'/security/sandbox/linux',
]
USE_LIBS += [
'mozsandbox',
]