From dbc8d2a4e476c06f59db3ff79b66afc8bc4ea27c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 12 Nov 2020 11:55:55 -0500 Subject: [PATCH 1/3] When handling includes, detect missing interned strings earlier. There were three separate places where we were hitting a sandbox Bug warning before we actually exited. Fixes #40094; bugfix on 0.3.1.1-alpha when %includes were introduced. --- src/lib/fs/conffile.c | 27 +++++++++++++++++++++------ src/lib/sandbox/sandbox.c | 37 ++++++++++++++++++++++++++++++++++--- src/lib/sandbox/sandbox.h | 5 ++--- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index f1f6d8ae5f..1f58a3590c 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -19,6 +19,7 @@ #include "lib/fs/path.h" #include "lib/log/log.h" #include "lib/malloc/malloc.h" +#include "lib/sandbox/sandbox.h" #include "lib/string/printf.h" #include @@ -59,14 +60,14 @@ config_get_lines_include(const char *string, config_line_t **result, static smartlist_t * expand_glob(const char *pattern, smartlist_t *opened_files) { - smartlist_t *matches = tor_glob(pattern); - if (!matches) { - return NULL; + if (! has_glob(pattern)) { + smartlist_t *matches = smartlist_new(); + smartlist_add_strdup(matches, pattern); + return matches; } - // if it is not a glob, return error when the path is missing - if (!has_glob(pattern) && smartlist_len(matches) == 0) { - smartlist_free(matches); + smartlist_t *matches = tor_glob(pattern); + if (!matches) { return NULL; } @@ -107,6 +108,13 @@ config_get_file_list(const char *pattern, smartlist_t *opened_files) if (opened_files) { smartlist_add_strdup(opened_files, path); } + if (sandbox_interned_string_is_missing(path)) { + log_err(LD_CONFIG, "Sandbox is active, but a new configuration " + "file \"%s\" has been listed with %%include. Cannot proceed.", + path); + error_found = true; + break; + } file_status_t file_type = file_status(path); if (file_type == FN_FILE) { @@ -201,6 +209,13 @@ config_process_include(const char *pattern, int recursion_level, int extended, int rv = -1; SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { + if (sandbox_interned_string_is_missing(config_file)) { + log_err(LD_CONFIG, "Sandbox is active, but a new configuration " + "file \"%s\" has been listed with %%include. Cannot proceed.", + config_file); + goto done; + } + log_notice(LD_CONFIG, "Including configuration file \"%s\".", config_file); config_line_t *included_config = NULL; config_line_t *included_config_last = NULL; diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 8d467c516e..d9ad8ec2c6 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -310,6 +310,8 @@ static int filter_nopar_gen[] = { #define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4) \ seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4)) +static const char *sandbox_get_interned_string(const char *str); + /** * Function responsible for setting up the rt_sigaction syscall for * the seccomp filter sandbox. @@ -1224,8 +1226,39 @@ static sandbox_filter_func_t filter_func[] = { sb_kill }; +/** + * Return the interned (and hopefully sandbox-permitted) string equal + * to @a str. + */ const char * sandbox_intern_string(const char *str) +{ + const char *interned = sandbox_get_interned_string(str); + + if (sandbox_active && str != NULL && interned == NULL) { + log_warn(LD_BUG, "No interned sandbox parameter found for %s", str); + } + + return interned ? interned : str; +} + +/** + * Return true if the sandbox is running and we are missing an interned string + * equal to @a str. + */ +bool +sandbox_interned_string_is_missing(const char *str) +{ + return sandbox_active && sandbox_get_interned_string(str) == NULL; +} + +/** + * Try to find and return the interned string equal to @a str. + * + * If there is no such string, return NULL. + **/ +static const char * +sandbox_get_interned_string(const char *str) { sandbox_cfg_t *elem; @@ -1245,9 +1278,7 @@ sandbox_intern_string(const char *str) } } - if (sandbox_active) - log_warn(LD_BUG, "No interned sandbox parameter found for %s", str); - return str; + return NULL; } /* DOCDOC */ diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h index a2b3227b90..eba99afbde 100644 --- a/src/lib/sandbox/sandbox.h +++ b/src/lib/sandbox/sandbox.h @@ -104,12 +104,11 @@ typedef struct { #endif /* defined(USE_LIBSECCOMP) */ #ifdef USE_LIBSECCOMP -/** Returns a registered protected string used with the sandbox, given that - * it matches the parameter. - */ const char* sandbox_intern_string(const char *param); +bool sandbox_interned_string_is_missing(const char *s); #else /* !defined(USE_LIBSECCOMP) */ #define sandbox_intern_string(s) (s) +#define sandbox_interned_string_is_missing(s) (false) #endif /* defined(USE_LIBSECCOMP) */ /** Creates an empty sandbox configuration file.*/ From baef0843a424116026f3f97185dae89271903041 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 8 Dec 2020 14:59:28 -0500 Subject: [PATCH 2/3] Fix a couple of documentation comments related to #40094 --- src/lib/fs/conffile.c | 8 ++++---- src/lib/sandbox/sandbox.c | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index 1f58a3590c..acd8dfb8cc 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -53,10 +53,10 @@ config_get_lines_include(const char *string, config_line_t **result, opened_lst, 1, NULL, config_process_include); } -/** Returns a list of paths obtained when expading globs in pattern. If - * pattern has no globs, returns a list with pattern if it is an - * existing path or NULL otherwise. If opened_files is provided, adds - * paths opened by glob to it. Returns NULL on failure. */ +/** Return a list of paths obtained when expading globs in pattern. + * If pattern has no globs, return a list with pattern in it. + * If opened_files is provided, add paths opened by glob to it. + * Return NULL on failure. */ static smartlist_t * expand_glob(const char *pattern, smartlist_t *opened_files) { diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index d9ad8ec2c6..168dfd943c 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -1229,7 +1229,9 @@ static sandbox_filter_func_t filter_func[] = { /** * Return the interned (and hopefully sandbox-permitted) string equal * to @a str. - */ + * + * Return NULL if `str` is NULL, or `str` is not an interned string. + **/ const char * sandbox_intern_string(const char *str) { From bd0046c9ec5bf6556d4ecf6b111b0de4c0266ebd Mon Sep 17 00:00:00 2001 From: Daniel Pinto Date: Fri, 13 Nov 2020 01:08:56 +0000 Subject: [PATCH 3/3] Avoid sandbox bug warning when unglobbing patterns #40094 Adds a more user-friendly error message when the configuration is reloaded and a new %include is added that makes its unglobbing access files/folders not allowed by the seccomp sandbox. --- src/lib/fs/conffile.c | 6 ++++++ src/lib/fs/path.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index acd8dfb8cc..0d0bdf09a6 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -23,6 +23,7 @@ #include "lib/string/printf.h" #include +#include static smartlist_t *config_get_file_list(const char *path, smartlist_t *opened_files); @@ -68,6 +69,11 @@ expand_glob(const char *pattern, smartlist_t *opened_files) smartlist_t *matches = tor_glob(pattern); if (!matches) { + if (errno == EPERM) { + log_err(LD_CONFIG, "Sandbox is active, but the configuration pattern " + "\"%s\" listed with %%include would access files or folders not " + "allowed by it. Cannot proceed.", pattern); + } return NULL; } diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c index 2eef4bded7..af421d0413 100644 --- a/src/lib/fs/path.c +++ b/src/lib/fs/path.c @@ -537,6 +537,10 @@ unglob_win32(const char *pattern, int prev_sep, int next_sep) static DIR * prot_opendir(const char *name) { + if (sandbox_interned_string_is_missing(name)) { + errno = EPERM; + return NULL; + } return opendir(sandbox_intern_string(name)); } @@ -544,6 +548,10 @@ prot_opendir(const char *name) static int prot_stat(const char *pathname, struct stat *buf) { + if (sandbox_interned_string_is_missing(pathname)) { + errno = EPERM; + return -1; + } return stat(sandbox_intern_string(pathname), buf); } @@ -551,6 +559,10 @@ prot_stat(const char *pathname, struct stat *buf) static int prot_lstat(const char *pathname, struct stat *buf) { + if (sandbox_interned_string_is_missing(pathname)) { + errno = EPERM; + return -1; + } return lstat(sandbox_intern_string(pathname), buf); } /** As closedir, but has the right type for gl_closedir */ @@ -563,7 +575,8 @@ wrap_closedir(void *arg) /** Return a new list containing the paths that match the pattern * pattern. Return NULL on error. On POSIX systems, errno is set by the - * glob function. + * glob function or is set to EPERM if glob tried to access a file not allowed + * by the seccomp sandbox. */ struct smartlist_t * tor_glob(const char *pattern)