commit dd7c99961774c19c6042100e660104c687ad6e22
Author: Nick Mathewson <nickm(a)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));