Bug 1376910 - Remove SysV IPC access from Linux content sandbox when possible. r=gcp draft
authorJed Davis <jld@mozilla.com>
Fri, 26 Jan 2018 19:43:10 -0700
changeset 752579 fbfc72e1a615fc0a9b893e0c1cb06bacf8e5ac70
parent 752350 8cc2427a322caa1e2c09ca3957335f88e573dc7a
push id98302
push userbmo:jld@mozilla.com
push dateThu, 08 Feb 2018 15:45:41 +0000
reviewersgcp
bugs1376910, 1271100, 1362601
milestone60.0a1
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'