Bug 1430949 - Isolate network namespace in Linux content sandbox level 4. r=gcp
authorJed Davis <jld@mozilla.com>
Tue, 23 Jan 2018 22:31:06 -0700
changeset 402006 a415b43fc1d26ff89cd3d9fd4bed95611febbabe
parent 402005 215eaf28c96247901e8b6ac1b37a9c392a74414d
child 402007 588b11d5976e5e903f944658956d0035dbcc9dc3
push id58966
push userjedavis@mozilla.com
push dateThu, 01 Feb 2018 01:24:30 +0000
treeherderautoland@a415b43fc1d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgcp
bugs1430949
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 1430949 - Isolate network namespace in Linux content sandbox level 4. r=gcp This is turned off if the X11 server is remote -- including TCP to localhost -- because otherwise it would be blocked. Note that ssh X forwarding presents a TCP-only server. The Nightly default for the force-namespace hidden pref is changed to false, because we will now normally be using namespaces if available. MozReview-Commit-ID: L9BbLdoLvLg
security/sandbox/linux/launch/SandboxLaunch.cpp
security/sandbox/linux/launch/moz.build
--- a/security/sandbox/linux/launch/SandboxLaunch.cpp
+++ b/security/sandbox/linux/launch/SandboxLaunch.cpp
@@ -29,18 +29,80 @@
 #include "mozilla/SandboxReporter.h"
 #include "mozilla/SandboxSettings.h"
 #include "mozilla/Unused.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"
+#endif
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include "X11UndefineNone.h"
+#include "gfxPlatform.h"
+#endif
+
 namespace mozilla {
 
+// Returns true if graphics will work from a content process
+// started in a new network namespace.  Specifically, named
+// Unix-domain sockets will work, but TCP/IP will not, even if it's a
+// connection to localhost: the child process has its own private
+// loopback interface.
+//
+// (Longer-term we intend to either proxy or remove X11 access from
+// content processes, at which point this will stop being an issue.)
+static bool
+IsDisplayLocal()
+{
+  // For X11, check whether the parent's connection is a Unix-domain
+  // socket.  This is done instead of trying to parse the display name
+  // because an empty hostname (e.g., ":0") will fall back to TCP in
+  // case of failure to connect using Unix-domain sockets.
+#ifdef MOZ_X11
+  // First, ensure that the parent process's graphics are initialized.
+  Unused << gfxPlatform::GetPlatform();
+
+  const auto display = gdk_display_get_default();
+  if (NS_WARN_IF(display == nullptr)) {
+    return false;
+  }
+  if (GDK_IS_X11_DISPLAY(display)) {
+    const int xSocketFd = ConnectionNumber(GDK_DISPLAY_XDISPLAY(display));
+    if (NS_WARN_IF(xSocketFd < 0)) {
+      return false;
+    }
+
+    int domain;
+    socklen_t optlen = static_cast<socklen_t>(sizeof(domain));
+    int rv = getsockopt(xSocketFd, SOL_SOCKET, SO_DOMAIN, &domain, &optlen);
+    if (NS_WARN_IF(rv != 0)) {
+      return false;
+    }
+    MOZ_RELEASE_ASSERT(static_cast<size_t>(optlen) == sizeof(domain));
+    // There's one more wrinkle here: the network namespace also
+    // controls "abstract namespace" addresses in the Unix domain.
+    // Xorg seems to listen on both abstract and normal addresses, but
+    // prefers abstract. This mean that if there exists a server that
+    // uses only the abstract namespace, then it will break and we
+    // won't be able to detect that ahead of time.  So, hopefully it
+    // does not exist.
+    return domain == AF_LOCAL;
+  }
+#endif
+
+  // Assume that other backends (e.g., Wayland) will not use the
+  // network namespace.
+  return true;
+}
+
 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;
@@ -152,25 +214,28 @@ SandboxLaunchPrepare(GeckoProcessType aT
     }
     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 >= 4) {
+      // 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) {
+        flags |= CLONE_NEWNET;
+      }
+    }
     // Hidden pref to allow testing user namespaces separately, even
     // if there's nothing that would require them.
-    if (Preferences::GetBool("security.sandbox.content.force-namespace",
-#ifdef NIGHTLY_BUILD
-                             true
-#else
-                             false
-#endif
-          )) {
+    if (Preferences::GetBool("security.sandbox.content.force-namespace", false)) {
       flags |= CLONE_NEWUSER;
     }
     break;
 #endif
   default:
     // Nothing yet.
     break;
   }
--- a/security/sandbox/linux/launch/moz.build
+++ b/security/sandbox/linux/launch/moz.build
@@ -21,9 +21,12 @@ LOCAL_INCLUDES += [
     '/security/sandbox/chromium',
     '/security/sandbox/linux',
 ]
 
 USE_LIBS += [
     'mozsandbox',
 ]
 
+# For the X11 socket domain inspection in SandboxLaunch:
+CXXFLAGS += CONFIG['TK_CFLAGS']
+
 FINAL_LIBRARY = 'xul'