ソースを参照

Make unix sockets work with the linux seccomp2 sandbox again

I didn't want to grant blanket permissions for chmod() and chown(),
so here's what I had to do:
   * Grant open() on all parent directories of a unix socket
   * Write code to allow chmod() and chown() on a given file only.
   * Grant chmod() and chown() on the unix socket.
Nick Mathewson 8 年 前
コミット
dd7c999617
4 ファイル変更108 行追加3 行削除
  1. 87 1
      src/common/sandbox.c
  2. 3 0
      src/common/sandbox.h
  3. 4 2
      src/or/connection.c
  4. 14 0
      src/or/main.c

+ 87 - 1
src/common/sandbox.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+ /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  * Copyright (c) 2007-2016, The Tor Project, Inc. */
@@ -438,6 +438,56 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
   return 0;
 }
 
+static int
+sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+  int rc;
+  sandbox_cfg_t *elem = NULL;
+
+  // for each dynamic parameter filters
+  for (elem = filter; elem != NULL; elem = elem->next) {
+    smp_param_t *param = elem->param;
+
+    if (param != NULL && param->prot == 1 && param->syscall
+        == SCMP_SYS(chmod)) {
+      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod),
+            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
+      if (rc != 0) {
+        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
+            "libseccomp error %d", rc);
+        return rc;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int
+sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+  int rc;
+  sandbox_cfg_t *elem = NULL;
+
+  // for each dynamic parameter filters
+  for (elem = filter; elem != NULL; elem = elem->next) {
+    smp_param_t *param = elem->param;
+
+    if (param != NULL && param->prot == 1 && param->syscall
+        == SCMP_SYS(chown)) {
+      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown),
+            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
+      if (rc != 0) {
+        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
+            "libseccomp error %d", rc);
+        return rc;
+      }
+    }
+  }
+
+  return 0;
+}
+
 static int
 sb__sysctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
 {
@@ -971,6 +1021,8 @@ static sandbox_filter_func_t filter_func[] = {
 #ifdef __NR_mmap2
     sb_mmap2,
 #endif
+    sb_chown,
+    sb_chmod,
     sb_open,
     sb_openat,
     sb__sysctl,
@@ -1246,6 +1298,40 @@ sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file)
   return 0;
 }
 
+int
+sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file)
+{
+  sandbox_cfg_t *elem = NULL;
+
+  elem = new_element(SCMP_SYS(chmod), file);
+  if (!elem) {
+    log_err(LD_BUG,"(Sandbox) failed to register parameter!");
+    return -1;
+  }
+
+  elem->next = *cfg;
+  *cfg = elem;
+
+  return 0;
+}
+
+int
+sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file)
+{
+  sandbox_cfg_t *elem = NULL;
+
+  elem = new_element(SCMP_SYS(chown), file);
+  if (!elem) {
+    log_err(LD_BUG,"(Sandbox) failed to register parameter!");
+    return -1;
+  }
+
+  elem->next = *cfg;
+  *cfg = elem;
+
+  return 0;
+}
+
 int
 sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
 {

+ 3 - 0
src/common/sandbox.h

@@ -149,6 +149,9 @@ sandbox_cfg_t * sandbox_cfg_new(void);
  */
 int sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file);
 
+int sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file);
+int sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file);
+
 /**DOCDOC*/
 int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2);
 

+ 4 - 2
src/or/connection.c

@@ -49,6 +49,7 @@
 #include "routerlist.h"
 #include "transports.h"
 #include "routerparse.h"
+#include "sandbox.h"
 #include "transports.h"
 
 #ifdef USE_BUFFEREVENTS
@@ -1291,7 +1292,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
       } else if (fstat(s, &st) == 0 &&
                  st.st_uid == pw->pw_uid && st.st_gid == pw->pw_gid) {
         /* No change needed */
-      } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) {
+      } else if (chown(sandbox_intern_string(address),
+                       pw->pw_uid, pw->pw_gid) < 0) {
         log_warn(LD_NET,"Unable to chown() %s socket: %s.",
                  address, strerror(errno));
         goto err;
@@ -1317,7 +1319,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
        * platforms. */
       if (fstat(s, &st) == 0 && (st.st_mode & 0777) == mode) {
         /* no change needed */
-      } else if (chmod(address, mode) < 0) {
+      } else if (chmod(sandbox_intern_string(address), mode) < 0) {
         log_warn(LD_FS,"Unable to make %s %s.", address, status);
         goto err;
       }

+ 14 - 0
src/or/main.c

@@ -3474,6 +3474,20 @@ sandbox_init_filter(void)
     }
   }
 
+  SMARTLIST_FOREACH_BEGIN(get_configured_ports(), port_cfg_t *, port) {
+    if (!port->is_unix_addr)
+      continue;
+    /* When we open an AF_UNIX address, we want permission to open the
+     * directory that holds it. */
+    char *dirname = tor_strdup(port->unix_addr);
+    if (get_parent_directory(dirname) == 0) {
+      OPEN(dirname);
+    }
+    tor_free(dirname);
+    sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr));
+    sandbox_cfg_allow_chown_filename(&cfg, tor_strdup(port->unix_addr));
+  } SMARTLIST_FOREACH_END(port);
+
   if (options->DirPortFrontPage) {
     sandbox_cfg_allow_open_filename(&cfg,
                                     tor_strdup(options->DirPortFrontPage));