Bug 1286865 - Step 2: Add XPCOM bindings for sandbox syscall reporter. r=gcp r=glandium draft
authorJed Davis <jld@mozilla.com>
Mon, 30 Jan 2017 18:50:41 -0700
changeset 479591 f8fb19dd078f3865d814c0d21998c1c5c917b849
parent 479590 2b6d4c95dd5928bca2cb85228d49522bf40bd92c
child 479592 16d73dcb5b84140467a267c86c7e7eda040d450b
push id44313
push userbmo:jld@mozilla.com
push dateTue, 07 Feb 2017 01:11:03 +0000
reviewersgcp, glandium
bugs1286865
milestone54.0a1
Bug 1286865 - Step 2: Add XPCOM bindings for sandbox syscall reporter. r=gcp r=glandium MozReview-Commit-ID: GERRsOJ7H2w
browser/installer/package-manifest.in
security/sandbox/linux/interfaces/moz.build
security/sandbox/linux/interfaces/mozISandboxReporter.idl
security/sandbox/linux/moz.build
security/sandbox/linux/reporter/SandboxReporterWrappers.cpp
security/sandbox/linux/reporter/moz.build
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -729,16 +729,17 @@
 @BINPATH@/wow_helper.exe
 #endif
 #endif
 #endif
 
 #if defined(MOZ_SANDBOX)
 #if defined(XP_LINUX)
 @BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@
+@RESPATH@/components/sandbox.xpt
 #endif
 #endif
 
 ; for Solaris SPARC
 #ifdef SOLARIS
 bin/libfreebl_32fpu_3.so
 bin/libfreebl_32int_3.so
 bin/libfreebl_32int64_3.so
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/interfaces/moz.build
@@ -0,0 +1,11 @@
+# -*- 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/.
+
+XPIDL_MODULE = 'sandbox'
+
+XPIDL_SOURCES += [
+    'mozISandboxReporter.idl',
+]
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/interfaces/mozISandboxReporter.idl
@@ -0,0 +1,65 @@
+/* -*- Mode: IDL; 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 "nsISupports.idl"
+
+// A wrapper for the C++ class SandboxReport, representing one system
+// call that was rejected by policy.
+[scriptable, builtinclass, uuid(ed1e84d3-3346-42e1-b28c-e76a77f549f0)]
+interface mozISandboxReport : nsISupports
+{
+  // The timestamp relative to the time when this property is read.
+  // This is mainly meant for distinguishing recent events that might
+  // be related to an observable failure from older ones that may be
+  // unrelated, not for exact timing.
+  readonly attribute uint64_t msecAgo;
+  readonly attribute int32_t pid;
+  readonly attribute int32_t tid;
+  readonly attribute ACString procType;
+  readonly attribute uint32_t syscall;
+  // Currently numArgs is effectively a constant and indicates the
+  // maximum number of arguments possible on the platform; the actual
+  // system call may use fewer.
+  readonly attribute uint32_t numArgs;
+  // The argument values are presented as strings because JS doesn't
+  // have 64-bit integers and data would be lost on 64-bit platforms
+  // if the XPIDL type uint64_t were used.  The string may be decimal
+  // or hex (with leading "0x").
+  ACString getArg(in uint32_t aIndex);
+};
+
+// A wrapper for SandboxReporter::Snapshot, representing the most
+// recent SandboxReport events.  Index 0 is the first report in the
+// session, and so on; exposing the indices like this lets us see how
+// many reports have been received even though only a limited number
+// of them are stored.
+[scriptable, builtinclass, uuid(6e8ff6e5-05c9-42d3-853d-40523fd86a50)]
+interface mozISandboxReportArray : nsISupports
+{
+  readonly attribute uint64_t begin;
+  readonly attribute uint64_t end;
+  // (aIndex >= begin && aIndex < end) must be true.
+  mozISandboxReport getElement(in uint64_t aIndex);
+};
+
+// A wrapper for the SandboxReporter; use the component/contract IDs
+// below to access the SandboxReporter singleton.  The component
+// constructor will fail if called in a child process.
+[scriptable, builtinclass, uuid(8535bdf7-6d9e-4853-acf9-a146449c4a3b)]
+interface mozISandboxReporter : nsISupports
+{
+  mozISandboxReportArray snapshot();
+};
+
+%{ C++
+
+#define MOZ_SANDBOX_REPORTER_CID \
+{0x5118a6f9, 0x2493, 0x4f97, {0x95, 0x52, 0x62, 0x06, 0x63, 0xe0, 0x3c, 0xb3}}
+
+#define MOZ_SANDBOX_REPORTER_CONTRACTID \
+    "@mozilla.org/sandbox/syscall-reporter;1"
+
+%}
--- a/security/sandbox/linux/moz.build
+++ b/security/sandbox/linux/moz.build
@@ -105,14 +105,15 @@ if CONFIG['OS_TARGET'] != 'Android':
     # Needed for clock_gettime with glibc < 2.17:
     OS_LIBS += [
         'rt',
     ]
 
 DIRS += [
     'broker',
     'glue',
+    'interfaces',
     'reporter',
 ]
 
 TEST_DIRS += [
     'gtest',
 ]
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/reporter/SandboxReporterWrappers.cpp
@@ -0,0 +1,220 @@
+/* -*- 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/ModuleUtils.h"
+#include "nsCOMPtr.h"
+#include "nsPrintfCString.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+
+class SandboxReportWrapper final : public mozISandboxReport
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZISANDBOXREPORT
+
+  explicit SandboxReportWrapper(const SandboxReport& aReport)
+  : mReport(aReport)
+  { }
+
+private:
+  ~SandboxReportWrapper() { }
+  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::MEDIA_PLUGIN:
+    aProcType.AssignLiteral("mediaPlugin");
+    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(Move(aSnap.mReports))
+  { }
+
+private:
+  ~SandboxReportArray() { }
+  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() { }
+
+private:
+  ~SandboxReporterWrapper() { }
+};
+
+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;
+}
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(SandboxReporterWrapper)
+
+NS_DEFINE_NAMED_CID(MOZ_SANDBOX_REPORTER_CID);
+
+static const mozilla::Module::CIDEntry kSandboxReporterCIDs[] = {
+  { &kMOZ_SANDBOX_REPORTER_CID, false, nullptr,
+    SandboxReporterWrapperConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kSandboxReporterContracts[] = {
+  { MOZ_SANDBOX_REPORTER_CONTRACTID, &kMOZ_SANDBOX_REPORTER_CID },
+  { nullptr }
+};
+
+static const mozilla::Module kSandboxReporterModule = {
+  mozilla::Module::kVersion,
+  kSandboxReporterCIDs,
+  kSandboxReporterContracts
+};
+
+NSMODULE_DEFN(SandboxReporterModule) = &kSandboxReporterModule;
+
+} // namespace mozilla
--- a/security/sandbox/linux/reporter/moz.build
+++ b/security/sandbox/linux/reporter/moz.build
@@ -6,16 +6,17 @@
 
 EXPORTS.mozilla += [
     'SandboxReporter.h',
     'SandboxReporterCommon.h',
 ]
 
 SOURCES += [
     'SandboxReporter.cpp',
+    'SandboxReporterWrappers.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/security/sandbox/linux', # SandboxLogging.h
 ]
 
 # Need this for base::PlatformThread
 include('/ipc/chromium/chromium-config.mozbuild')