Browse Source

Merge remote-tracking branch 'ctoader/gsoc-cap-stage2'

Conflicts:
	src/common/sandbox.c
Nick Mathewson 10 years ago
parent
commit
e0b2cd061b
12 changed files with 1561 additions and 136 deletions
  1. 7 1
      configure.ac
  2. 2 1
      src/common/address.c
  3. 2 0
      src/common/compat.c
  4. 2 1
      src/common/crypto.c
  5. 1231 120
      src/common/sandbox.c
  6. 198 3
      src/common/sandbox.h
  7. 5 3
      src/common/util.c
  8. 2 0
      src/common/util.h
  9. 2 1
      src/or/config.c
  10. 11 4
      src/or/dns.c
  11. 98 1
      src/or/main.c
  12. 1 1
      src/or/routerlist.c

+ 7 - 1
configure.ac

@@ -402,7 +402,13 @@ save_CPPFLAGS="$CPPFLAGS"
 LIBS="-levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32 $LIBS"
 LDFLAGS="$TOR_LDFLAGS_libevent $LDFLAGS"
 CPPFLAGS="$TOR_CPPFLAGS_libevent $CPPFLAGS"
-AC_CHECK_FUNCS(event_get_version event_get_version_number event_get_method event_set_log_callback evdns_set_outgoing_bind_address event_base_loopexit)
+AC_CHECK_FUNCS([event_get_version \
+                event_get_version_number \
+                event_get_method \
+                event_set_log_callback \
+                evdns_set_outgoing_bind_address \
+                evutil_secure_rng_set_urandom_device_file \
+                event_base_loopexit])
 AC_CHECK_MEMBERS([struct event.min_heap_idx], , ,
 [#include <event.h>
 ])

+ 2 - 1
src/common/address.c

@@ -14,6 +14,7 @@
 #include "address.h"
 #include "torlog.h"
 #include "container.h"
+#include "sandbox.h"
 
 #ifdef _WIN32
 #include <process.h>
@@ -234,7 +235,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = family;
     hints.ai_socktype = SOCK_STREAM;
