Bug 1430949 - Isolate network namespace in Linux content sandbox level 4. r?gcp draft
authorJed Davis <jld@mozilla.com>
Tue, 23 Jan 2018 22:31:06 -0700
changeset 724482 03849e29d1a4a9dcab7235249238fdafc55f38d5
parent 724481 8aa2a4e5317f9b490e47a2676ed7446c93ea9a54
child 747162 d97c8a7786f5ca559b7942856907bc5b99914e7e
push id96758
push userbmo:jld@mozilla.com
push dateThu, 25 Jan 2018 02:07:55 +0000
reviewersgcp
bugs1430949
milestone60.0a1
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'