diff options
-rw-r--r-- | changes/bug18253 | 3 | ||||
-rw-r--r-- | src/common/sandbox.c | 88 | ||||
-rw-r--r-- | src/common/sandbox.h | 3 | ||||
-rw-r--r-- | src/or/connection.c | 13 | ||||
-rw-r--r-- | src/or/main.c | 14 |
5 files changed, 118 insertions, 3 deletions
diff --git a/changes/bug18253 b/changes/bug18253 new file mode 100644 index 0000000000..56bc701780 --- /dev/null +++ b/changes/bug18253 @@ -0,0 +1,3 @@ + o Minor bugfixes (linux seccomp2 sandbox): + - Fix the sandbox's interoprability with unix sockets under setuid. + Fixes bug 18253; bugfix on 0.2.8.1-alpha. diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 69d2b4dd26..b07af6bd2a 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. */ @@ -448,6 +448,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; @@ -980,6 +1030,8 @@ static sandbox_filter_func_t filter_func[] = { #ifdef __NR_mmap2 sb_mmap2, #endif + sb_chown, + sb_chmod, sb_open, sb_openat, sb__sysctl, @@ -1256,6 +1308,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 b4cc9f7d18..4918ad047b 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 4e915f1213..9c8dcdebb9 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 @@ -1287,11 +1288,16 @@ connection_listener_new(const struct sockaddr *listensockaddr, #ifdef HAVE_PWD_H if (options->User) { pw = tor_getpwnam(options->User); + struct stat st; if (pw == NULL) { log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.", address, options->User); goto err; - } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) { + } else if (fstat(s, &st) == 0 && + st.st_uid == pw->pw_uid && st.st_gid == pw->pw_gid) { + /* No change needed */ + } 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; @@ -1302,6 +1308,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, { unsigned mode; const char *status; + struct stat st; if (port_cfg->is_world_writable) { mode = 0666; status = "world-writable"; @@ -1314,7 +1321,9 @@ connection_listener_new(const struct sockaddr *listensockaddr, } /* We need to use chmod; fchmod doesn't work on sockets on all * platforms. */ - if (chmod(address, mode) < 0) { + if (fstat(s, &st) == 0 && (st.st_mode & 0777) == mode) { + /* no change needed */ + } 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 f37c23c9f5..00768ac18f 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -3482,6 +3482,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)); |