-    err = getaddrinfo(name, NULL, &hints, &res);
+    err = sandbox_getaddrinfo(name, NULL, &hints, &res);
     if (!err) {
       best = NULL;
       for (res_p = res; res_p; res_p = res_p->ai_next) {

+ 2 - 0
src/common/compat.c

@@ -110,6 +110,7 @@
 #include "util.h"
 #include "container.h"
 #include "address.h"
+#include "sandbox.h"
 
 /* Inline the strl functions if the platform doesn't have them. */
 #ifndef HAVE_STRLCPY
@@ -126,6 +127,7 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
 {
   int fd;
 #ifdef O_CLOEXEC
+  path = sandbox_intern_string(path);
   fd = open(path, flags|O_CLOEXEC, mode);
   if (fd >= 0)
     return fd;

+ 2 - 1
src/common/crypto.c

@@ -56,6 +56,7 @@
 #include "../common/util.h"
 #include "container.h"
 #include "compat.h"
+#include "sandbox.h"
 
 #if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
 #error "We require OpenSSL >= 0.9.8"
@@ -2349,7 +2350,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
   return 0;
 #else
   for (i = 0; filenames[i]; ++i) {
-    fd = open(filenames[i], O_RDONLY, 0);
+    fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0);
     if (fd<0) continue;
     log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
     n = read_all(fd, (char*)out, out_len, 0);

File diff suppressed because it is too large
+ 1231 - 120
src/common/sandbox.c


+ 198 - 3
src/common/sandbox.h

@@ -12,6 +12,9 @@
 #ifndef SANDBOX_H_
 #define SANDBOX_H_
 
+#include "orconfig.h"
+#include "torint.h"
+
 #ifndef SYS_SECCOMP
 
 /**
@@ -22,13 +25,99 @@
 
 #endif
 
+#if defined(HAVE_SECCOMP_H) && defined(__linux__)
+#define USE_LIBSECCOMP
+#endif
+
+struct sandbox_cfg_elem;
+
+/** Typedef to structure used to manage a sandbox configuration. */
+typedef struct sandbox_cfg_elem sandbox_cfg_t;
+
 /**
  * Linux definitions
  */
-#ifdef __linux__
+#ifdef USE_LIBSECCOMP
 
+#ifndef __USE_GNU
 #define __USE_GNU
+#endif
 #include <sys/ucontext.h>
+#include <seccomp.h>
+#include <netdb.h>
+
+#define PARAM_PTR 0
+#define PARAM_NUM 1
+
+/**
+ * Enum used to manage the type of the implementation for general purpose.
+ */
+typedef enum {
+  /** Libseccomp implementation based on seccomp2*/
+  LIBSECCOMP2 = 0
+} SB_IMPL;
+
+/**
+ *  Configuration parameter structure associated with the LIBSECCOMP2
+ *  implementation.
+ */
+typedef struct smp_param {
+  /** syscall associated with parameter. */
+  int syscall;
+
+  /** parameter index. */
+  int pindex;
+  /** parameter value. */
+  intptr_t value;
+
+  /**  parameter flag (0 = not protected, 1 = protected). */
+  int prot;
+} smp_param_t;
+
+/**
+ * Structure used to manage a sandbox configuration.
+ *
+ * It is implemented as a linked list of parameters. Currently only controls
+ * parameters for open, openat, execve, stat64.
+ */
+struct sandbox_cfg_elem {
+  /** Sandbox implementation which dictates the parameter type. */
+  SB_IMPL implem;
+
+  /** Configuration parameter. */
+  void *param;
+
+  /** Next element of the configuration*/
+  struct sandbox_cfg_elem *next;
+};
+
+/**
+ * Structure used for keeping a linked list of getaddrinfo pre-recorded
+ * results.
+ */
+struct sb_addr_info_el {
+  /** Name of the address info result. */
+  char *name;
+  /** Pre-recorded getaddrinfo result. */
+  struct addrinfo *info;
+  /** Next element in the list. */
+  struct sb_addr_info_el *next;
+};
+/** Typedef to structure used to manage an addrinfo list. */
+typedef struct sb_addr_info_el sb_addr_info_t;
+
+/** Function pointer defining the prototype of a filter function.*/
+typedef int (*sandbox_filter_func_t)(scmp_filter_ctx ctx,
+    sandbox_cfg_t *filter);
+
+/** Type that will be used in step 3 in order to manage multiple sandboxes.*/
+typedef struct {
+  /** function pointers associated with the filter */
+  sandbox_filter_func_t *filter_func;
+
+  /** filter function pointer parameters */
+  sandbox_cfg_t *filter_dynamic;
+} sandbox_t;
 
 /**
  * Linux 32 bit definitions
@@ -46,10 +135,116 @@
 
 #endif
 
-#endif // __linux__
+#endif // USE_LIBSECCOMP
+
+#ifdef USE_LIBSECCOMP
+/** Pre-calls getaddrinfo in order to pre-record result. */
+int sandbox_add_addrinfo(const char *addr);
+
+struct addrinfo;
+/** Replacement for getaddrinfo(), using pre-recorded results. */
+int sandbox_getaddrinfo(const char *name, const char *servname,
+                        const struct addrinfo *hints,
+                        struct addrinfo **res);
+#else
+#define sandbox_getaddrinfo(name, servname, hints, res)  \
+  getaddrinfo((name),(servname), (hints),(res))
+#define sandbox_add_addrinfo(name) \
+  ((void)(name))
+#endif
 
+/** Use <b>fd</b> to log non-survivable sandbox violations. */
 void sandbox_set_debugging_fd(int fd);
-int tor_global_sandbox(void);
+
+#ifdef USE_LIBSECCOMP
+/** Returns a registered protected string used with the sandbox, given that
+ * it matches the parameter.
+ */
+const char* sandbox_intern_string(const char *param);
+#else
+#define sandbox_intern_string(s) (s)
+#endif
+
+/** Creates an empty sandbox configuration file.*/
+sandbox_cfg_t * sandbox_cfg_new(void);
+
+/**
+ * Function used to add a open allowed filename to a supplied configuration.
+ * The (char*) specifies the path to the allowed file, fr = 1 tells the
+ * function that the char* needs to be free-ed, 0 means the pointer does not
+ * need to be free-ed.
+ */
+int sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file,
+    int fr);
+
+/** Function used to add a series of open allowed filenames to a supplied
+ * configuration.
+ *  @param cfg  sandbox configuration.
+ *  @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
+ *    the char* specifies the path to the allowed file, 1 tells the function
+ *    that the char* needs to be free-ed, 0 means the pointer does not need to
+ *    be free-ed; the final parameter needs to be <NULL, 0>.
+ */
+int sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...);
+
+/**
+ * Function used to add a openat allowed filename to a supplied configuration.
+ * The (char*) specifies the path to the allowed file, fr = 1 tells the
+ * function that the char* needs to be free-ed, 0 means the pointer does not
+ * need to be free-ed.
+ */
+int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file,
+    int fr);
+
+/** Function used to add a series of openat allowed filenames to a supplied
+ * configuration.
+ *  @param cfg  sandbox configuration.
+ *  @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
+ *    the char* specifies the path to the allowed file, 1 tells the function
+ *    that the char* needs to be free-ed, 0 means the pointer does not need to
+ *    be free-ed; the final parameter needs to be <NULL, 0>.
+ */
+int sandbox_cfg_allow_openat_filename_array(sandbox_cfg_t **cfg, ...);
+
+/**
+ * Function used to add a execve allowed filename to a supplied configuration.
+ * The (char*) specifies the path to the allowed file, fr = 1 tells the
+ * function that the char* needs to be free-ed, 0 means the pointer does not
+ * need to be free-ed.
+ */
+int sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com);
+
+/** Function used to add a series of execve allowed filenames to a supplied
+ * configuration.
+ *  @param cfg  sandbox configuration.
+ *  @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
+ *    the char* specifies the path to the allowed file, 1 tells the function
+ *    that the char* needs to be free-ed, 0 means the pointer does not need to
+ *    be free-ed; the final parameter needs to be <NULL, 0>.
+ */
+int sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...);
+
+/**
+ * Function used to add a stat/stat64 allowed filename to a configuration.
+ * The (char*) specifies the path to the allowed file, fr = 1 tells the
+ * function that the char* needs to be free-ed, 0 means the pointer does not
+ * need to be free-ed.
+ */
+int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file,
+    int fr);
+
+/** Function used to add a series of stat64 allowed filenames to a supplied
+ * configuration.
+ *  @param cfg  sandbox configuration.
+ *  @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
+ *    the char* specifies the path to the allowed file, 1 tells the function
+ *    that the char* needs to be free-ed, 0 means the pointer does not need to
+ *    be free-ed; the final parameter needs to be <NULL, 0>.
+ */
+int sandbox_cfg_allow_stat_filename_array(sandbox_cfg_t **cfg, ...);
+
+/** Function used to initialise a sandbox configuration.*/
+int sandbox_init(sandbox_cfg_t* cfg);
 
 #endif /* SANDBOX_H_ */
 

