[tor-commits] [sandboxed-tor-browser/master] Disable PI futex calls in the Tor Browser sandbox (x86_64).

yawning at torproject.org yawning at torproject.org
Sat Dec 3 21:38:34 UTC 2016


commit af2f433511ba613c7139709d2abebdba6820e8ca
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Sat Dec 3 21:32:34 2016 +0000

    Disable PI futex calls in the Tor Browser sandbox (x86_64).
    
    There are rumors that PI futexes have scary race conditions, that enable
    an exploit that is being sold by the forces of darkness.  On systems where
    we can filter futex kernel args, we reject such calls.
    
    However this breaks PulseAudio, because PI futex usage is determined at
    compile time.  This fixes up the mutex creation call, to never request PI
    mutexes.
    
    Thanks to the unnamed reporter who filed the issues on the tails, bug
    tracker and chatted with me on IRC about it.
    
    Note: This could be enabled unconditionally (ie: also on x86), but since
    that platform doesn't filter syscalls by argument due to seccomp-bpf
    limitations, it seems somewhat pointless.
    
    See: https://labs.riseup.net/code/issues/11524
---
 data/torbrowser-launcher-whitelist.seccomp         | 29 +++++++-
 .../internal/sandbox/application.go                |  9 +++
 src/tbb_stub/tbb_stub.c                            | 81 ++++++++++++++++++++++
 3 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/data/torbrowser-launcher-whitelist.seccomp b/data/torbrowser-launcher-whitelist.seccomp
index f47a290..7e47052 100644
--- a/data/torbrowser-launcher-whitelist.seccomp
+++ b/data/torbrowser-launcher-whitelist.seccomp
@@ -1,7 +1,32 @@
 TIOCGPGRP=21519
 
-# futex: FUTEX_CMP_REQUEUE_PRIVATE || FUTEX_LOCK_PI_PRIVATE || FUTEX_UNLOCK_PI_PRIVATE || FUTEX_WAIT || FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME || FUTEX_WAIT_PRIVATE || FUTEX_WAKE || FUTEX_WAKE_OP_PRIVATE || FUTEX_WAKE_PRIVATE || FUTEX_WAIT_BITSET_PRIVATE || FUTEX_UNLOCK_PI
-futex: arg1 == 0 || arg1 == 128 || arg1 == 129 || arg1 == 132 || arg1 == 133 || arg1 == 393 || arg1 == 134 || arg1 == 1 || arg1 == 135 || arg1 == 139 || arg1 == 140 || arg1 == 137 || arg1 == 7
+FUTEX_WAIT=0
+FUTEX_WAKE=1
+FUTEX_FD=2
+FUTEX_REQUEUE=3
+FUTEX_CMP_REQUEUE=3
+FUTEX_WAKE_OP=5
+#FUTEX_LOCK_PI=6
+#FUTEX_UNLOCK_PI=7
+FUTEX_WAIT_BITSET=9
+FUTEX_PRIVATE_FLAG=128
+FUTEX_CLOCK_REALTIME=256
+
+FUTEX_WAIT_PRIVATE=FUTEX_WAIT | FUTEX_PRIVATE_FLAG
+FUTEX_WAKE_PRIVATE=FUTEX_WAKE | FUTEX_PRIVATE_FLAG
+FUTEX_CMP_REQUEUE_PRIVATE=FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG
+FUTEX_WAKE_OP_PRIVATE=FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG
+#FUTEX_LOCK_PI_PRIVATE=FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG
+#FUTEX_UNLOCK_PI_PRIVATE=FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG
+FUTEX_WAIT_BITSET_PRIVATE=FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG
+
+# XXX/yawning: Because we patch PulseAudio's mutex creation, we can omit
+# FUTEX_LOCK_PI_PRIVATE, FUTEX_UNLOCK_PI_PRIVATE, FUTEX_UNLOCK_PI.
+#
+# This is deliberate and aims to avoid rumored scary race conditions in the
+# PI futex code.
+futex: arg1 == FUTEX_CMP_REQUEUE_PRIVATE || arg1 == FUTEX_WAIT || arg1 == FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME || arg1 == FUTEX_WAIT_PRIVATE || arg1 == FUTEX_WAKE || arg1 == FUTEX_WAKE_OP_PRIVATE || arg1 == FUTEX_WAKE_PRIVATE || arg1 == FUTEX_WAIT_BITSET_PRIVATE
+
 lseek: 1
 open: 1
 read: 1
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
index 6ce948e..edac173 100644
--- a/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
+++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/application.go
@@ -232,6 +232,15 @@ func RunTorBrowser(cfg *config.Config, manif *config.Manifest, tor *tor.Tor) (cm
 				ldLibraryPath = ldLibraryPath + ":" + paLibsPath
 				h.roBind(paLibsPath, restrictedPulseDir, false)
 				extraLdLibraryPath = extraLdLibraryPath + ":" + restrictedPulseDir
+
+				matches, err := filepath.Glob(paLibsPath + "/*.so")
+				if err != nil {
+					return nil, err
+				}
+				for _, v := range matches {
+					_, f := filepath.Split(v)
+					extraLibs = append(extraLibs, f)
+				}
 			} else {
 				log.Printf("sandbox: Failed to find pulse audio libraries.")
 			}
