summaryrefslogtreecommitdiffstats
path: root/security/sandbox/linux/reporter
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /security/sandbox/linux/reporter
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--security/sandbox/linux/reporter/SandboxReporter.cpp299
-rw-r--r--security/sandbox/linux/reporter/SandboxReporter.h86
-rw-r--r--security/sandbox/linux/reporter/SandboxReporterCommon.h66
-rw-r--r--security/sandbox/linux/reporter/SandboxReporterWrappers.cpp199
-rw-r--r--security/sandbox/linux/reporter/components.conf13
-rw-r--r--security/sandbox/linux/reporter/moz.build36
6 files changed, 699 insertions, 0 deletions
diff --git a/security/sandbox/linux/reporter/SandboxReporter.cpp b/security/sandbox/linux/reporter/SandboxReporter.cpp
new file mode 100644
index 0000000000..a7c71cd5c9
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporter.cpp
@@ -0,0 +1,299 @@
+/* -*- 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 <time.h> // for clockid_t
+
+#include "GeckoProfiler.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/PodOperations.h"
+#include "nsThreadUtils.h"
+#include "mozilla/Telemetry.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+// Distinguish architectures for the telemetry key.
+#if defined(__i386__)
+# define SANDBOX_ARCH_NAME "x86"
+#elif defined(__x86_64__)
+# define SANDBOX_ARCH_NAME "amd64"
+#elif defined(__arm__)
+# define SANDBOX_ARCH_NAME "arm"
+#elif defined(__aarch64__)
+# define SANDBOX_ARCH_NAME "arm64"
+#else
+# error "unrecognized architecture"
+#endif
+
+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 | SOCK_CLOEXEC, 0, fds)) {
+ SANDBOX_LOG_ERRNO("SandboxReporter: socketpair failed");
+ return false;
+ }
+ mClientFd = fds[0];
+ mServerFd = fds[1];
+
+ if (!PlatformThread::Create(0, this, &mThread)) {
+ SANDBOX_LOG_ERRNO("SandboxReporter: thread creation failed");
+ 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 MOZ_UNANNOTATED;
+ 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.sys.mjs.
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ "SandboxReporter::Singleton", [] { ClearOnShutdown(&sSingleton); }));
+ }
+ return sSingleton.get();
+}
+
+void SandboxReporter::GetClientFileDescriptorMapping(int* aSrcFd,
+ int* aDstFd) const {
+ MOZ_ASSERT(mClientFd >= 0);
+ *aSrcFd = mClientFd;
+ *aDstFd = kSandboxReporterFileDesc;
+}
+
+// This function is mentioned in Histograms.json; keep that in mind if
+// it's renamed or moved to a different file.
+static void SubmitToTelemetry(const SandboxReport& aReport) {
+ nsAutoCString key;
+ // The key contains the process type, something that uniquely
+ // identifies the syscall, and in some cases arguments (see below
+ // for details). Arbitrary formatting choice: fields in the key are
+ // separated by ':', except that (arch, syscall#) pairs are
+ // separated by '/'.
+ //
+ // Examples:
+ // * "content:x86/64" (bug 1285768)
+ // * "content:x86_64/110" (bug 1285768)
+ // * "gmp:madvise:8" (bug 1303813)
+ // * "content:clock_gettime:4" (bug 1334687)
+
+ switch (aReport.mProcType) {
+ 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::RDD:
+ key.AppendLiteral("rdd");
+ break;
+ case SandboxReport::ProcType::SOCKET_PROCESS:
+ key.AppendLiteral("socket");
+ break;
+ case SandboxReport::ProcType::UTILITY:
+ key.AppendLiteral("utility");
+ break;
+ default:
+ MOZ_ASSERT(false);
+ }
+ key.Append(':');
+
+ switch (aReport.mSyscall) {
+ // Syscalls that are filtered by arguments in one or more of the
+ // policies in SandboxFilter.cpp should generally have those
+ // arguments included here, but don't include irrelevant
+ // information that would cause large numbers of distinct keys for
+ // the same issue -- for example, pids or pointers. When in
+ // doubt, include arguments only if they would typically be
+ // constants (or asm immediates) in the code making the syscall.
+ //
+ // Also, keep in mind that this is opt-out data collection and
+ // privacy is critical. While it's unlikely that information in
+ // the register values alone could personally identify a user
+ // (see also crash reports, where register contents are public),
+ // and the guidelines in the previous paragraph should rule out
+ // any value that's capable of holding PII, please be careful.
+ //
+ // When making changes here, please consult with a data steward
+ // (https://wiki.mozilla.org/Firefox/Data_Collection) and ask for
+ // a review if you are unsure about anything.
+
+ // This macro includes one argument as a decimal number; it should
+ // be enough for most cases.
+#define ARG_DECIMAL(name, idx) \
+ case __NR_##name: \
+ key.AppendLiteral(#name ":"); \
+ key.AppendInt(aReport.mArgs[idx]); \
+ break
+
+ // This may be more convenient if the argument is a set of bit flags.
+#define ARG_HEX(name, idx) \
+ case __NR_##name: \
+ key.AppendLiteral(#name ":0x"); \
+ key.AppendInt(aReport.mArgs[idx], 16); \
+ break
+
+ // clockid_t is annoying: there are a small set of fixed timers,
+ // but it can also encode a pid/tid (or a fd for a hardware clock
+ // device); in this case the value is negative.
+#define ARG_CLOCKID(name, idx) \
+ case __NR_##name: \
+ key.AppendLiteral(#name ":"); \
+ if (static_cast<clockid_t>(aReport.mArgs[idx]) < 0) { \
+ key.AppendLiteral("dynamic"); \
+ } else { \
+ key.AppendInt(aReport.mArgs[idx]); \
+ } \
+ break
+
+ // The syscalls handled specially:
+
+ ARG_HEX(clone, 0); // flags
+ ARG_DECIMAL(prctl, 0); // option
+ ARG_HEX(ioctl, 1); // request
+ ARG_DECIMAL(fcntl, 1); // cmd
+ ARG_DECIMAL(madvise, 2); // advice
+ ARG_CLOCKID(clock_gettime, 0); // clk_id
+
+#ifdef __NR_socketcall
+ ARG_DECIMAL(socketcall, 0); // call
+#endif
+#ifdef __NR_ipc
+ ARG_DECIMAL(ipc, 0); // call
+#endif
+
+#undef ARG_DECIMAL
+#undef ARG_HEX
+#undef ARG_CLOCKID
+
+ default:
+ // Otherwise just use the number, with the arch name to disambiguate.
+ key.Append(SANDBOX_ARCH_NAME "/");
+ key.AppendInt(aReport.mSyscall);
+ }
+
+ Telemetry::Accumulate(Telemetry::SANDBOX_REJECTED_SYSCALLS, key);
+}
+
+void SandboxReporter::AddOne(const SandboxReport& aReport) {
+ SubmitToTelemetry(aReport);
+
+ MutexAutoLock lock(mMutex);
+ mBuffer[mCount % kSandboxReporterBufferSize] = aReport;
+ ++mCount;
+}
+
+void SandboxReporter::ThreadMain(void) {
+ // Create a nsThread wrapper for the current platform thread, and register it
+ // with the thread manager.
+ (void)NS_GetCurrentThread();
+
+ PlatformThread::SetName("SandboxReporter");
+ AUTO_PROFILER_REGISTER_THREAD("SandboxReporter");
+
+ 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_ERRNO("SandboxReporter: recvmsg");
+ }
+ if (recvd <= 0) {
+ break;
+ }
+
+ if (static_cast<size_t>(recvd) < sizeof(rep)) {
+ SANDBOX_LOG("SandboxReporter: packet too short (%d < %d)", recvd,
+ sizeof(rep));
+ continue;
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ SANDBOX_LOG("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);
+ }
+ return snapshot;
+}
+
+} // namespace mozilla
diff --git a/security/sandbox/linux/reporter/SandboxReporter.h b/security/sandbox/linux/reporter/SandboxReporter.h
new file mode 100644
index 0000000000..0969111c9c
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporter.h
@@ -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 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 MOZ_UNANNOTATED;
+ // 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
diff --git a/security/sandbox/linux/reporter/SandboxReporterCommon.h b/security/sandbox/linux/reporter/SandboxReporterCommon.h
new file mode 100644
index 0000000000..9bfb40bb98
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporterCommon.h
@@ -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 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,
+ FILE,
+ MEDIA_PLUGIN,
+ RDD,
+ SOCKET_PROCESS,
+ UTILITY,
+ };
+
+ // 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
diff --git a/security/sandbox/linux/reporter/SandboxReporterWrappers.cpp b/security/sandbox/linux/reporter/SandboxReporterWrappers.cpp
new file mode 100644
index 0000000000..755e8e858d
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporterWrappers.cpp
@@ -0,0 +1,199 @@
+/* -*- 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 "mozISandboxReporter.h"
+#include "SandboxReporter.h"
+
+#include <time.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Components.h"
+#include "nsCOMPtr.h"
+#include "nsPrintfCString.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
+
+using namespace mozilla;
+
+namespace mozilla {
+
+class SandboxReportWrapper final : public mozISandboxReport {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_MOZISANDBOXREPORT
+
+ explicit SandboxReportWrapper(const SandboxReport& aReport)
+ : mReport(aReport) {}
+
+ private:
+ ~SandboxReportWrapper() = default;
+ SandboxReport mReport;
+};
+
+NS_IMPL_ISUPPORTS(SandboxReportWrapper, mozISandboxReport)
+
+/* readonly attribute uint64_t msecAgo; */
+NS_IMETHODIMP SandboxReportWrapper::GetMsecAgo(uint64_t* aMsec) {
+ struct timespec then = mReport.mTime, now = {0, 0};
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+
+ const uint64_t now_msec = uint64_t(now.tv_sec) * 1000 + now.tv_nsec / 1000000;
+ const uint64_t then_msec =
+ uint64_t(then.tv_sec) * 1000 + then.tv_nsec / 1000000;
+ MOZ_DIAGNOSTIC_ASSERT(now_msec >= then_msec);
+ if (now_msec >= then_msec) {
+ *aMsec = now_msec - then_msec;
+ } else {
+ *aMsec = 0;
+ }
+ return NS_OK;
+}
+
+/* readonly attribute int32_t pid; */
+NS_IMETHODIMP SandboxReportWrapper::GetPid(int32_t* aPid) {
+ *aPid = mReport.mPid;
+ return NS_OK;
+}
+
+/* readonly attribute int32_t tid; */
+NS_IMETHODIMP SandboxReportWrapper::GetTid(int32_t* aTid) {
+ *aTid = mReport.mTid;
+ return NS_OK;
+}
+
+/* readonly attribute ACString procType; */
+NS_IMETHODIMP SandboxReportWrapper::GetProcType(nsACString& aProcType) {
+ switch (mReport.mProcType) {
+ case SandboxReport::ProcType::CONTENT:
+ aProcType.AssignLiteral("content");
+ return NS_OK;
+ case SandboxReport::ProcType::FILE:
+ aProcType.AssignLiteral("file");
+ return NS_OK;
+ case SandboxReport::ProcType::MEDIA_PLUGIN:
+ aProcType.AssignLiteral("mediaPlugin");
+ return NS_OK;
+ case SandboxReport::ProcType::RDD:
+ aProcType.AssignLiteral("dataDecoder");
+ return NS_OK;
+ case SandboxReport::ProcType::SOCKET_PROCESS:
+ aProcType.AssignLiteral("socketProcess");
+ return NS_OK;
+ case SandboxReport::ProcType::UTILITY:
+ aProcType.AssignLiteral("utility");
+ return NS_OK;
+ default:
+ MOZ_ASSERT(false);
+ return NS_ERROR_UNEXPECTED;
+ }
+}
+
+/* readonly attribute uint32_t syscall; */
+NS_IMETHODIMP SandboxReportWrapper::GetSyscall(uint32_t* aSyscall) {
+ *aSyscall = static_cast<uint32_t>(mReport.mSyscall);
+ MOZ_ASSERT(static_cast<SandboxReport::ULong>(*aSyscall) == mReport.mSyscall);
+ return NS_OK;
+}
+
+/* readonly attribute uint32_t numArgs; */
+NS_IMETHODIMP SandboxReportWrapper::GetNumArgs(uint32_t* aNumArgs) {
+ *aNumArgs = static_cast<uint32_t>(kSandboxSyscallArguments);
+ return NS_OK;
+}
+
+/* ACString getArg (in uint32_t aIndex); */
+NS_IMETHODIMP SandboxReportWrapper::GetArg(uint32_t aIndex,
+ nsACString& aRetval) {
+ if (aIndex >= kSandboxSyscallArguments) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ const auto arg = mReport.mArgs[aIndex];
+ nsAutoCString str;
+ // Use decimal for smaller numbers (more likely ints) and hex for
+ // larger (more likely pointers). This cutoff is arbitrary.
+ if (arg >= 1000000) {
+ str.AppendLiteral("0x");
+ str.AppendInt(arg, 16);
+ } else {
+ str.AppendInt(arg, 10);
+ }
+ aRetval = str;
+ return NS_OK;
+}
+
+class SandboxReportArray final : public mozISandboxReportArray {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_MOZISANDBOXREPORTARRAY
+
+ explicit SandboxReportArray(SandboxReporter::Snapshot&& aSnap)
+ : mOffset(aSnap.mOffset), mArray(std::move(aSnap.mReports)) {}
+
+ private:
+ ~SandboxReportArray() = default;
+ uint64_t mOffset;
+ nsTArray<SandboxReport> mArray;
+};
+
+NS_IMPL_ISUPPORTS(SandboxReportArray, mozISandboxReportArray)
+
+/* readonly attribute uint64_t begin; */
+NS_IMETHODIMP SandboxReportArray::GetBegin(uint64_t* aBegin) {
+ *aBegin = mOffset;
+ return NS_OK;
+}
+
+/* readonly attribute uint64_t end; */
+NS_IMETHODIMP SandboxReportArray::GetEnd(uint64_t* aEnd) {
+ *aEnd = mOffset + mArray.Length();
+ return NS_OK;
+}
+
+/* mozISandboxReport getElement (in uint64_t aIndex); */
+NS_IMETHODIMP SandboxReportArray::GetElement(uint64_t aIndex,
+ mozISandboxReport** aRetval) {
+ uint64_t relIndex = aIndex - mOffset;
+ if (relIndex >= mArray.Length()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsCOMPtr<mozISandboxReport> wrapper =
+ new SandboxReportWrapper(mArray[relIndex]);
+ wrapper.forget(aRetval);
+ return NS_OK;
+}
+
+class SandboxReporterWrapper final : public mozISandboxReporter {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_MOZISANDBOXREPORTER
+
+ SandboxReporterWrapper() = default;
+
+ private:
+ ~SandboxReporterWrapper() = default;
+};
+
+NS_IMPL_ISUPPORTS(SandboxReporterWrapper, mozISandboxReporter)
+
+/* mozISandboxReportArray snapshot(); */
+NS_IMETHODIMP SandboxReporterWrapper::Snapshot(
+ mozISandboxReportArray** aRetval) {
+ if (!XRE_IsParentProcess()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsCOMPtr<mozISandboxReportArray> wrapper =
+ new SandboxReportArray(SandboxReporter::Singleton()->GetSnapshot());
+ wrapper.forget(aRetval);
+ return NS_OK;
+}
+
+} // namespace mozilla
+
+NS_IMPL_COMPONENT_FACTORY(mozISandboxReporter) {
+ return MakeAndAddRef<SandboxReporterWrapper>().downcast<nsISupports>();
+}
diff --git a/security/sandbox/linux/reporter/components.conf b/security/sandbox/linux/reporter/components.conf
new file mode 100644
index 0000000000..7bd278f349
--- /dev/null
+++ b/security/sandbox/linux/reporter/components.conf
@@ -0,0 +1,13 @@
+# -*- 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/.
+
+Classes = [
+ {
+ 'cid': '{5118a6f9-2493-4f97-9552-620663e03cb3}',
+ 'contract_ids': ['@mozilla.org/sandbox/syscall-reporter;1'],
+ 'type': 'mozISandboxReporter',
+ },
+]
diff --git a/security/sandbox/linux/reporter/moz.build b/security/sandbox/linux/reporter/moz.build
new file mode 100644
index 0000000000..ebc11c5ab6
--- /dev/null
+++ b/security/sandbox/linux/reporter/moz.build
@@ -0,0 +1,36 @@
+# -*- 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",
+]
+
+UNIFIED_SOURCES += [
+ "SandboxReporter.cpp",
+ "SandboxReporterWrappers.cpp",
+]
+
+XPCOM_MANIFESTS += [
+ "components.conf",
+]
+
+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"
+
+REQUIRES_UNIFIED_BUILD = True