diff options
Diffstat (limited to 'src/shared/seccomp-util.c')
-rw-r--r-- | src/shared/seccomp-util.c | 62 |
1 files changed, 42 insertions, 20 deletions
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index fbb232cd45..220658b3ad 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -935,7 +935,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u /* If the system call is not known on this architecture, then that's fine, let's ignore it */ _cleanup_free_ char *n = NULL; - n = seccomp_syscall_resolve_num_arch(arch, PTR_TO_INT(id) - 1); + n = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", strna(n), PTR_TO_INT(id) - 1); } } @@ -950,13 +950,11 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u return 0; } -int seccomp_parse_syscall_filter_internal( - bool invert, +int seccomp_parse_syscall_filter_full( const char *name, int errno_num, Hashmap *filter, - bool whitelist, - bool warn, + SeccompParseFlags flags, const char *unit, const char *filename, unsigned line) { @@ -972,15 +970,20 @@ int seccomp_parse_syscall_filter_internal( set = syscall_filter_set_find(name); if (!set) { - if (warn) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown system call group, ignoring: %s", name); - return 0; - } else + if (!(flags & SECCOMP_PARSE_PERMISSIVE)) return -EINVAL; + + log_syntax(unit, flags & SECCOMP_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0, + "Unknown system call group, ignoring: %s", name); + return 0; } NULSTR_FOREACH(i, set->value) { - r = seccomp_parse_syscall_filter_internal(invert, i, errno_num, filter, whitelist, warn, unit, filename, line); + /* Call ourselves again, for the group to parse. Note that we downgrade logging here (i.e. take + * away the SECCOMP_PARSE_LOG flag) since any issues in the group table are our own problem, + * not a problem in user configuration data and we shouldn't pretend otherwise by complaining + * about them. */ + r = seccomp_parse_syscall_filter_full(i, errno_num, filter, flags &~ SECCOMP_PARSE_LOG, unit, filename, line); if (r < 0) return r; } @@ -989,19 +992,20 @@ int seccomp_parse_syscall_filter_internal( id = seccomp_syscall_resolve_name(name); if (id == __NR_SCMP_ERROR) { - if (warn) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", name); - return 0; - } else + if (!(flags & SECCOMP_PARSE_PERMISSIVE)) return -EINVAL; + + log_syntax(unit, flags & SECCOMP_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0, + "Failed to parse system call, ignoring: %s", name); + return 0; } /* If we previously wanted to forbid a syscall and now * we want to allow it, then remove it from the list. */ - if (!invert == whitelist) { + if (!(flags & SECCOMP_PARSE_INVERT) == !!(flags & SECCOMP_PARSE_WHITELIST)) { r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num)); if (r < 0) - return warn ? log_oom() : -ENOMEM; + return flags & SECCOMP_PARSE_LOG ? log_oom() : -ENOMEM; } else (void) hashmap_remove(filter, INT_TO_PTR(id + 1)); } @@ -1534,17 +1538,35 @@ int seccomp_restrict_archs(Set *archs) { int r; /* This installs a filter with no rules, but that restricts the system call architectures to the specified - * list. */ + * list. + * + * There are some qualifications. However the most important use is to stop processes from bypassing + * system call restrictions, in case they used a broader (multiplexing) syscall which is only available + * in a non-native architecture. There are no holes in this use case, at least so far. */ + /* Note libseccomp includes our "native" (current) architecture in the filter by default. + * We do not remove it. For example, our callers expect to be able to call execve() afterwards + * to run a program with the restrictions applied. */ seccomp = seccomp_init(SCMP_ACT_ALLOW); if (!seccomp) return -ENOMEM; SET_FOREACH(id, archs, i) { r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1); - if (r == -EEXIST) - continue; - if (r < 0) + if (r < 0 && r != -EEXIST) + return r; + } + + /* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32 + * x32 syscalls should basically match x86-64 for everything except the pointer type. + * The important thing is that you can block the old 32-bit x86 syscalls. + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */ + + if (seccomp_arch_native() == SCMP_ARCH_X32 || + set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1))) { + + r = seccomp_arch_add(seccomp, SCMP_ARCH_X86_64); + if (r < 0 && r != -EEXIST) return r; } |