From 7461cd30676da62324271ddd7b7d347eeff40266 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 16 Nov 2017 12:44:47 -0500 Subject: [PATCH 1/4] Permit kill(pid, 0) in the seccomp2 sandbox. We don't want to allow general signals to be sent, but there's no problem sending a kill(0) to probe whether a process is there. Fixes bug 24198; bugfix on 0.2.5.1-alpha when the seccomp2 sandbox was introduced. --- changes/bug24198 | 4 ++++ src/common/sandbox.c | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 changes/bug24198 diff --git a/changes/bug24198 b/changes/bug24198 new file mode 100644 index 0000000000..6790706872 --- /dev/null +++ b/changes/bug24198 @@ -0,0 +1,4 @@ + o Minor bugfixes (controller, linux seccomp2 sandbox): + - Avoid a crash when attempting to use the seccomp2 sandbox + together with the OwningControllerProcess feature. + Fixes bug 24198; bugfix on 0.2.5.1-alpha. diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 7f4511db2a..0b862a549c 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -1050,6 +1050,19 @@ sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif +static int +sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + (void) filter; +#ifdef __NR_kill + /* Allow killing anything with signal 0 -- it isn't really a kill. */ + return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill), + SCMP_CMP(1, SCMP_CMP_EQ, 0)); +#else + return 0; +#endif +} + /** * Array of function pointers responsible for filtering different syscalls at * a parameter level. @@ -1088,7 +1101,8 @@ static sandbox_filter_func_t filter_func[] = { sb_socket, sb_setsockopt, sb_getsockopt, - sb_socketpair + sb_socketpair, + sb_kill }; const char * From d2d6a1b082fa0eac8b6478889a0c28bf05e48073 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 16 Nov 2017 13:53:48 -0500 Subject: [PATCH 2/4] Make our seccomp2 sandbox handle Glibc 2.26 There are three changes here: * We need to allow epoll_pwait. * We need to allow PF_NETLINK sockets to be opened with SOCK_CLOEXEC. * We need to use openat() instead of open(). Note that this fix is not complete, since the openat() change is turned off. The next commit will make the openat() change happen when we're running glibc 2.26 or later. Fix for 24315. --- src/common/sandbox.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 7f4511db2a..417c1e3051 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -127,6 +127,9 @@ static int filter_nopar_gen[] = { SCMP_SYS(clone), SCMP_SYS(epoll_create), SCMP_SYS(epoll_wait), +#ifdef __NR_epoll_pwait + SCMP_SYS(epoll_pwait), +#endif #ifdef HAVE_EVENTFD SCMP_SYS(eventfd2), #endif @@ -421,6 +424,21 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif +/** Allow a single file to be opened. If use_openat is true, + * we're using a libc that remaps all the opens into openats. */ +static int +allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file) +{ + if (use_openat) { + return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), + SCMP_CMP_STR(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); + } else { + return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), + SCMP_CMP_STR(0, SCMP_CMP_EQ, file)); + } +} + /** * Function responsible for setting up the open syscall for * the seccomp filter sandbox. @@ -437,8 +455,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) if (param != NULL && param->prot == 1 && param->syscall == SCMP_SYS(open)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); + rc = allow_file_open(ctx, 0 /* XXXX */, param->value); if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " "libseccomp error %d", rc); @@ -456,6 +473,15 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return rc; } + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(openat), + SCMP_CMP_MASKED(2, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW, + O_RDONLY)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " + "libseccomp error %d", rc); + return rc; + } + return 0; } @@ -645,7 +671,7 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter) rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK), - SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW), + SCMP_CMP_MASKED(1, SOCK_CLOEXEC, SOCK_RAW), SCMP_CMP(2, SCMP_CMP_EQ, 0)); if (rc) return rc; @@ -1616,7 +1642,8 @@ add_param_filter(scmp_filter_ctx ctx, sandbox_cfg_t* cfg) // function pointer for (i = 0; i < ARRAY_LENGTH(filter_func); i++) { - if ((filter_func[i])(ctx, cfg)) { + rc = filter_func[i](ctx, cfg); + if (rc) { log_err(LD_BUG,"(Sandbox) failed to add syscall %d, received libseccomp " "error %d", i, rc); return rc; From 2d3904aba67e79e57db1814033b1df3f77336065 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 16 Nov 2017 14:06:38 -0500 Subject: [PATCH 3/4] Check the libc version to decide whether to allow openat. --- configure.ac | 2 ++ src/common/sandbox.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f2c3f90baa..3ff8190521 100644 --- a/configure.ac +++ b/configure.ac @@ -390,6 +390,7 @@ AC_CHECK_FUNCS( getrlimit \ gettimeofday \ gmtime_r \ + gnu_get_libc_version \ htonll \ inet_aton \ ioctl \ @@ -1011,6 +1012,7 @@ AC_CHECK_HEADERS([assert.h \ arpa/inet.h \ crt_externs.h \ execinfo.h \ + gnu/libc-version.h \ grp.h \ ifaddrs.h \ inttypes.h \ diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 417c1e3051..d0ead2caec 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -56,6 +56,9 @@ #include #include +#ifdef HAVE_GNU_LIBC_VERSION_H +#include +#endif #ifdef HAVE_LINUX_NETFILTER_IPV4_H #include #endif @@ -424,6 +427,37 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif +#ifdef HAVE_GNU_LIBC_VERSION_H +#ifdef HAVE_GNU_GET_LIBC_VERSION +#define CHECK_LIBC_VERSION +#endif +#endif + +/* Return true if we think we're running with a libc that always uses + * openat on linux. */ +static int +libc_uses_openat_for_everything(void) +{ +#ifdef CHECK_LIBC_VERSION + const char *version = gnu_get_libc_version(); + if (version == NULL) + return 0; + + int major = -1; + int minor = -1; + + tor_sscanf(version, "%d.%d", &major, &minor); + if (major >= 3) + return 1; + else if (major == 2 && minor >= 26) + return 1; + else + return 0; +#else + return 0; +#endif +} + /** Allow a single file to be opened. If use_openat is true, * we're using a libc that remaps all the opens into openats. */ static int @@ -449,13 +483,15 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc; sandbox_cfg_t *elem = NULL; + int use_openat = libc_uses_openat_for_everything(); + // 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(open)) { - rc = allow_file_open(ctx, 0 /* XXXX */, param->value); + rc = allow_file_open(ctx, use_openat, param->value); if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " "libseccomp error %d", rc); From 80bf270404a52c634a14f6aad594dec4e9ce1e12 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 16 Nov 2017 14:07:58 -0500 Subject: [PATCH 4/4] Add a changes file. --- changes/ticket24315 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket24315 diff --git a/changes/ticket24315 b/changes/ticket24315 new file mode 100644 index 0000000000..df34dbf412 --- /dev/null +++ b/changes/ticket24315 @@ -0,0 +1,3 @@ + o Major features (linux seccomp2 sandbox): + - Update the sandbox rules so that they should now work correctly with + Glibc 2.26. Closes ticket 24315.