Browse Source

Get Libevent's PRNG functioning under the linux sandbox

Libevent uses an arc4random implementation (I know, I know) to
generate DNS transaction IDs and capitalization.  But it liked to
initialize it either with opening /dev/urandom (which won't work
under the sandbox if it doesn't use the right pointer), or with
sysctl({CTL_KERN,KERN_RANDOM,RANDOM_UUIC}).  To make _that_ work, we
were permitting sysctl unconditionally.  That's not such a great
idea.

Instead, we try to initialize the libevent PRNG _before_ installing
the sandbox, and make sysctl always fail with EPERM under the
sandbox.
Nick Mathewson 10 years ago
parent
commit
e6785ee16d
5 changed files with 50 additions and 1 deletions
  1. 1 0
      configure.ac
  2. 19 0
      src/common/compat_libevent.c
  3. 2 0
      src/common/compat_libevent.h
  4. 18 1
      src/common/sandbox.c
  5. 10 0
      src/or/main.c

+ 1 - 0
configure.ac

@@ -435,6 +435,7 @@ AC_CHECK_FUNCS([event_get_version \
                 event_set_log_callback \
                 evdns_set_outgoing_bind_address \
                 evutil_secure_rng_set_urandom_device_file \
+                evutil_secure_rng_init \
                 event_base_loopexit])
 AC_CHECK_MEMBERS([struct event.min_heap_idx], , ,
 [#include <event.h>

+ 19 - 0
src/common/compat_libevent.c

@@ -13,6 +13,8 @@
 #include "compat.h"
 #include "compat_libevent.h"
 
+#include "crypto.h"
+
 #include "util.h"
 #include "torlog.h"
 
@@ -626,6 +628,23 @@ tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
 }
 #endif
 
+int
+tor_init_libevent_rng(void)
+{
+  int rv = 0;
+#ifdef HAVE_EVUTIL_SECURE_RNG_INIT
+  char buf[256];
+  if (evutil_secure_rng_init() < 0) {
+    rv = -1;
+  }
+  /* Older libevent -- manually initialize the RNG */
+  crypto_rand(buf, 32);
+  evutil_secure_rng_add_bytes(buf, 32);
+  evutil_secure_rng_get_bytes(buf, sizeof(buf));
+#endif
+  return rv;
+}
+
 #if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1) \
   && !defined(TOR_UNIT_TESTS)
 void

+ 2 - 0
src/common/compat_libevent.h

@@ -89,6 +89,8 @@ int tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
                                    struct bufferevent_rate_limit_group *g);
 #endif
 
+int tor_init_libevent_rng(void);
+
 void tor_gettimeofday_cached(struct timeval *tv);
 void tor_gettimeofday_cache_clear(void);
 #ifdef TOR_UNIT_TESTS

+ 18 - 1
src/common/sandbox.c

@@ -124,7 +124,6 @@ static int filter_nopar_gen[] = {
     SCMP_SYS(read),
     SCMP_SYS(rt_sigreturn),
     SCMP_SYS(set_robust_list),
-    SCMP_SYS(_sysctl),
 #ifdef __NR_sigreturn
     SCMP_SYS(sigreturn),
 #endif
@@ -373,6 +372,23 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
   return 0;
 }
 
+static int
+sb__sysctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+  int rc;
+  (void) filter;
+  (void) ctx;
+
+  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(_sysctl));
+  if (rc != 0) {
+    log_err(LD_BUG,"(Sandbox) failed to add _sysctl syscall, "
+        "received libseccomp error %d", rc);
+    return rc;
+  }
+
+  return 0;
+}
+
 /**
  * Function responsible for setting up the rename syscall for
  * the seccomp filter sandbox.
@@ -850,6 +866,7 @@ static sandbox_filter_func_t filter_func[] = {
 #endif
     sb_open,
     sb_openat,
+    sb__sysctl,
     sb_rename,
 #ifdef __NR_fcntl64
     sb_fcntl64,

+ 10 - 0
src/or/main.c

@@ -2432,6 +2432,9 @@ tor_init(int argc, char *argv[])
     return -1;
   }
   stream_choice_seed_weak_rng();
+  if (tor_init_libevent_rng() < 0) {
+    log_warn(LD_NET, "Problem initializing libevent RNG.");
+  }
 
   return 0;
 }
@@ -2723,6 +2726,7 @@ init_addrinfo(void)
 static sandbox_cfg_t*
 sandbox_init_filter(void)
 {
+  const or_options_t *options = get_options();
   sandbox_cfg_t *cfg = sandbox_cfg_new();
 
   sandbox_cfg_allow_openat_filename(&cfg,
@@ -2761,8 +2765,14 @@ sandbox_init_filter(void)
       tor_strdup("/dev/srandom"),
       tor_strdup("/dev/urandom"),
       tor_strdup("/dev/random"),
+      tor_strdup("/etc/hosts"),
       NULL, 0
   );
+  if (options->ServerDNSResolvConfFile)
+    sandbox_cfg_allow_open_filename(&cfg,
+                                tor_strdup(options->ServerDNSResolvConfFile));
+  else
+    sandbox_cfg_allow_open_filename(&cfg, tor_strdup("/etc/resolv.conf"));
 
 #define RENAME_SUFFIX(name, suffix)        \
   sandbox_cfg_allow_rename(&cfg,           \