Bug 1376910 - Remove SysV IPC access from Linux content sandbox when possible. r=gcp
authorJed Davis <jld@mozilla.com>
Fri, 26 Jan 2018 19:43:10 -0700
changeset 402974 74b5e036363f6123db0a96e31355b4aa88058c28
parent 402973 dcb60325f0cf4e375a0e2bb36d96e7632a16bdba
child 402975 00db0a388e72888e2051762bdcc5f0085eea6c6e
push id33408
push usercsabou@mozilla.com
push dateFri, 09 Feb 2018 00:28:58 +0000
treeherdermozilla-central@75f63c4d1ebc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgcp
bugs1376910, 1271100, 1362601
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1376910 - Remove SysV IPC access from Linux content sandbox when possible. r=gcp There are a few things that use SysV IPC, which we discovered the last time we tried to do this, which need to be accomodated: 1. The ALSA dmix plugin; if the build has ALSA support (off by default) and if audio remoting is disabled, SysV IPC is allowed. 2. ATI/AMD's old proprietary graphics driver (fglrx), which is obsolete and doesn't support newer hardware, but still has users; if it's detected, SysV IPC is allowed. 3. Graphics libraries trying to use the MIT-SHM extension; this is already turned off for other reasons (see bug 1271100), but that shim seems to not load early enough in some cases, so it's copied into libmozsandbox, which is preloaded before anything else in LD_PRELOAD. Also, msgget is now blocked in all cases; the only case it was known to be used involved ESET antivirus, which is now handled specially (bug 1362601). In any case, the seccomp-bpf policy has never allowed actually *using* message queues, so creating them is not very useful. MozReview-Commit-ID: 5bOOQcXFd9U
security/sandbox/linux/SandboxFilter.cpp
security/sandbox/linux/SandboxHooks.cpp
security/sandbox/linux/launch/SandboxLaunch.cpp
security/sandbox/linux/launch/moz.build
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -14,16 +14,17 @@
 #include "SandboxLogging.h"
 #ifdef MOZ_GMP_SANDBOX
 #include "SandboxOpenedFiles.h"
 #endif
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/UniquePtr.h"
+#include "prenv.h"
 
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/ioctl.h>
 #include <linux/ipc.h>
 #include <linux/net.h>
 #include <linux/prctl.h>
 #include <linux/sched.h>
@@ -371,16 +372,17 @@ public:
 // 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;
   ContentProcessSandboxParams mParams;
+  bool mAllowSysV;
 
   bool BelowLevel(int aLevel) const {
     return mParams.mLevel < aLevel;
   }
   ResultExpr AllowBelowLevel(int aLevel, ResultExpr aOrElse) const {
     return BelowLevel(aLevel) ? Allow() : Move(aOrElse);
   }
   ResultExpr AllowBelowLevel(int aLevel) const {
@@ -589,16 +591,17 @@ private:
     return rv;
   }
 
 public:
   ContentSandboxPolicy(SandboxBrokerClient* aBroker,
                        ContentProcessSandboxParams&& aParams)
     : mBroker(aBroker)
     , mParams(Move(aParams))
+    , mAllowSysV(PR_GetEnv("MOZ_SANDBOX_ALLOW_SYSV") != nullptr)
     { }
 
   ~ContentSandboxPolicy() override = default;
 
   Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
     switch(aCall) {
     case SYS_RECVFROM:
     case SYS_SENDTO:
@@ -655,18 +658,20 @@ public:
       // anymore; this needs to be studied.
     case SHMGET:
     case SHMCTL:
     case SHMAT:
     case SHMDT:
     case SEMGET:
     case SEMCTL:
     case SEMOP:
-    case MSGGET:
-      return Some(Allow());
+      if (mAllowSysV) {
+        return Some(Allow());
+      }
+      return SandboxPolicyCommon::EvaluateIpcCall(aCall);
     default:
       return SandboxPolicyCommon::EvaluateIpcCall(aCall);
     }
   }
 #endif
 
 #ifdef MOZ_PULSEAUDIO
   ResultExpr PrctlPolicy() const override {
--- a/security/sandbox/linux/SandboxHooks.cpp
+++ b/security/sandbox/linux/SandboxHooks.cpp
@@ -9,16 +9,19 @@
 
 #include <dlfcn.h>
 #include <signal.h>
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/inotify.h>
+#ifdef MOZ_X11
+#include <X11/Xlib.h>
+#endif
 
 // Signal number used to enable seccomp on each thread.
 extern mozilla::Atomic<int> gSeccompTsyncBroadcastSignum;
 
 static bool
 SigSetNeedsFixup(const sigset_t* aSet)
 {
   int tsyncSignum = gSeccompTsyncBroadcastSignum;
@@ -116,8 +119,22 @@ inotify_init(void)
 }
 
 extern "C" MOZ_EXPORT int
 inotify_init1(int flags)
 {
   errno = ENOSYS;
   return -1;
 }
+
+#ifdef MOZ_X11
+// We're already preventing the use of X11 MIT-SHM like this in
+// widget/gtk/mozgtk/mozgtk.c because of bug 1271100, but that's not
+// quite enough: sometimes libXext can be preloaded, so we have to
+// defeat that with our own preload library.  (With just the mozgtk
+// interposition, we saw crashes when we blocked the SysV IPC
+// syscalls; see bug 1376910 comment #14.)
+extern "C" MOZ_EXPORT Bool
+XShmQueryExtension(Display* aDisplay)
+{
+  return False;
+}
+#endif
--- a/security/sandbox/linux/launch/SandboxLaunch.cpp
+++ b/security/sandbox/linux/launch/SandboxLaunch.cpp
@@ -16,24 +16,28 @@
 
 #include "LinuxCapabilities.h"
 #include "LinuxSched.h"
 #include "SandboxChrootProto.h"
 #include "SandboxInfo.h"
 #include "SandboxLogging.h"
 #include "base/eintr_wrapper.h"
 #include "base/strings/safe_sprintf.h"
+#include "mozilla/Array.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SandboxReporter.h"
 #include "mozilla/SandboxSettings.h"
+#include "mozilla/Services.h"
 #include "mozilla/Unused.h"
+#include "nsCOMPtr.h"
+#include "nsIGfxInfo.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
 
 #ifdef MOZ_X11
 #ifndef MOZ_WIDGET_GTK
 #error "Unknown toolkit"
@@ -93,16 +97,48 @@ IsDisplayLocal()
   }
 #endif
 
   // Assume that other backends (e.g., Wayland) will not use the
   // network namespace.
   return true;
 }
 
