Bug 1286865 - Step 1: Gather syscall info from SIGSYS handlers into the parent process. r=gcp
MozReview-Commit-ID: 8GfFo4xso65
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -46,16 +46,20 @@
#if defined(MOZ_SANDBOX)
#include "mozilla/Preferences.h"
#include "mozilla/sandboxing/sandboxLogging.h"
#include "nsDirectoryServiceUtils.h"
#endif
#endif
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+#include "mozilla/SandboxReporter.h"
+#endif
+
#include "nsTArray.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsNativeCharsetUtils.h"
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
using mozilla::MonitorAutoLock;
using mozilla::ipc::GeckoChildProcessHost;
@@ -907,16 +911,25 @@ GeckoChildProcessHost::PerformAsyncLaunc
// "false" == crash reporting disabled
childArgv.push_back("false");
}
# elif defined(MOZ_WIDGET_COCOA)
childArgv.push_back(CrashReporter::GetChildNotificationPipe());
# endif // OS_LINUX
#endif
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ {
+ int srcFd, dstFd;
+ SandboxReporter::Singleton()
+ ->GetClientFileDescriptorMapping(&srcFd, &dstFd);
+ mFileMap.push_back(std::make_pair(srcFd, dstFd));
+ }
+#endif
+
#ifdef MOZ_WIDGET_COCOA
// Add a mach port to the command line so the child can communicate its
// 'task_t' back to the parent.
//
// Put a random number into the channel name, so that a compromised renderer
// can't pretend being the child that's forked off.
std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
base::RandInt(0, std::numeric_limits<int>::max()));
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -8,16 +8,17 @@
#include "LinuxCapabilities.h"
#include "LinuxSched.h"
#include "SandboxBrokerClient.h"
#include "SandboxChroot.h"
#include "SandboxFilter.h"
#include "SandboxInternal.h"
#include "SandboxLogging.h"
+#include "SandboxReporterClient.h"
#include "SandboxUtil.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <pthread.h>
#include <signal.h>
@@ -80,16 +81,17 @@ SandboxCrashFunc gSandboxCrashFunc;
#ifdef MOZ_GMP_SANDBOX
// For media plugins, we can start the sandbox before we dlopen the
// module, so we have to pre-open the file and simulate the sandboxed
// open().
static SandboxOpenedFile gMediaPluginFile;
#endif
+static Maybe<SandboxReporterClient> gSandboxReporterClient;
static UniquePtr<SandboxChroot> gChrootHelper;
static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
// Test whether a ucontext, interpreted as the state after a syscall,
// indicates the given error. See also sandbox::Syscall::PutValueInUcontext.
static bool
ContextIsError(const ucontext_t *aContext, int aError)
{
@@ -132,37 +134,30 @@ SigSysHandler(int nr, siginfo_t *info, v
// which will overwrite one or more registers with the return value.
ucontext_t savedCtx = *ctx;
gChromiumSigSysHandler(nr, info, ctx);
if (!ContextIsError(ctx, ENOSYS)) {
return;
}
- pid_t pid = getpid();
- unsigned long syscall_nr = SECCOMP_SYSCALL(&savedCtx);
- unsigned long args[6];
- args[0] = SECCOMP_PARM1(&savedCtx);
- args[1] = SECCOMP_PARM2(&savedCtx);
- args[2] = SECCOMP_PARM3(&savedCtx);
- args[3] = SECCOMP_PARM4(&savedCtx);
- args[4] = SECCOMP_PARM5(&savedCtx);
- args[5] = SECCOMP_PARM6(&savedCtx);
+ SandboxReport report = gSandboxReporterClient->MakeReportAndSend(&savedCtx);
// TODO, someday when this is enabled on MIPS: include the two extra
// args in the error message.
- SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, syscall %d,"
+ SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, tid %d, syscall %d,"
" args %d %d %d %d %d %d.%s",
- pid, syscall_nr,
- args[0], args[1], args[2], args[3], args[4], args[5],
+ report.mPid, report.mTid, report.mSyscall,
+ report.mArgs[0], report.mArgs[1], report.mArgs[2],
+ report.mArgs[3], report.mArgs[4], report.mArgs[5],
gSandboxCrashOnError ? " Killing process." : "");
if (gSandboxCrashOnError) {
// Bug 1017393: record syscall number somewhere useful.
- info->si_addr = reinterpret_cast<void*>(syscall_nr);
+ info->si_addr = reinterpret_cast<void*>(report.mSyscall);
gSandboxCrashFunc(nr, info, &savedCtx);
_exit(127);
}
}
/**
* This function installs the SIGSYS handler. This is slightly
@@ -459,16 +454,17 @@ ApplySandboxWithTSync(sock_fprog* aFilte
}
}
// Common code for sandbox startup.
static void
SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)
{
MOZ_ASSERT(gSandboxCrashFunc);
+ MOZ_RELEASE_ASSERT(gSandboxReporterClient.isSome());
// Note: PolicyCompiler borrows the policy and registry for its
// lifetime, but does not take ownership of them.
sandbox::bpf_dsl::PolicyCompiler compiler(aPolicy.get(),
sandbox::Trap::Registry());
sandbox::CodeGen::Program program = compiler.Compile();
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
sandbox::bpf_dsl::DumpBPF::PrintProgram(program);
@@ -658,16 +654,18 @@ SetContentProcessSandbox(int aBrokerFd,
{
if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForContent)) {
if (aBrokerFd >= 0) {
close(aBrokerFd);
}
return false;
}
+ gSandboxReporterClient.emplace(SandboxReport::ProcType::CONTENT);
+
// This needs to live until the process exits.
static Maybe<SandboxBrokerClient> sBroker;
if (aBrokerFd >= 0) {
sBroker.emplace(aBrokerFd);
}
SetCurrentProcessSandbox(GetContentSandboxPolicy(sBroker.ptrOr(nullptr),
aSyscallWhitelist));
@@ -689,16 +687,18 @@ SetContentProcessSandbox(int aBrokerFd,
*/
void
SetMediaPluginSandbox(const char *aFilePath)
{
if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia)) {
return;
}
+ gSandboxReporterClient.emplace(SandboxReport::ProcType::MEDIA_PLUGIN);
+
MOZ_ASSERT(!gMediaPluginFile.mPath);
if (aFilePath) {
gMediaPluginFile.mPath = strdup(aFilePath);
gMediaPluginFile.mFd = open(aFilePath, O_RDONLY | O_CLOEXEC);
if (gMediaPluginFile.mFd == -1) {
SANDBOX_LOG_ERROR("failed to open plugin file %s: %s",
aFilePath, strerror(errno));
MOZ_CRASH();
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -164,16 +164,17 @@ public:
virtual ResultExpr EvaluateSyscall(int sysno) const override {
switch (sysno) {
// Timekeeping
case __NR_clock_gettime: {
Arg<clockid_t> clk_id(0);
return If(clk_id == CLOCK_MONOTONIC, Allow())
#ifdef CLOCK_MONOTONIC_COARSE
+ // Used by SandboxReporter, among other things.
.ElseIf(clk_id == CLOCK_MONOTONIC_COARSE, Allow())
#endif
.ElseIf(clk_id == CLOCK_PROCESS_CPUTIME_ID, Allow())
.ElseIf(clk_id == CLOCK_REALTIME, Allow())
#ifdef CLOCK_REALTIME_COARSE
.ElseIf(clk_id == CLOCK_REALTIME_COARSE, Allow())
#endif
.ElseIf(clk_id == CLOCK_THREAD_CPUTIME_ID, Allow())
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxReporterClient.cpp
@@ -0,0 +1,89 @@
+/* -*- 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 "SandboxReporterClient.h"
+#include "SandboxLogging.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/PodOperations.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#ifdef ANDROID
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+#else
+#include <ucontext.h>
+#endif
+
+namespace mozilla {
+
+SandboxReporterClient::SandboxReporterClient(SandboxReport::ProcType aProcType,
+ int aFd)
+ : mProcType(aProcType)
+ , mFd(aFd)
+{
+ // Unfortunately, there isn't a good way to check that the fd is a
+ // socket connected to the right thing without attempting some kind
+ // of in-band handshake. However, the crash reporter (which also
+ // uses a "magic number" fd) doesn't do any kind of checking either,
+ // so it's probably okay to skip it here.
+}
+
+SandboxReport
+SandboxReporterClient::MakeReport(const void* aContext)
+{
+ SandboxReport report;
+ const auto ctx = static_cast<const ucontext_t*>(aContext);
+
+ // Zero the entire struct; some memory safety analyses care about
+ // sending uninitialized alignment padding to another process.
+ PodZero(&report);
+
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &report.mTime);
+ report.mPid = getpid();
+ report.mTid = syscall(__NR_gettid);
+ report.mProcType = mProcType;
+ report.mSyscall = SECCOMP_SYSCALL(ctx);
+ report.mArgs[0] = SECCOMP_PARM1(ctx);
+ report.mArgs[1] = SECCOMP_PARM2(ctx);
+ report.mArgs[2] = SECCOMP_PARM3(ctx);
+ report.mArgs[3] = SECCOMP_PARM4(ctx);
+ report.mArgs[4] = SECCOMP_PARM5(ctx);
+ report.mArgs[5] = SECCOMP_PARM6(ctx);
+ // Named Return Value Optimization allows the compiler to optimize
+ // out the copy here (and the one in MakeReportAndSend).
+ return report;
+}
+
+void
+SandboxReporterClient::SendReport(const SandboxReport& aReport)
+{
+ // The "common" seccomp-bpf policy allows sendmsg but not send(to),
+ // so just use sendmsg even though send would suffice for this.
+ struct iovec iov;
+ struct msghdr msg;
+
+ iov.iov_base = const_cast<void*>(static_cast<const void*>(&aReport));
+ iov.iov_len = sizeof(SandboxReport);
+ PodZero(&msg);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ const auto sent = sendmsg(mFd, &msg, MSG_NOSIGNAL);
+
+ if (sent != sizeof(SandboxReport)) {
+ MOZ_DIAGNOSTIC_ASSERT(sent == -1);
+ SANDBOX_LOG_ERROR("Failed to report rejected syscall: %s",
+ strerror(errno));
+ }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxReporterClient.h
@@ -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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SandboxReporterClient_h
+#define mozilla_SandboxReporterClient_h
+
+#include "reporter/SandboxReporterCommon.h"
+
+namespace mozilla {
+
+// This class is instantiated in child processes in Sandbox.cpp to
+// send reports from the SIGSYS handler to the SandboxReporter
+// instance in the parent.
+class SandboxReporterClient {
+public:
+ // Note: this does not take ownership of the file descriptor; if
+ // it's not kSandboxReporterFileDesc (e.g., for unit testing), the
+ // caller will need to close it to avoid leaks.
+ explicit SandboxReporterClient(SandboxReport::ProcType aProcType,
+ int aFd = kSandboxReporterFileDesc);
+
+ // Constructs a report from a signal context (the ucontext_t* passed
+ // as void* to an sa_sigaction handler); uses the caller's pid and tid.
+ SandboxReport MakeReport(const void* aContext);
+
+ void SendReport(const SandboxReport& aReport);
+
+ SandboxReport MakeReportAndSend(const void* aContext) {
+ SandboxReport report = MakeReport(aContext);
+ SendReport(report);
+ return report;
+ }
+private:
+ SandboxReport::ProcType mProcType;
+ int mFd;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_SandboxReporterClient_h
--- a/security/sandbox/linux/moz.build
+++ b/security/sandbox/linux/moz.build
@@ -62,16 +62,17 @@ SOURCES += [
'Sandbox.cpp',
'SandboxBrokerClient.cpp',
'SandboxChroot.cpp',
'SandboxFilter.cpp',
'SandboxFilterUtil.cpp',
'SandboxHooks.cpp',
'SandboxInfo.cpp',
'SandboxLogging.cpp',
+ 'SandboxReporterClient.cpp',
'SandboxUtil.cpp',
]
# This copy of SafeSPrintf doesn't need to avoid the Chromium logging
# dependency like the one in libxul does, but this way the behavior is
# consistent. See also the comment in SandboxLogging.h.
SOURCES['../chromium/base/strings/safe_sprintf.cc'].flags += ['-DNDEBUG']
@@ -104,13 +105,14 @@ if CONFIG['OS_TARGET'] != 'Android':
# Needed for clock_gettime with glibc < 2.17:
OS_LIBS += [
'rt',
]
DIRS += [
'broker',
'glue',
+ 'reporter',
]
TEST_DIRS += [
'gtest',
]
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporter.cpp
@@ -0,0 +1,177 @@
+/* -*- 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 "SandboxReporter.h"
+#include "SandboxLogging.h"
+
+#include <algorithm>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/PodOperations.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+StaticAutoPtr<SandboxReporter> SandboxReporter::sSingleton;
+
+SandboxReporter::SandboxReporter()
+ : mClientFd(-1)
+ , mServerFd(-1)
+ , mMutex("SandboxReporter")
+ , mBuffer(MakeUnique<SandboxReport[]>(kSandboxReporterBufferSize))
+ , mCount(0)
+{
+}
+
+bool
+SandboxReporter::Init()
+{
+ int fds[2];
+
+ if (0 != socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)) {
+ SANDBOX_LOG_ERROR("SandboxReporter: socketpair failed: %s",
+ strerror(errno));
+ return false;
+ }
+ mClientFd = fds[0];
+ mServerFd = fds[1];
+
+ if (!PlatformThread::Create(0, this, &mThread)) {
+ SANDBOX_LOG_ERROR("SandboxReporter: thread creation failed: %s",
+ strerror(errno));
+ close(mClientFd);
+ close(mServerFd);
+ mClientFd = mServerFd = -1;
+ return false;
+ }
+
+ return true;
+}
+
+SandboxReporter::~SandboxReporter()
+{
+ if (mServerFd < 0) {
+ return;
+ }
+ shutdown(mServerFd, SHUT_RD);
+ PlatformThread::Join(mThread);
+ close(mServerFd);
+ close(mClientFd);
+}
+
+/* static */ SandboxReporter*
+SandboxReporter::Singleton()
+{
+ static StaticMutex sMutex;
+ StaticMutexAutoLock lock(sMutex);
+
+ if (sSingleton == nullptr) {
+ sSingleton = new SandboxReporter();
+ if (!sSingleton->Init()) {
+ // If socketpair or thread creation failed, trying to continue
+ // with child process creation is unlikely to succeed; crash
+ // instead of trying to handle that case.
+ MOZ_CRASH("SandboxRepoter::Singleton: initialization failed");
+ }
+ // ClearOnShutdown must be called on the main thread and will
+ // destroy the object on the main thread. That *should* be safe;
+ // the destructor will shut down the reporter's socket reader
+ // thread before freeing anything, IPC should already be shut down
+ // by that point (so it won't race by calling Singleton()), all
+ // non-main XPCOM threads will also be shut down, and currently
+ // the only other user is the main-thread-only Troubleshoot.jsm.
+ NS_DispatchToMainThread(NS_NewRunnableFunction([] {
+ ClearOnShutdown(&sSingleton);
+ }));
+ }
+ return sSingleton.get();
+}
+
+void
+SandboxReporter::GetClientFileDescriptorMapping(int* aSrcFd, int* aDstFd) const
+{
+ MOZ_ASSERT(mClientFd >= 0);
+ *aSrcFd = mClientFd;
+ *aDstFd = kSandboxReporterFileDesc;
+}
+
+void
+SandboxReporter::AddOne(const SandboxReport& aReport)
+{
+ // TODO: send a copy to Telemetry
+ MutexAutoLock lock(mMutex);
+ mBuffer[mCount % kSandboxReporterBufferSize] = aReport;
+ ++mCount;
+}
+
+void
+SandboxReporter::ThreadMain(void)
+{
+ for (;;) {
+ SandboxReport rep;
+ struct iovec iov;
+ struct msghdr msg;
+
+ iov.iov_base = &rep;
+ iov.iov_len = sizeof(rep);
+ PodZero(&msg);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ const auto recvd = recvmsg(mServerFd, &msg, 0);
+ if (recvd < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ SANDBOX_LOG_ERROR("SandboxReporter: recvmsg: %s", strerror(errno));
+ }
+ if (recvd <= 0) {
+ break;
+ }
+
+ if (static_cast<size_t>(recvd) < sizeof(rep)) {
+ SANDBOX_LOG_ERROR("SandboxReporter: packet too short (%d < %d)",
+ recvd, sizeof(rep));
+ continue;
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ SANDBOX_LOG_ERROR("SandboxReporter: packet too long");
+ continue;
+ }
+
+ AddOne(rep);
+ }
+}
+
+SandboxReporter::Snapshot
+SandboxReporter::GetSnapshot()
+{
+ Snapshot snapshot;
+ MutexAutoLock lock(mMutex);
+
+ const uint64_t bufSize = static_cast<uint64_t>(kSandboxReporterBufferSize);
+ const uint64_t start = std::max(mCount, bufSize) - bufSize;
+ snapshot.mOffset = start;
+ snapshot.mReports.Clear();
+ snapshot.mReports.SetCapacity(mCount - start);
+ for (size_t i = start; i < mCount; ++i) {
+ const SandboxReport* rep = &mBuffer[i % kSandboxReporterBufferSize];
+ MOZ_ASSERT(rep->IsValid());
+ snapshot.mReports.AppendElement(*rep);
+ }
+ // Named Return Value Optimization would apply here, but C++11
+ // doesn't require it; so, instead of possibly copying the entire
+ // array contents, invoke the move constructor and copy at most a
+ // few words.
+ return Move(snapshot);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporter.h
@@ -0,0 +1,87 @@
+/* -*- 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/. */
+
+#ifndef mozilla_SandboxReporter_h
+#define mozilla_SandboxReporter_h
+
+#include "SandboxReporterCommon.h"
+
+#include "base/platform_thread.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/Types.h"
+#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+
+// This object collects the SandboxReport messages from all of the
+// child processes, submits them to Telemetry, and maintains a ring
+// buffer of the last kSandboxReporterBufferSize reports.
+class SandboxReporter final
+ : public PlatformThread::Delegate
+{
+public:
+ // For normal use, don't construct this directly; use the
+ // Singleton() method.
+ //
+ // For unit testing, use this constructor followed by the Init
+ // method; the object isn't usable unless Init returns true.
+ explicit SandboxReporter();
+ ~SandboxReporter();
+
+ // See above; this method is not thread-safe.
+ bool Init();
+
+ // Used in GeckoChildProcessHost to connect the child process's
+ // client to this report collector.
+ void GetClientFileDescriptorMapping(int* aSrcFd, int* aDstFd) const;
+
+ // A snapshot of the report ring buffer; element 0 of `mReports` is
+ // the `mOffset`th report to be received, and so on.
+ struct Snapshot {
+ // The buffer has to fit in memory, but the total number of
+ // reports received in the session can increase without bound and
+ // could potentially overflow a uint32_t, so this is 64-bit.
+ // (It's exposed to JS as a 53-bit int, effectively, but that
+ // should also be large enough.)
+ uint64_t mOffset;
+ nsTArray<SandboxReport> mReports;
+ };
+
+ // Read the ring buffer contents; this method is thread-safe.
+ Snapshot GetSnapshot();
+
+ // Gets or creates the singleton report collector. Crashes if
+ // initialization fails (if a socketpair and/or thread can't be
+ // created, there was almost certainly about to be a crash anyway).
+ // Thread-safe as long as the pointer isn't used during/after XPCOM
+ // shutdown.
+ static SandboxReporter* Singleton();
+private:
+ // These are constant over the life of the object:
+ int mClientFd;
+ int mServerFd;
+ PlatformThreadHandle mThread;
+
+ Mutex mMutex;
+ // These are protected by mMutex:
+ UniquePtr<SandboxReport[]> mBuffer;
+ uint64_t mCount;
+
+ static StaticAutoPtr<SandboxReporter> sSingleton;
+
+ void ThreadMain(void) override;
+ void AddOne(const SandboxReport& aReport);
+};
+
+// This is a constant so the % operations can be optimized. This is
+// exposed in the header so that unit tests can see it.
+static const size_t kSandboxReporterBufferSize = 32;
+
+} // namespace mozilla
+
+#endif // mozilla_SandboxReporter_h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporterCommon.h
@@ -0,0 +1,62 @@
+/* -*- 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/. */
+
+#ifndef mozilla_SandboxReporterCommon_h
+#define mozilla_SandboxReporterCommon_h
+
+#include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/Types.h"
+
+#include <sys/types.h>
+
+// Note: this is also used in libmozsandbox, so dependencies on
+// symbols from libxul probably won't work.
+
+namespace mozilla {
+static const size_t kSandboxSyscallArguments = 6;
+// fds 0-2: stdio; fd 3: IPC; fd 4: crash reporter. (The IPC child
+// process launching code will check that we don't try to use the same
+// fd twice.)
+static const int kSandboxReporterFileDesc = 5;
+
+// This struct represents a system call that was rejected by a
+// seccomp-bpf policy.
+struct SandboxReport {
+ // In the future this may include finer distinctions than
+ // GeckoProcessType -- e.g., whether a content process can load
+ // file:/// URLs, or if it's reserved for content with certain
+ // user-granted permissions.
+ enum class ProcType : uint8_t {
+ CONTENT,
+ MEDIA_PLUGIN,
+ };
+
+ // The syscall number and arguments are usually `unsigned long`, but
+ // that causes ambiguous overload errors with nsACString::AppendInt.
+ using ULong = UnsignedStdintTypeForSize<sizeof(unsigned long)>::Type;
+
+ // This time uses CLOCK_MONOTONIC_COARSE. Displaying or reporting
+ // it should usually be done relative to the current value of that
+ // clock (or the time at some other event of interest, like a
+ // subsequent crash).
+ struct timespec mTime;
+
+ // The pid/tid values, like every other field in this struct, aren't
+ // authenticated and a compromised process could send anything, so
+ // use the values with caution.
+ pid_t mPid;
+ pid_t mTid;
+ ProcType mProcType;
+ ULong mSyscall;
+ ULong mArgs[kSandboxSyscallArguments];
+
+ SandboxReport() : mPid(0) { }
+ bool IsValid() const { return mPid > 0; }
+};
+
+} // namespace mozilla
+
+#endif // mozilla_SandboxReporterCommon_h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/reporter/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; python-indent: 4; 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/.
+
+EXPORTS.mozilla += [
+ 'SandboxReporter.h',
+ 'SandboxReporterCommon.h',
+]
+
+SOURCES += [
+ 'SandboxReporter.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/security/sandbox/linux', # SandboxLogging.h
+]
+
+# Need this for base::PlatformThread
+include('/ipc/chromium/chromium-config.mozbuild')
+
+# Need this for safe_sprintf.h used by SandboxLogging.h,
+# but it has to be after ipc/chromium/src.
+LOCAL_INCLUDES += [
+ '/security/sandbox/chromium',
+]
+
+FINAL_LIBRARY = 'xul'