diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 0a0471bcb1..c7663417f7 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -9,6 +9,7 @@ #include #include #include /* IWYU pragma: keep */ +#include #include #include @@ -2152,6 +2153,47 @@ int seccomp_filter_set_add(Hashmap *filter, bool add, const SyscallFilterSet *se return 0; } +/* Block PTRACE_POKE{TEXT,DATA} FOLL_FORCE writes. A missing filter is a bypass, so unlike the other helpers + * this fails when the native architecture cannot be filtered. A secondary architecture the kernel refuses a + * filter for is skipped as everywhere else: it cannot run binaries either. */ +int seccomp_restrict_ptrace(void) { + uint32_t arch; + int r; + + r = dlopen_libseccomp(LOG_DEBUG); + if (r < 0) + return r; + + SECCOMP_FOREACH_LOCAL_ARCH(arch) { + _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; + + r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW); + if (r < 0) + return r; + + r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(ptrace), + 1, SCMP_A0(SCMP_CMP_EQ, PTRACE_POKETEXT)); + if (r < 0) + return r; + + r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(ptrace), + 1, SCMP_A0(SCMP_CMP_EQ, PTRACE_POKEDATA)); + if (r < 0) + return r; + + r = sym_seccomp_load(seccomp); + if (r < 0) { + if (ERRNO_IS_NEG_SECCOMP_FATAL(r) || arch == sym_seccomp_arch_native()) + return log_debug_errno(r, "Failed to apply ptrace restrictions for architecture %s: %m", + seccomp_arch_to_string(arch)); + log_debug_errno(r, "Failed to apply ptrace restrictions for architecture %s, skipping: %m", + seccomp_arch_to_string(arch)); + } + } + + return 0; +} + int seccomp_lock_personality(unsigned long personality) { uint32_t arch; int r; diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 699d819ecc..20f30d88c7 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -122,6 +122,7 @@ static inline int seccomp_restrict_realtime(void) { return seccomp_restrict_realtime_full(EPERM); } int seccomp_memory_deny_write_execute(void); +int seccomp_restrict_ptrace(void); int seccomp_lock_personality(unsigned long personality); int seccomp_protect_hostname(void); int seccomp_restrict_suid_sgid(void); @@ -166,6 +167,10 @@ static inline bool is_seccomp_available(void) { return false; } +static inline int seccomp_restrict_ptrace(void) { + return -EOPNOTSUPP; +} + #endif int dlopen_libseccomp(int log_level) _dlopen_loader_;