Bug 1286865 - Step 4: Report rejected syscall info in Telemetry. r=gcp r?francois
MozReview-Commit-ID: 7R755WT1Ftu
--- a/security/sandbox/linux/reporter/SandboxReporter.cpp
+++ b/security/sandbox/linux/reporter/SandboxReporter.cpp
@@ -6,22 +6,34 @@
#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 "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"
+#else
+#error "unrecognized architecture"
+#endif
namespace mozilla {
StaticAutoPtr<SandboxReporter> SandboxReporter::sSingleton;
SandboxReporter::SandboxReporter()
: mClientFd(-1)
, mServerFd(-1)
@@ -98,20 +110,122 @@ SandboxReporter::Singleton()
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::MEDIA_PLUGIN:
+ key.AppendLiteral("gmp");
+ 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.
+
+ // 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_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)
{
- // TODO: send a copy to Telemetry
+ SubmitToTelemetry(aReport);
+
MutexAutoLock lock(mMutex);
mBuffer[mCount % kSandboxReporterBufferSize] = aReport;
++mCount;
}
void
SandboxReporter::ThreadMain(void)
{
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10414,16 +10414,26 @@
"SANDBOX_CONTENT_ENABLED": {
"alert_emails": ["gcp@mozilla.com"],
"bug_numbers": [1098428],
"expires_in_version": "55",
"kind": "boolean",
"cpp_guard": "XP_LINUX",
"description": "Whether the sandbox is enabled for the content process"
},
+ "SANDBOX_REJECTED_SYSCALLS": {
+ "alert_emails": ["jld@mozilla.com", "gcp@mozilla.com"],
+ "bug_numbers": [1286865],
+ "expires_in_version": "never",
+ "releaseChannelCollection": "opt-out",
+ "kind": "count",
+ "keyed": true,
+ "cpp_guard": "XP_LINUX",
+ "description": "System calls blocked by a seccomp-bpf sandbox policy; limited to syscalls where we would crash on Nightly. The key is generally the architecture and syscall ID but in some cases we include non-personally-identifying information from the syscall arguments; see the function SubmitToTelemetry in security/sandbox/linux/reporter/SandboxReporter.cpp for details."
+ },
"SYNC_WORKER_OPERATION": {
"alert_emails": ["amarchesini@mozilla.com", "khuey@mozilla.com" ],
"bug_numbers": [1267904],
"expires_in_version": "never",
"kind": "exponential",
"high": 5000,
"n_buckets": 20,
"keyed": true,