[tor-commits] [sandboxed-tor-browser/master] Bug 20773: Stop mounting /proc in the Tor Browser container.

yawning at torproject.org yawning at torproject.org
Mon Jul 3 17:30:48 UTC 2017


commit 95857360ec7f84cf9f0a01855c15881c89919133
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Mon Jul 3 17:27:35 2017 +0000

    Bug 20773: Stop mounting /proc in the Tor Browser container.
    
    Wasn't so bad to figure out, though upstream still should fall back
    gracefully, since the only reason why it crashes horribly is because
    pthread_attr_getstack() returns a stack size of 0 for the default thread
    when /proc is missing.
    
    In our case we can safely fall back to querying RLIMIT_STACK, because
    the sandbox containerization explicity sets it to something large, but
    relatively sane.
---
 ChangeLog                                          |  1 +
 README.md                                          | 12 ++--
 .../internal/sandbox/application.go                |  1 +
 src/tbb_stub/tbb_stub.c                            | 76 ++++++++++++++++++++++
 4 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b42022a..51f693a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 Changes in version 0.0.9 - UNRELEASED:
  * Bug 22712: Suppress ATK Bridge initialization which will never work.
+ * Bug 20773: Stop mounting /proc in the Tor Browser container.
  * Fix the build being broken on Debian Jessie due to #22648.
  * Remove the undocumented command line options that enable unsafe behavior.
 
diff --git a/README.md b/README.md
index dc4fc18..6cad572 100644
--- a/README.md
+++ b/README.md
@@ -41,18 +41,16 @@ Things that the sandbox breaks:
 
 Places where the sandbox could be better:
 
- * More about the host system is exposed than neccecary, primarily because
-   Firefox crashes without `/proc`.
+ * The updater container still mounts `/proc`.
+ * PulseAudio is likely unsafe without a protocol filter like X11.
+ * X11 is still X11, and despite mitigations is likely still unsafe.
 
 Upstream Bugs:
 
- * Tor Browser should run without a `/proc` filesystem.
-   (https://bugs.torproject.org/20283)
+ * Tor Browser should run without a `/proc` filesystem, worked around in
+   the worst possible way.  (https://bugs.torproject.org/20283)
  * OpenGL software rendering is  broken on certain Linux systems.
    (https://bugs.torproject.org/20866)
- * On certain systems, Firefox crashes with an X11 error due to the lack of
-   MIT-SHM support.  This appears to be a race condition, and still occurs
-   despite mitigations. (https://bugzilla.mozilla.org/show_bug.cgi?id=1271100)
 
 Notes:
 
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
index d3162dd..a160b67 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
@@ -69,6 +69,7 @@ func RunTorBrowser(cfg *config.Config, manif *config.Manifest, tor *tor.Tor) (pr
 	h.stderr = logger
 	h.seccompFn = installTorBrowserSeccompProfile
 	h.fakeDbus = true
+	h.mountProc = false
 
 	// Gtk+ and PulseAudio.
 	hasAdwaita := h.appendGtk2Theme()
diff --git a/src/tbb_stub/tbb_stub.c b/src/tbb_stub/tbb_stub.c
index e7ca733..84a14e8 100644
--- a/src/tbb_stub/tbb_stub.c
+++ b/src/tbb_stub/tbb_stub.c
@@ -37,6 +37,9 @@
 
 #define _GNU_SOURCE /* Fuck *BSD and Macintoys. */
 
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <arpa/inet.h>
@@ -47,11 +50,13 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 static pthread_once_t stub_init_once = PTHREAD_ONCE_INIT;
 static int (*real_connect)(int, const struct sockaddr *, socklen_t) = NULL;
 static int (*real_socket)(int, int, int) = NULL;
 static void *(*real_dlopen)(const char *, int) = NULL;
+static int (*real_pthread_attr_getstack)(const pthread_attr_t *, void **, size_t *);
 static struct sockaddr_un socks_addr;
 static struct sockaddr_un control_addr;
 
@@ -228,6 +233,73 @@ pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid)
   return -1;
 }
 
+/* Firefox will crash if pthread_attr_getstack doesn't return a sensible stack
+ * size, which will happen if /proc is missing, since glibc grovels through
+ * /proc/self/maps to determine this information for the default thread.
+ *
+ * See: glibc/nptl/pthread_getattr_np.c
+ */
+int
+pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize)
+{
+  int ret;
+
+  ret = real_pthread_attr_getstack(attr, stackaddr, stacksize);
+  if (ret != 0) {
+    fprintf(stderr, "WARN: pthread_attr_getstack(%p, %p, %p) = %d\n", attr, stackaddr, stacksize, ret);
+    return ret;
+  }
+
+#if 0
+  fprintf(stderr, "tbb_stub: pthread_attr_getstack(%p, %p, %p) = %d\n", attr, stackaddr, stacksize, ret);
+  fprintf(stderr, "tbb_stub:  stackaddr: %p\n", stackaddr);
+  fprintf(stderr, "tbb_stub:  stacksize: %ld\n", *stacksize);
+#endif
+
+  /* If we got a sensible value for the stack size, then return. */
+  if (*stacksize != 0) {
+    return ret;
+  } else {
+    /* Otherwise, we should be the initial thread (pid == tid). */
+    pid_t tid = syscall(__NR_gettid);
+    pid_t pid = getpid();
+
+    if (tid != pid) {
+      fprintf(stderr, "ERROR: Got a 0 stack size when pid = %d != tid = %d\n", pid, tid);
+      abort();
+    }
+  }
+
+  /* First try pthread_attr_getstacksize(), which works on glibc 2.25. */
+  ret = pthread_attr_getstacksize(attr, stacksize);
+  if (ret != 0 || *stacksize == 0) {
+    /* Fall back to getrlimit(). */
+    struct rlimit rl;
+
+    ret = getrlimit(RLIMIT_STACK, &rl);
+    if (ret != 0) {
+      fprintf(stderr, "ERROR: Failed to query rlimit: %d", ret);
+      abort();
+    }
+
+    /* So, the main reason why glibc digs through proc is so that it can
+     * return the current committed stack size, and not the upper bound on
+     * the stack size.  But without /proc, there's no good way to get this
+     * information.
+     *
+     * This is probably ok, pthread_attr_getstacksize() without proc mounted
+     * appears to do the same thing.
+     */
+    *stacksize = rl.rlim_cur;
+  }
+
+#if 0
+  fprintf(stderr, "tbb_stub: Fallback stacksize: %ld\n", *stacksize);
+#endif
+
+  return ret;
+}
+
 /*  Initialize the stub. */
 static void
 stub_init(void)
@@ -257,6 +329,10 @@ stub_init(void)
     fprintf(stderr, "ERROR: Failed to find `socket()` symbol: %s\n", dlerror());
     goto out;
   }
+  if ((real_pthread_attr_getstack = dlsym(RTLD_NEXT, "pthread_attr_getstack")) == NULL) {
+    fprintf(stderr, "ERROR: Failed to find `pthread_attr_getstack()` symbol: %s\n", dlerror());
+    goto out;
+  }
 
   /* Initialize the SOCKS target address. */
   socks_addr.sun_family = AF_LOCAL;



More information about the tor-commits mailing list