Loading changes/bug40020 0 → 100644 +9 −0 Original line number Diff line number Diff line o Minor bugfixes (linux seccomp2 sandbox): - Makes the seccomp sandbox allow the correct syscall for opendir according to the running glibc version. The opendir function either uses open or openat but the current code does not differenciate between opendir and open calls. This adds a new seccomp sandbox rule for opendir. This fixes crashes when reloading torrc with sandbox enabled when running on glibc 2.15 to 2.21 and 2.26. Patch from Daniel Pinto. Fixes bug 40020; bugfix on 0.3.5.11. src/app/main/main.c +11 −4 Original line number Diff line number Diff line Loading @@ -822,6 +822,9 @@ sandbox_init_filter(void) #define OPEN(name) \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name)) #define OPENDIR(dir) \ sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir)) #define OPEN_DATADIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name)) Loading @@ -839,7 +842,7 @@ sandbox_init_filter(void) } while (0) #define OPEN_KEY_DIRECTORY() \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory)) OPENDIR(options->KeyDirectory) #define OPEN_CACHEDIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name)) #define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \ Loading @@ -853,7 +856,7 @@ sandbox_init_filter(void) OPEN_KEYDIR(name suffix); \ } while (0) OPEN(options->DataDirectory); OPENDIR(options->DataDirectory); OPEN_KEY_DIRECTORY(); OPEN_CACHEDIR_SUFFIX("cached-certs", ".tmp"); Loading Loading @@ -900,7 +903,11 @@ sandbox_init_filter(void) } SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, { if (file_status(f) == FN_DIR) { OPENDIR(f); } else { OPEN(f); } }); #define RENAME_SUFFIX(name, suffix) \ Loading Loading @@ -1013,7 +1020,7 @@ sandbox_init_filter(void) * directory that holds it. */ char *dirname = tor_strdup(port->unix_addr); if (get_parent_directory(dirname) == 0) { OPEN(dirname); OPENDIR(dirname); } tor_free(dirname); sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr)); Loading src/lib/sandbox/sandbox.c +73 −4 Original line number Diff line number Diff line Loading @@ -289,6 +289,12 @@ static int filter_nopar_gen[] = { SCMP_SYS(poll) }; /* opendir is not a syscall but it will use either open or openat. We do not * want the decision to allow open/openat to be the callers reponsability, so * we create a phony syscall number for opendir and sb_opendir will choose the * correct syscall. */ #define PHONY_OPENDIR_SYSCALL -2 /* These macros help avoid the error where the number of filters we add on a * single rule don't match the arg_cnt param. */ #define seccomp_rule_add_0(ctx,act,call) \ Loading Loading @@ -469,14 +475,24 @@ is_libc_at_least(int major, int minor) #endif /* defined(CHECK_LIBC_VERSION) */ } /* Return true if we think we're running with a libc that always uses * openat on linux. */ /* Return true if we think we're running with a libc that uses openat for the * open function on linux. */ static int libc_uses_openat_for_everything(void) libc_uses_openat_for_open(void) { return is_libc_at_least(2, 26); } /* Return true if we think we're running with a libc that uses openat for the * opendir function on linux. */ static int libc_uses_openat_for_opendir(void) { // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) return is_libc_at_least(2, 27) || (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); } /* Return true if we think we're running with a libc that needs to cast * negative arguments like AT_FDCWD for seccomp rules. */ static int Loading Loading @@ -510,7 +526,7 @@ 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(); int use_openat = libc_uses_openat_for_open(); // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { Loading Loading @@ -643,6 +659,38 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } static int sb_opendir(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 == PHONY_OPENDIR_SYSCALL) { if (libc_uses_openat_for_opendir()) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE| O_DIRECTORY|O_CLOEXEC)); } else { rc = allow_file_open(ctx, 0, param->value); } if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " "libseccomp error %d", rc); return rc; } } } return 0; } /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. Loading Loading @@ -1157,6 +1205,7 @@ static sandbox_filter_func_t filter_func[] = { sb_chmod, sb_open, sb_openat, sb_opendir, sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, Loading Loading @@ -1476,6 +1525,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) { sandbox_cfg_t *elem = NULL; elem = new_element(PHONY_OPENDIR_SYSCALL, dir); elem->next = *cfg; *cfg = elem; return 0; } /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. Loading Loading @@ -1803,6 +1865,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) { (void)cfg; (void)dir; return 0; } int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) { Loading src/lib/sandbox/sandbox.h +7 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2); */ int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file); /** * Function used to add a opendir allowed filename to a supplied configuration. * The (char*) specifies the path to the allowed dir; we steal the pointer to * that dir. */ int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir); /** * Function used to add a stat/stat64 allowed filename to a configuration. * The (char*) specifies the path to the allowed file; that pointer is stolen. Loading Loading
changes/bug40020 0 → 100644 +9 −0 Original line number Diff line number Diff line o Minor bugfixes (linux seccomp2 sandbox): - Makes the seccomp sandbox allow the correct syscall for opendir according to the running glibc version. The opendir function either uses open or openat but the current code does not differenciate between opendir and open calls. This adds a new seccomp sandbox rule for opendir. This fixes crashes when reloading torrc with sandbox enabled when running on glibc 2.15 to 2.21 and 2.26. Patch from Daniel Pinto. Fixes bug 40020; bugfix on 0.3.5.11.
src/app/main/main.c +11 −4 Original line number Diff line number Diff line Loading @@ -822,6 +822,9 @@ sandbox_init_filter(void) #define OPEN(name) \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name)) #define OPENDIR(dir) \ sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir)) #define OPEN_DATADIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name)) Loading @@ -839,7 +842,7 @@ sandbox_init_filter(void) } while (0) #define OPEN_KEY_DIRECTORY() \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory)) OPENDIR(options->KeyDirectory) #define OPEN_CACHEDIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name)) #define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \ Loading @@ -853,7 +856,7 @@ sandbox_init_filter(void) OPEN_KEYDIR(name suffix); \ } while (0) OPEN(options->DataDirectory); OPENDIR(options->DataDirectory); OPEN_KEY_DIRECTORY(); OPEN_CACHEDIR_SUFFIX("cached-certs", ".tmp"); Loading Loading @@ -900,7 +903,11 @@ sandbox_init_filter(void) } SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, { if (file_status(f) == FN_DIR) { OPENDIR(f); } else { OPEN(f); } }); #define RENAME_SUFFIX(name, suffix) \ Loading Loading @@ -1013,7 +1020,7 @@ sandbox_init_filter(void) * directory that holds it. */ char *dirname = tor_strdup(port->unix_addr); if (get_parent_directory(dirname) == 0) { OPEN(dirname); OPENDIR(dirname); } tor_free(dirname); sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr)); Loading
src/lib/sandbox/sandbox.c +73 −4 Original line number Diff line number Diff line Loading @@ -289,6 +289,12 @@ static int filter_nopar_gen[] = { SCMP_SYS(poll) }; /* opendir is not a syscall but it will use either open or openat. We do not * want the decision to allow open/openat to be the callers reponsability, so * we create a phony syscall number for opendir and sb_opendir will choose the * correct syscall. */ #define PHONY_OPENDIR_SYSCALL -2 /* These macros help avoid the error where the number of filters we add on a * single rule don't match the arg_cnt param. */ #define seccomp_rule_add_0(ctx,act,call) \ Loading Loading @@ -469,14 +475,24 @@ is_libc_at_least(int major, int minor) #endif /* defined(CHECK_LIBC_VERSION) */ } /* Return true if we think we're running with a libc that always uses * openat on linux. */ /* Return true if we think we're running with a libc that uses openat for the * open function on linux. */ static int libc_uses_openat_for_everything(void) libc_uses_openat_for_open(void) { return is_libc_at_least(2, 26); } /* Return true if we think we're running with a libc that uses openat for the * opendir function on linux. */ static int libc_uses_openat_for_opendir(void) { // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) return is_libc_at_least(2, 27) || (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); } /* Return true if we think we're running with a libc that needs to cast * negative arguments like AT_FDCWD for seccomp rules. */ static int Loading Loading @@ -510,7 +526,7 @@ 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(); int use_openat = libc_uses_openat_for_open(); // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { Loading Loading @@ -643,6 +659,38 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } static int sb_opendir(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 == PHONY_OPENDIR_SYSCALL) { if (libc_uses_openat_for_opendir()) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE| O_DIRECTORY|O_CLOEXEC)); } else { rc = allow_file_open(ctx, 0, param->value); } if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " "libseccomp error %d", rc); return rc; } } } return 0; } /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. Loading Loading @@ -1157,6 +1205,7 @@ static sandbox_filter_func_t filter_func[] = { sb_chmod, sb_open, sb_openat, sb_opendir, sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, Loading Loading @@ -1476,6 +1525,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) { sandbox_cfg_t *elem = NULL; elem = new_element(PHONY_OPENDIR_SYSCALL, dir); elem->next = *cfg; *cfg = elem; return 0; } /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. Loading Loading @@ -1803,6 +1865,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) { (void)cfg; (void)dir; return 0; } int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) { Loading
src/lib/sandbox/sandbox.h +7 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2); */ int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file); /** * Function used to add a opendir allowed filename to a supplied configuration. * The (char*) specifies the path to the allowed dir; we steal the pointer to * that dir. */ int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir); /** * Function used to add a stat/stat64 allowed filename to a configuration. * The (char*) specifies the path to the allowed file; that pointer is stolen. Loading