+// Content processes may need direct access to SysV IPC in certain
+// uncommon use cases: if using fglrx GPU drivers (officially obsolete
+// but still in use), or the ALSA dmix plugin without cubeb remoting.
+static bool
+ContentNeedsSysVIPC()
+{
+#ifdef MOZ_ALSA
+  if (!Preferences::GetBool("media.cubeb.sandbox")) {
+    return true;
+  }
+#endif
+  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+  nsAutoString vendorID;
+  static const Array<nsresult (nsIGfxInfo::*)(nsAString&), 2> kMethods = {
+    &nsIGfxInfo::GetAdapterVendorID,
+    &nsIGfxInfo::GetAdapterVendorID2,
+  };
+  for (const auto method : kMethods) {
+    if (NS_SUCCEEDED((gfxInfo->*method)(vendorID))) {
+      // This test is based on telemetry data.  The proprietary ATI
+      // drivers seem to use this vendor string, including for some
+      // newer devices that have AMD branding in the device name.
+      // The open-source drivers integrated into Mesa appear to use
+      // the vendor ID "X.Org" instead.
+      if (vendorID.EqualsLiteral("ATI Technologies Inc.")) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 static void
 PreloadSandboxLib(base::environment_map* aEnv)
 {
   // Preload libmozsandbox.so so that sandbox-related interpositions
   // can be defined there instead of in the executable.
   // (This could be made conditional on intent to use sandboxing, but
   // it's harmless for non-sandboxed processes.)
   nsAutoCString preload;
@@ -211,18 +247,26 @@ SandboxLaunchPrepare(GeckoProcessType aT
     if (level >= 1) {
       canChroot = true;
       flags |= CLONE_NEWNET | CLONE_NEWIPC;
     }
     break;
 #endif
 #ifdef MOZ_CONTENT_SANDBOX
   case GeckoProcessType_Content:
-    // TODO: CLONE_NEWIPC (bug 1376910) if not fglrx and level >= 1,
-    // once the XShm detection shim is fixed.
+    if (level >= 1) {
+      static const bool needSysV = ContentNeedsSysVIPC();
+      if (needSysV) {
+        // Tell the child process so it can adjust its seccomp-bpf
+        // policy.
+        aOptions->env_map["MOZ_SANDBOX_ALLOW_SYSV"] = "1";
+      } else {
+        flags |= CLONE_NEWIPC;
+      }
+    }
 
     if (level >= 4) {
       canChroot = true;
       // Unshare network namespace if allowed by graphics; see
       // function definition above for details.  (The display
       // local-ness is cached because it won't change.)
       static const bool isDisplayLocal = IsDisplayLocal();
       if (isDisplayLocal) {
--- a/security/sandbox/linux/launch/moz.build
+++ b/security/sandbox/linux/launch/moz.build
@@ -21,12 +21,15 @@ LOCAL_INCLUDES += [
     '/security/sandbox/chromium',
     '/security/sandbox/linux',
 ]
 
 USE_LIBS += [
     'mozsandbox',
 ]
 
+if CONFIG['MOZ_ALSA']:
+    DEFINES['MOZ_ALSA'] = True
+
 # For the X11 socket domain inspection in SandboxLaunch:
 CXXFLAGS += CONFIG['TK_CFLAGS']
 
 FINAL_LIBRARY = 'xul'