+ 5 - 3
src/common/util.c

@@ -24,6 +24,7 @@
 #include "torint.h"
 #include "container.h"
 #include "address.h"
+#include "../common/sandbox.h"
 
 #ifdef _WIN32
 #include <io.h>
@@ -1799,7 +1800,7 @@ file_status(const char *fname)
   int r;
   f = tor_strdup(fname);
   clean_name_for_stat(f);
-  r = stat(f, &st);
+  r = stat(sandbox_intern_string(f), &st);
   tor_free(f);
   if (r) {
     if (errno == ENOENT) {
@@ -1849,7 +1850,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
   tor_assert(dirname);
   f = tor_strdup(dirname);
   clean_name_for_stat(f);
-  r = stat(f, &st);
+  r = stat(sandbox_intern_string(f), &st);
   tor_free(f);
   if (r) {
     if (errno != ENOENT) {
@@ -3039,6 +3040,7 @@ smartlist_t *
 tor_listdir(const char *dirname)
 {
   smartlist_t *result;
+  const char *prot_dname = sandbox_intern_string(dirname);
 #ifdef _WIN32
   char *pattern=NULL;
   TCHAR tpattern[MAX_PATH] = {0};
@@ -3082,7 +3084,7 @@ tor_listdir(const char *dirname)
 #else
   DIR *d;
   struct dirent *de;
-  if (!(d = opendir(dirname)))
+  if (!(d = opendir(prot_dname)))
     return NULL;
 
   result = smartlist_new();

+ 2 - 0
src/common/util.h

@@ -542,5 +542,7 @@ STATIC int format_helper_exit_status(unsigned char child_state,
 
 const char *libor_get_digests(void);
 
+#define ARRAY_LENGTH(x) (sizeof(x)) / sizeof(x[0])
+
 #endif
 

+ 2 - 1
src/or/config.c

@@ -6301,7 +6301,8 @@ remove_file_if_very_old(const char *fname, time_t now)
 #define VERY_OLD_FILE_AGE (28*24*60*60)
   struct stat st;
 
-  if (stat(fname, &st)==0 && st.st_mtime < now-VERY_OLD_FILE_AGE) {
+  if (stat(sandbox_intern_string(fname), &st)==0 &&
+      st.st_mtime < now-VERY_OLD_FILE_AGE) {
     char buf[ISO_TIME_LEN+1];
     format_local_iso_time(buf, st.st_mtime);
     log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. "

+ 11 - 4
src/or/dns.c

@@ -24,6 +24,7 @@
 #include "relay.h"
 #include "router.h"
 #include "ht.h"
+#include "../common/sandbox.h"
 #ifdef HAVE_EVENT2_DNS_H
 #include <event2/event.h>
 #include <event2/dns.h>
@@ -1443,13 +1444,14 @@ configure_nameservers(int force)
   const or_options_t *options;
   const char *conf_fname;
   struct stat st;
-  int r;
+  int r, flags;
   options = get_options();
   conf_fname = options->ServerDNSResolvConfFile;
 #ifndef _WIN32
   if (!conf_fname)
     conf_fname = "/etc/resolv.conf";
 #endif
+  flags = DNS_OPTIONS_ALL;
 
   if (!the_evdns_base) {
     if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) {
@@ -1477,7 +1479,7 @@ configure_nameservers(int force)
 
   evdns_set_log_fn(evdns_log_cb);
   if (conf_fname) {
-    if (stat(conf_fname, &st)) {
+    if (stat(sandbox_intern_string(conf_fname), &st)) {
       log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s",
                conf_fname, strerror(errno));
       goto err;
@@ -1491,9 +1493,14 @@ configure_nameservers(int force)
       evdns_base_search_clear(the_evdns_base);
       evdns_base_clear_nameservers_and_suspend(the_evdns_base);
     }
+    if (flags & DNS_OPTION_HOSTSFILE) {
+      flags ^= DNS_OPTION_HOSTSFILE;
+      evdns_base_load_hosts(the_evdns_base,
+          sandbox_intern_string("/etc/resolv.conf"));
+    }
     log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
-    if ((r = evdns_base_resolv_conf_parse(the_evdns_base,
-                                          DNS_OPTIONS_ALL, conf_fname))) {
+    if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags,
+        sandbox_intern_string(conf_fname)))) {
       log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)",
                conf_fname, conf_fname, r);
       goto err;

+ 98 - 1
src/or/main.c

@@ -2655,6 +2655,95 @@ find_flashcard_path(PWCHAR path, size_t size)
 }
 #endif
 
+static void
+init_addrinfo(void)
+{
+  char hname[256];
+
+  // host name to sandbox
+  gethostname(hname, sizeof(hname));
+  sandbox_add_addrinfo(hname);
+}
+
+static sandbox_cfg_t*
+sandbox_init_filter(void)
+{
+  sandbox_cfg_t *cfg = sandbox_cfg_new();
+
+  sandbox_cfg_allow_openat_filename(&cfg,
+      get_datadir_fname("cached-status"), 1);
+
+  sandbox_cfg_allow_open_filename_array(&cfg,
+      get_datadir_fname("cached-certs"), 1,
+      get_datadir_fname("cached-certs.tmp"), 1,
+      get_datadir_fname("cached-consensus"), 1,
+      get_datadir_fname("unverified-consensus"), 1,
+      get_datadir_fname("unverified-consensus.tmp"), 1,
+      get_datadir_fname("cached-microdesc-consensus"), 1,
+      get_datadir_fname("cached-microdesc-consensus.tmp"), 1,
+      get_datadir_fname("cached-microdescs"), 1,
+      get_datadir_fname("cached-microdescs.tmp"), 1,
+      get_datadir_fname("cached-microdescs.new"), 1,
+      get_datadir_fname("cached-microdescs.new.tmp"), 1,
+      get_datadir_fname("unverified-microdesc-consensus"), 1,
+      get_datadir_fname("cached-descriptors"), 1,
+      get_datadir_fname("cached-descriptors.new"), 1,
+      get_datadir_fname("cached-descriptors.tmp"), 1,
+      get_datadir_fname("cached-descriptors.new.tmp"), 1,
+      get_datadir_fname("cached-descriptors.tmp.tmp"), 1,
+      get_datadir_fname("cached-extrainfo"), 1,
+      get_datadir_fname("state.tmp"), 1,
+      get_datadir_fname("unparseable-desc.tmp"), 1,
+      get_datadir_fname("unparseable-desc"), 1,
+      "/dev/srandom", 0,
+      "/dev/urandom", 0,
+      "/dev/random", 0,
+      NULL, 0
+  );
+
+  sandbox_cfg_allow_stat_filename_array(&cfg,
+      get_datadir_fname(NULL), 1,
+      get_datadir_fname("lock"), 1,
+      get_datadir_fname("state"), 1,
+      get_datadir_fname("router-stability"), 1,
+      get_datadir_fname("cached-extrainfo.new"), 1,
+      NULL, 0
+  );
+
+  // orport
+  if (server_mode(get_options())) {
+    sandbox_cfg_allow_open_filename_array(&cfg,
+        get_datadir_fname2("keys", "secret_id_key"), 1,
+        get_datadir_fname2("keys", "secret_onion_key"), 1,
+        get_datadir_fname2("keys", "secret_onion_key_ntor"), 1,
+        get_datadir_fname2("keys", "secret_onion_key_ntor.tmp"), 1,
+        get_datadir_fname2("keys", "secret_id_key.old"), 1,
+        get_datadir_fname2("keys", "secret_onion_key.old"), 1,
+        get_datadir_fname2("keys", "secret_onion_key_ntor.old"), 1,
+        get_datadir_fname2("keys", "secret_onion_key.tmp"), 1,
+        get_datadir_fname2("keys", "secret_id_key.tmp"), 1,
+        get_datadir_fname("fingerprint"), 1,
+        get_datadir_fname("fingerprint.tmp"), 1,
+        get_datadir_fname("cached-consensus"), 1,
+        get_datadir_fname("cached-consensus.tmp"), 1,
+        "/etc/resolv.conf", 0,
+        NULL, 0
+    );
+
+    sandbox_cfg_allow_stat_filename_array(&cfg,
+        get_datadir_fname("keys"), 1,
+        get_datadir_fname("stats/dirreq-stats"), 1,
+        NULL, 0
+    );
+  }
+
+  sandbox_cfg_allow_execve(&cfg, "/usr/local/bin/tor");
+
+  init_addrinfo();
+
+  return cfg;
+}
+
 /** Main entry point for the Tor process.  Called from main(). */
 /* This function is distinct from main() only so we can link main.c into
  * the unittest binary without conflicting with the unittests' main. */
@@ -2723,10 +2812,18 @@ tor_main(int argc, char *argv[])
     return -1;
 
   if (get_options()->Sandbox) {
-    if (tor_global_sandbox()) {
+    sandbox_cfg_t* cfg = sandbox_init_filter();
+
+    if (sandbox_init(cfg)) {
       log_err(LD_BUG,"Failed to create syscall sandbox filter");
       return -1;
     }
+
+    // registering libevent rng
+#ifdef HAVE_EVUTIL_SECURE_RNG_SET_URANDOM_DEVICE_FILE
+    evutil_secure_rng_set_urandom_device_file(
+        (char*) sandbox_intern_string("/dev/urandom"));
+#endif
   }
 
   switch (get_options()->command) {

+ 1 - 1
src/or/routerlist.c

@@ -37,7 +37,7 @@
 #include "routerlist.h"
 #include "routerparse.h"
 #include "routerset.h"
-
+#include "../common/sandbox.h"
 // #define DEBUG_ROUTERLIST
 
 /****************************************************************************/

Some files were not shown because too many files changed in this diff