commit dd7c99961774c19c6042100e660104c687ad6e22 Author: Nick Mathewson nickm@torproject.org Date: Mon Mar 14 14:07:02 2016 -0400
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. --- src/common/sandbox.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/common/sandbox.h | 3 ++ src/or/connection.c | 6 ++-- src/or/main.c | 14 +++++++++ 4 files changed, 108 insertions(+), 3 deletions(-)
diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 4e765b7..586d5fa 100644 --- a/src/common/sandbox.c +++ b/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. */ @@ -439,6 +439,56 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) }
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) { int rc; @@ -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, @@ -1247,6 +1299,40 @@ sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file) }
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) { sandbox_cfg_t *elem = NULL; diff --git a/src/common/sandbox.h b/src/common/sandbox.h index b4cc9f7..4918ad0 100644 --- a/src/common/sandbox.h +++ b/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);
diff --git a/src/or/connection.c b/src/or/connection.c index 2c135ca..19e4b41 100644 --- a/src/or/connection.c +++ b/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; } diff --git a/src/or/main.c b/src/or/main.c index cfd1169..5ba97a5 100644 --- a/src/or/main.c +++ b/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));
tor-commits@lists.torproject.org