diff --git a/src/tbb_stub/tbb_stub.c b/src/tbb_stub/tbb_stub.c
index 7e2bb1f..e431222 100644
--- a/src/tbb_stub/tbb_stub.c
+++ b/src/tbb_stub/tbb_stub.c
@@ -51,6 +51,9 @@
 #ifdef __i386__
 #include <sys/time.h>
 #include <sys/resource.h>
+#else
+#include <glob.h>
+#include <stdbool.h>
 #endif
 
 static pthread_once_t stub_init_once = PTHREAD_ONCE_INIT;
@@ -177,6 +180,7 @@ XQueryExtension(Display *display, _Xconst char *name, int *major, int *event, in
 }
 
 #ifdef __i386__
+
 static int (*real_getrlimit)(__rlimit_resource_t, struct rlimit *);
 
 int
@@ -195,6 +199,83 @@ getrlimit(__rlimit_resource_t resource, struct rlimit *rlim)
 
   return real_getrlimit(resource, rlim);
 }
+
+#else
+
+typedef struct pa_mutex pm;
+static pm* (*real_pa_mutex_new)(bool, bool);
+
+static char *
+glob_library(const char *lib_glob) {
+  glob_t gb;
+  char *lib = NULL;
+  size_t i;
+
+  if (glob(lib_glob, GLOB_MARK, NULL, &gb) != 0) {
+    return NULL;
+  }
+
+  for (i = 0; i < gb.gl_pathc; i++) {
+    const char *path = gb.gl_pathv[i];
+    size_t plen = strlen(path);
+
+    if (plen > 0 && path[plen] != '/') {
+      lib = strndup(path, plen);
+      break;
+    }
+  }
+
+  globfree(&gb);
+
+  return lib;
+}
+
+/* There are rumors that PI futexes have scary race conditions, that enable
+ * an exploit that is being sold by the forces of darkness.  On systems where
+ * we can filter futex kernel args, we reject such calls.
+ *
+ * However this breaks PulseAudio, because PI futex usage is determined at
+ * compile time.  This fixes up the mutex creation call, to never request PI
+ * mutexes.
+ *
+ * Thanks to the unnamed reporter who filed the issues on the tails, bug
+ * tracker and chatted with me on IRC about it.
+ * See: https://labs.riseup.net/code/issues/11524
+ *
+ * Note: This could be enabled unconditionally (ie: also on x86), but since
+ * that platform doesn't filter syscalls by argument due to seccomp-bpf
+ * limitations, it seems somewhat pointless.
+ */
+pm *
+pa_mutex_new(bool recursive, bool inherit_priority) {
+  (void) inherit_priority;
+
+  pthread_once(&stub_init_once, stub_init);
+
+  if (real_pa_mutex_new == NULL) {
+    void *handle;
+    char *lib;
+
+    if ((lib = glob_library("/usr/lib/pulseaudio/libpulsecore-*.so")) == NULL) {
+      fprintf(stderr, "ERROR: Failed to find `libpulsecore-*.so`");
+      abort();
+    }
+
+    if ((handle = real_dlopen(lib, RTLD_LAZY|RTLD_LOCAL)) == NULL) {
+      fprintf(stderr, "ERROR: Failed to dlopen() libpulsecore.so: %s\n", dlerror());
+      abort();
+    }
+    free(lib);
+
+    if ((real_pa_mutex_new = dlsym(handle, "pa_mutex_new")) == NULL) {
+      fprintf(stderr, "ERROR: Failed to find `pa_mutex_new()` symbol: %s\n", dlerror());
+      abort();
+    }
+    dlclose(handle);
+  }
+  return real_pa_mutex_new(recursive, false);
+}
+
 #endif
 
 /*  Initialize the stub. */



More information about the tor-commits mailing list