diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/condition.c | 28 | ||||
-rw-r--r-- | src/shared/install.c | 99 | ||||
-rw-r--r-- | src/shared/install.h | 34 | ||||
-rw-r--r-- | src/shared/seccomp-util.c | 351 | ||||
-rw-r--r-- | src/shared/seccomp-util.h | 39 | ||||
-rw-r--r-- | src/shared/switch-root.c | 25 |
6 files changed, 412 insertions, 164 deletions
diff --git a/src/shared/condition.c b/src/shared/condition.c index f13fa6a9fd..8bd6a51a99 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -146,25 +146,24 @@ static int condition_test_virtualization(Condition *c) { assert(c->parameter); assert(c->type == CONDITION_VIRTUALIZATION); + if (streq(c->parameter, "private-users")) + return running_in_userns(); + v = detect_virtualization(); if (v < 0) return v; /* First, compare with yes/no */ b = parse_boolean(c->parameter); - - if (v > 0 && b > 0) - return true; - - if (v == 0 && b == 0) - return true; + if (b >= 0) + return b == !!v; /* Then, compare categorization */ - if (VIRTUALIZATION_IS_VM(v) && streq(c->parameter, "vm")) - return true; + if (streq(c->parameter, "vm")) + return VIRTUALIZATION_IS_VM(v); - if (VIRTUALIZATION_IS_CONTAINER(v) && streq(c->parameter, "container")) - return true; + if (streq(c->parameter, "container")) + return VIRTUALIZATION_IS_CONTAINER(v); /* Finally compare id */ return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v)); @@ -329,9 +328,9 @@ static int condition_test_needs_update(Condition *c) { uint64_t timestamp; int r; - r = parse_env_file(p, NULL, "TimestampNSec", ×tamp_str, NULL); + r = parse_env_file(p, NULL, "TIMESTAMP_NSEC", ×tamp_str, NULL); if (r < 0) { - log_error_errno(-r, "Failed to parse timestamp file '%s', using mtime: %m", p); + log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); return true; } else if (r == 0) { log_debug("No data in timestamp file '%s', using mtime", p); @@ -340,12 +339,11 @@ static int condition_test_needs_update(Condition *c) { r = safe_atou64(timestamp_str, ×tamp); if (r < 0) { - log_error_errno(-r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", - timestamp_str, p); + log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p); return true; } - other.st_mtim.tv_nsec = timestamp % NSEC_PER_SEC; + timespec_store(&other.st_mtim, timestamp); } return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec; diff --git a/src/shared/install.c b/src/shared/install.c index 21cb57bc5a..474426d927 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -518,6 +518,7 @@ static int remove_marked_symlinks_fd( const char *path, const char *config_path, const LookupPaths *lp, + bool dry_run, bool *restart, UnitFileChange **changes, unsigned *n_changes) { @@ -566,7 +567,7 @@ static int remove_marked_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes); if (q < 0 && r == 0) r = q; @@ -603,14 +604,16 @@ static int remove_marked_symlinks_fd( if (!found) continue; - if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - unit_file_changes_add(changes, n_changes, -errno, p, NULL); - continue; - } + if (!dry_run) { + if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { + if (r == 0) + r = -errno; + unit_file_changes_add(changes, n_changes, -errno, p, NULL); + continue; + } - (void) rmdir_parents(p, config_path); + (void) rmdir_parents(p, config_path); + } unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); @@ -621,7 +624,7 @@ static int remove_marked_symlinks_fd( q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); if (q < 0) return q; - if (q > 0) + if (q > 0 && !dry_run) *restart = true; } } @@ -633,6 +636,7 @@ static int remove_marked_symlinks( Set *remove_symlinks_to, const char *config_path, const LookupPaths *lp, + bool dry_run, UnitFileChange **changes, unsigned *n_changes) { @@ -659,7 +663,7 @@ static int remove_marked_symlinks( return -errno; /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes); if (r == 0) r = q; } while (restart); @@ -1805,10 +1809,9 @@ static int install_context_mark_for_removal( int unit_file_mask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1824,7 +1827,7 @@ int unit_file_mask( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; @@ -1840,7 +1843,7 @@ int unit_file_mask( if (!path) return -ENOMEM; - q = create_symlink(&paths, "/dev/null", path, force, changes, n_changes); + q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -1850,7 +1853,7 @@ int unit_file_mask( int unit_file_unmask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, @@ -1862,6 +1865,7 @@ int unit_file_unmask( size_t n_todo = 0, n_allocated = 0; const char *config_path; char **i; + bool dry_run; int r, q; assert(scope >= 0); @@ -1871,7 +1875,8 @@ int unit_file_unmask( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + dry_run = !!(flags & UNIT_FILE_DRY_RUN); STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; @@ -1908,7 +1913,7 @@ int unit_file_unmask( if (!path) return -ENOMEM; - if (unlink(path) < 0) { + if (!dry_run && unlink(path) < 0) { if (errno != ENOENT) { if (r >= 0) r = -errno; @@ -1926,7 +1931,7 @@ int unit_file_unmask( return q; } - q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); if (r >= 0) r = q; @@ -1935,10 +1940,9 @@ int unit_file_unmask( int unit_file_link( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1956,7 +1960,7 @@ int unit_file_link( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { _cleanup_free_ char *full = NULL; @@ -2005,7 +2009,7 @@ int unit_file_link( if (!new_path) return -ENOMEM; - q = create_symlink(&paths, *i, new_path, force, changes, n_changes); + q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -2177,11 +2181,11 @@ int unit_file_revert( return q; } - q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes); if (r >= 0) r = q; - q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes); if (r >= 0) r = q; @@ -2190,12 +2194,11 @@ int unit_file_revert( int unit_file_add_dependency( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2220,7 +2223,7 @@ int unit_file_add_dependency( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info, changes, n_changes); @@ -2260,15 +2263,14 @@ int unit_file_add_dependency( return -ENOMEM; } - return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } int unit_file_enable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2286,7 +2288,7 @@ int unit_file_enable( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(f, files) { r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, @@ -2305,12 +2307,12 @@ int unit_file_enable( is useful to determine whether the passed files had any installation data at all. */ - return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes); } int unit_file_disable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, @@ -2330,7 +2332,7 @@ int unit_file_disable( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) @@ -2345,15 +2347,14 @@ int unit_file_disable( if (r < 0) return r; - return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); + return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); } int unit_file_reenable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2368,19 +2369,19 @@ int unit_file_reenable( n[i] = basename(files[i]); n[i] = NULL; - r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); + r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes); if (r < 0) return r; /* But the enable command with the full name */ - return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); + return unit_file_enable(scope, flags, root_dir, files, changes, n_changes); } int unit_file_set_default( UnitFileScope scope, + UnitFileFlags flags, const char *root_dir, const char *name, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2411,7 +2412,7 @@ int unit_file_set_default( return r; new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - return create_symlink(&paths, i->path, new_path, force, changes, n_changes); + return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } int unit_file_get_default( @@ -2735,7 +2736,7 @@ static int execute_preset( if (r < 0) return r; - r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes); + r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes); } else r = 0; @@ -2803,11 +2804,10 @@ static int preset_prepare_one( int unit_file_preset( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2826,7 +2826,7 @@ int unit_file_preset( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = read_presets(scope, root_dir, &presets); if (r < 0) @@ -2838,15 +2838,14 @@ int unit_file_preset( return r; } - return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } int unit_file_preset_all( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2865,7 +2864,7 @@ int unit_file_preset_all( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = read_presets(scope, root_dir, &presets); if (r < 0) @@ -2906,7 +2905,7 @@ int unit_file_preset_all( } } - return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } static void unit_file_list_free_one(UnitFileList *f) { diff --git a/src/shared/install.h b/src/shared/install.h index b1f220693b..7a5859e729 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -23,6 +23,7 @@ typedef enum UnitFileScope UnitFileScope; typedef enum UnitFileState UnitFileState; typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFileChangeType UnitFileChangeType; +typedef enum UnitFileFlags UnitFileFlags; typedef enum UnitFileType UnitFileType; typedef struct UnitFileChange UnitFileChange; typedef struct UnitFileList UnitFileList; @@ -78,6 +79,12 @@ enum UnitFileChangeType { _UNIT_FILE_CHANGE_INVALID = INT_MIN }; +enum UnitFileFlags { + UNIT_FILE_RUNTIME = 1, + UNIT_FILE_FORCE = 1 << 1, + UNIT_FILE_DRY_RUN = 1 << 2, +}; + /* type can either one of the UnitFileChangeTypes listed above, or a negative error. * If source is specified, it should be the contents of the path symlink. * In case of an error, source should be the existing symlink contents or NULL @@ -144,65 +151,59 @@ bool unit_type_may_template(UnitType type) _const_; int unit_file_enable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_disable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_reenable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset_all( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_mask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_unmask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_link( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_revert( @@ -213,9 +214,9 @@ int unit_file_revert( unsigned *n_changes); int unit_file_set_default( UnitFileScope scope, + UnitFileFlags flags, const char *root_dir, const char *file, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_get_default( @@ -224,12 +225,11 @@ int unit_file_get_default( char **name); int unit_file_add_dependency( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, - bool force, UnitFileChange **changes, unsigned *n_changes); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 8116c7671f..c9b24f1065 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -26,25 +26,52 @@ #include "macro.h" #include "seccomp-util.h" #include "string-util.h" +#include "util.h" const char* seccomp_arch_to_string(uint32_t c) { + /* Maintain order used in <seccomp.h>. + * + * Names used here should be the same as those used for ConditionArchitecture=, + * except for "subarchitectures" like x32. */ - if (c == SCMP_ARCH_NATIVE) + switch(c) { + case SCMP_ARCH_NATIVE: return "native"; - if (c == SCMP_ARCH_X86) + case SCMP_ARCH_X86: return "x86"; - if (c == SCMP_ARCH_X86_64) + case SCMP_ARCH_X86_64: return "x86-64"; - if (c == SCMP_ARCH_X32) + case SCMP_ARCH_X32: return "x32"; - if (c == SCMP_ARCH_ARM) + case SCMP_ARCH_ARM: return "arm"; - if (c == SCMP_ARCH_S390) + case SCMP_ARCH_AARCH64: + return "arm64"; + case SCMP_ARCH_MIPS: + return "mips"; + case SCMP_ARCH_MIPS64: + return "mips64"; + case SCMP_ARCH_MIPS64N32: + return "mips64-n32"; + case SCMP_ARCH_MIPSEL: + return "mips-le"; + case SCMP_ARCH_MIPSEL64: + return "mips64-le"; + case SCMP_ARCH_MIPSEL64N32: + return "mips64-le-n32"; + case SCMP_ARCH_PPC: + return "ppc"; + case SCMP_ARCH_PPC64: + return "ppc64"; + case SCMP_ARCH_PPC64LE: + return "ppc64-le"; + case SCMP_ARCH_S390: return "s390"; - if (c == SCMP_ARCH_S390X) + case SCMP_ARCH_S390X: return "s390x"; - - return NULL; + default: + return NULL; + } } int seccomp_arch_from_string(const char *n, uint32_t *ret) { @@ -63,6 +90,26 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) { *ret = SCMP_ARCH_X32; else if (streq(n, "arm")) *ret = SCMP_ARCH_ARM; + else if (streq(n, "arm64")) + *ret = SCMP_ARCH_AARCH64; + else if (streq(n, "mips")) + *ret = SCMP_ARCH_MIPS; + else if (streq(n, "mips64")) + *ret = SCMP_ARCH_MIPS64; + else if (streq(n, "mips64-n32")) + *ret = SCMP_ARCH_MIPS64N32; + else if (streq(n, "mips-le")) + *ret = SCMP_ARCH_MIPSEL; + else if (streq(n, "mips64-le")) + *ret = SCMP_ARCH_MIPSEL64; + else if (streq(n, "mips64-le-n32")) + *ret = SCMP_ARCH_MIPSEL64N32; + else if (streq(n, "ppc")) + *ret = SCMP_ARCH_PPC; + else if (streq(n, "ppc64")) + *ret = SCMP_ARCH_PPC64; + else if (streq(n, "ppc64-le")) + *ret = SCMP_ARCH_PPC64LE; else if (streq(n, "s390")) *ret = SCMP_ARCH_S390; else if (streq(n, "s390x")) @@ -73,44 +120,81 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) { return 0; } -int seccomp_add_secondary_archs(scmp_filter_ctx *c) { - -#if defined(__i386__) || defined(__x86_64__) +int seccomp_init_conservative(scmp_filter_ctx *ret, uint32_t default_action) { + scmp_filter_ctx seccomp; int r; - /* Add in all possible secondary archs we are aware of that - * this kernel might support. */ + /* Much like seccomp_init(), but tries to be a bit more conservative in its defaults: all secondary archs are + * added by default, and NNP is turned off. */ - r = seccomp_arch_add(c, SCMP_ARCH_X86); - if (r < 0 && r != -EEXIST) - return r; + seccomp = seccomp_init(default_action); + if (!seccomp) + return -ENOMEM; - r = seccomp_arch_add(c, SCMP_ARCH_X86_64); - if (r < 0 && r != -EEXIST) - return r; + r = seccomp_add_secondary_archs(seccomp); + if (r < 0) + goto finish; - r = seccomp_arch_add(c, SCMP_ARCH_X32); - if (r < 0 && r != -EEXIST) - return r; + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; -#elif defined(__s390__) || defined(__s390x__) - int r; + *ret = seccomp; + return 0; + +finish: + seccomp_release(seccomp); + return r; +} + +int seccomp_add_secondary_archs(scmp_filter_ctx ctx) { /* Add in all possible secondary archs we are aware of that * this kernel might support. */ - r = seccomp_arch_add(c, SCMP_ARCH_S390); - if (r < 0 && r != -EEXIST) - return r; + static const int seccomp_arches[] = { +#if defined(__i386__) || defined(__x86_64__) + SCMP_ARCH_X86, + SCMP_ARCH_X86_64, + SCMP_ARCH_X32, - r = seccomp_arch_add(c, SCMP_ARCH_S390X); - if (r < 0 && r != -EEXIST) - return r; +#elif defined(__arm__) || defined(__aarch64__) + SCMP_ARCH_ARM, + SCMP_ARCH_AARCH64, + +#elif defined(__arm__) || defined(__aarch64__) + SCMP_ARCH_ARM, + SCMP_ARCH_AARCH64, + +#elif defined(__mips__) || defined(__mips64__) + SCMP_ARCH_MIPS, + SCMP_ARCH_MIPS64, + SCMP_ARCH_MIPS64N32, + SCMP_ARCH_MIPSEL, + SCMP_ARCH_MIPSEL64, + SCMP_ARCH_MIPSEL64N32, +#elif defined(__powerpc__) || defined(__powerpc64__) + SCMP_ARCH_PPC, + SCMP_ARCH_PPC64, + SCMP_ARCH_PPC64LE, + +#elif defined(__s390__) || defined(__s390x__) + SCMP_ARCH_S390, + SCMP_ARCH_S390X, #endif + }; - return 0; + unsigned i; + int r; + for (i = 0; i < ELEMENTSOF(seccomp_arches); i++) { + r = seccomp_arch_add(ctx, seccomp_arches[i]); + if (r < 0 && r != -EEXIST) + return r; + } + + return 0; } static bool is_basic_seccomp_available(void) { @@ -132,28 +216,48 @@ bool is_seccomp_available(void) { return cached_enabled; } -const SystemCallFilterSet syscall_filter_sets[] = { - { +const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { + [SYSCALL_FILTER_SET_BASIC_IO] = { + /* Basic IO */ + .name = "@basic-io", + .value = + "close\0" + "dup2\0" + "dup3\0" + "dup\0" + "lseek\0" + "pread64\0" + "preadv\0" + "pwrite64\0" + "pwritev\0" + "read\0" + "readv\0" + "write\0" + "writev\0" + }, + [SYSCALL_FILTER_SET_CLOCK] = { /* Clock */ - .set_name = "@clock", + .name = "@clock", .value = "adjtimex\0" "clock_adjtime\0" "clock_settime\0" "settimeofday\0" "stime\0" - }, { + }, + [SYSCALL_FILTER_SET_CPU_EMULATION] = { /* CPU emulation calls */ - .set_name = "@cpu-emulation", + .name = "@cpu-emulation", .value = "modify_ldt\0" "subpage_prot\0" "switch_endian\0" "vm86\0" "vm86old\0" - }, { + }, + [SYSCALL_FILTER_SET_DEBUG] = { /* Debugging/Performance Monitoring/Tracing */ - .set_name = "@debug", + .name = "@debug", .value = "lookup_dcookie\0" "perf_event_open\0" @@ -161,21 +265,32 @@ const SystemCallFilterSet syscall_filter_sets[] = { "process_vm_writev\0" "ptrace\0" "rtas\0" +#ifdef __NR_s390_runtime_instr "s390_runtime_instr\0" +#endif "sys_debug_setcontext\0" - }, { - /* Default list */ - .set_name = "@default", + }, + [SYSCALL_FILTER_SET_DEFAULT] = { + /* Default list: the most basic of operations */ + .name = "@default", .value = + "clock_getres\0" + "clock_gettime\0" + "clock_nanosleep\0" "execve\0" "exit\0" "exit_group\0" "getrlimit\0" /* make sure processes can query stack size and such */ + "gettimeofday\0" + "nanosleep\0" + "pause\0" "rt_sigreturn\0" "sigreturn\0" - }, { + "time\0" + }, + [SYSCALL_FILTER_SET_IO_EVENT] = { /* Event loop use */ - .set_name = "@io-event", + .name = "@io-event", .value = "_newselect\0" "epoll_create1\0" @@ -191,10 +306,12 @@ const SystemCallFilterSet syscall_filter_sets[] = { "ppoll\0" "pselect6\0" "select\0" - }, { - /* Message queues, SYSV IPC or other IPC: unusual */ - .set_name = "@ipc", + }, + [SYSCALL_FILTER_SET_IPC] = { + /* Message queues, SYSV IPC or other IPC */ + .name = "@ipc", .value = "ipc\0" + "memfd_create\0" "mq_getsetattr\0" "mq_notify\0" "mq_open\0" @@ -205,6 +322,8 @@ const SystemCallFilterSet syscall_filter_sets[] = { "msgget\0" "msgrcv\0" "msgsnd\0" + "pipe2\0" + "pipe\0" "process_vm_readv\0" "process_vm_writev\0" "semctl\0" @@ -215,33 +334,36 @@ const SystemCallFilterSet syscall_filter_sets[] = { "shmctl\0" "shmdt\0" "shmget\0" - }, { + }, + [SYSCALL_FILTER_SET_KEYRING] = { /* Keyring */ - .set_name = "@keyring", + .name = "@keyring", .value = "add_key\0" "keyctl\0" "request_key\0" - }, { + }, + [SYSCALL_FILTER_SET_MODULE] = { /* Kernel module control */ - .set_name = "@module", + .name = "@module", .value = "delete_module\0" "finit_module\0" "init_module\0" - }, { + }, + [SYSCALL_FILTER_SET_MOUNT] = { /* Mounting */ - .set_name = "@mount", + .name = "@mount", .value = "chroot\0" "mount\0" - "oldumount\0" "pivot_root\0" "umount2\0" "umount\0" - }, { + }, + [SYSCALL_FILTER_SET_NETWORK_IO] = { /* Network or Unix socket IO, should not be needed if not network facing */ - .set_name = "@network-io", + .name = "@network-io", .value = "accept4\0" "accept\0" @@ -264,9 +386,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "socket\0" "socketcall\0" "socketpair\0" - }, { + }, + [SYSCALL_FILTER_SET_OBSOLETE] = { /* Unusual, obsolete or unimplemented, some unknown even to libseccomp */ - .set_name = "@obsolete", + .name = "@obsolete", .value = "_sysctl\0" "afs_syscall\0" @@ -292,9 +415,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "uselib\0" "ustat\0" "vserver\0" - }, { + }, + [SYSCALL_FILTER_SET_PRIVILEGED] = { /* Nice grab-bag of all system calls which need superuser capabilities */ - .set_name = "@privileged", + .name = "@privileged", .value = "@clock\0" "@module\0" @@ -331,15 +455,15 @@ const SystemCallFilterSet syscall_filter_sets[] = { "setuid\0" "swapoff\0" "swapon\0" - "sysctl\0" + "_sysctl\0" "vhangup\0" - }, { + }, + [SYSCALL_FILTER_SET_PROCESS] = { /* Process control, execution, namespaces */ - .set_name = "@process", + .name = "@process", .value = "arch_prctl\0" "clone\0" - "execve\0" "execveat\0" "fork\0" "kill\0" @@ -349,19 +473,106 @@ const SystemCallFilterSet syscall_filter_sets[] = { "tkill\0" "unshare\0" "vfork\0" - }, { + }, + [SYSCALL_FILTER_SET_RAW_IO] = { /* Raw I/O ports */ - .set_name = "@raw-io", + .name = "@raw-io", .value = "ioperm\0" "iopl\0" "pciconfig_iobase\0" "pciconfig_read\0" "pciconfig_write\0" +#ifdef __NR_s390_pci_mmio_read "s390_pci_mmio_read\0" +#endif +#ifdef __NR_s390_pci_mmio_write "s390_pci_mmio_write\0" - }, { - .set_name = NULL, - .value = NULL - } +#endif + }, + [SYSCALL_FILTER_SET_RESOURCES] = { + /* Alter resource settings */ + .name = "@resources", + .value = + "sched_setparam\0" + "sched_setscheduler\0" + "sched_setaffinity\0" + "setpriority\0" + "setrlimit\0" + "set_mempolicy\0" + "migrate_pages\0" + "move_pages\0" + "mbind\0" + "sched_setattr\0" + "prlimit64\0" + }, }; + +const SyscallFilterSet *syscall_filter_set_find(const char *name) { + unsigned i; + + if (isempty(name) || name[0] != '@') + return NULL; + + for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) + if (streq(syscall_filter_sets[i].name, name)) + return syscall_filter_sets + i; + + return NULL; +} + +int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action) { + const char *sys; + int r; + + assert(seccomp); + assert(set); + + NULSTR_FOREACH(sys, set->value) { + int id; + + if (sys[0] == '@') { + const SyscallFilterSet *other; + + other = syscall_filter_set_find(sys); + if (!other) + return -EINVAL; + + r = seccomp_add_syscall_filter_set(seccomp, other, action); + } else { + id = seccomp_syscall_resolve_name(sys); + if (id == __NR_SCMP_ERROR) + return -EINVAL; + + r = seccomp_rule_add(seccomp, action, id, 0); + } + if (r < 0) + return r; + } + + return 0; +} + +int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action) { + scmp_filter_ctx seccomp; + int r; + + assert(set); + + /* The one-stop solution: allocate a seccomp object, add a filter to it, and apply it */ + + r = seccomp_init_conservative(&seccomp, default_action); + if (r < 0) + return r; + + r = seccomp_add_syscall_filter_set(seccomp, set, action); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; + +} diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index cca7c17912..8e209efef2 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -20,18 +20,47 @@ ***/ #include <seccomp.h> +#include <stdbool.h> #include <stdint.h> const char* seccomp_arch_to_string(uint32_t c); int seccomp_arch_from_string(const char *n, uint32_t *ret); -int seccomp_add_secondary_archs(scmp_filter_ctx *c); +int seccomp_init_conservative(scmp_filter_ctx *ret, uint32_t default_action); + +int seccomp_add_secondary_archs(scmp_filter_ctx c); bool is_seccomp_available(void); -typedef struct SystemCallFilterSet { - const char *set_name; +typedef struct SyscallFilterSet { + const char *name; const char *value; -} SystemCallFilterSet; +} SyscallFilterSet; + +enum { + SYSCALL_FILTER_SET_BASIC_IO, + SYSCALL_FILTER_SET_CLOCK, + SYSCALL_FILTER_SET_CPU_EMULATION, + SYSCALL_FILTER_SET_DEBUG, + SYSCALL_FILTER_SET_DEFAULT, + SYSCALL_FILTER_SET_IO_EVENT, + SYSCALL_FILTER_SET_IPC, + SYSCALL_FILTER_SET_KEYRING, + SYSCALL_FILTER_SET_MODULE, + SYSCALL_FILTER_SET_MOUNT, + SYSCALL_FILTER_SET_NETWORK_IO, + SYSCALL_FILTER_SET_OBSOLETE, + SYSCALL_FILTER_SET_PRIVILEGED, + SYSCALL_FILTER_SET_PROCESS, + SYSCALL_FILTER_SET_RAW_IO, + SYSCALL_FILTER_SET_RESOURCES, + _SYSCALL_FILTER_SET_MAX +}; + +extern const SyscallFilterSet syscall_filter_sets[]; + +const SyscallFilterSet *syscall_filter_set_find(const char *name); + +int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action); -extern const SystemCallFilterSet syscall_filter_sets[]; +int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action); diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index 47d3a5a1fa..4eff4f692e 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -75,17 +75,29 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, NULSTR_FOREACH(i, move_mounts) { char new_mount[PATH_MAX]; struct stat sb; + size_t n; - xsprintf(new_mount, "%s%s", new_root, i); + n = snprintf(new_mount, sizeof new_mount, "%s%s", new_root, i); + if (n >= sizeof new_mount) { + bool move = mountflags & MS_MOVE; + + log_warning("New path is too long, %s: %s%s", + move ? "forcing unmount instead" : "ignoring", + new_root, i); + + if (move) + if (umount2(i, MNT_FORCE) < 0) + log_warning_errno(errno, "Failed to unmount %s: %m", i); + continue; + } mkdir_p_label(new_mount, 0755); - if ((stat(new_mount, &sb) < 0) || + if (stat(new_mount, &sb) < 0 || sb.st_dev != new_root_stat.st_dev) { /* Mount point seems to be mounted already or - * stat failed. Unmount the old mount - * point. */ + * stat failed. Unmount the old mount point. */ if (umount2(i, MNT_DETACH) < 0) log_warning_errno(errno, "Failed to unmount %s: %m", i); continue; @@ -97,10 +109,9 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, if (umount2(i, MNT_FORCE) < 0) log_warning_errno(errno, "Failed to unmount %s: %m", i); - } - if (mountflags & MS_BIND) - log_error_errno(errno, "Failed to bind mount %s to %s: %m", i, new_mount); + } else if (mountflags & MS_BIND) + log_error_errno(errno, "Failed to bind mount %s to %s: %m", i, new_mount); } } |