shared/seccomp: add seccomp_restrict_ptrace()
PTRACE_POKETEXT and PTRACE_POKEDATA use FOLL_FORCE to forcibly write into a tracee's memory. That includes executable read-only pages. If we restrict execution to trusted binaries PID 1 must enforce that it's impossible to abuse this to get untrusted code execution. Note, that usermodehelpers are not subject to PID 1's seccomp filters. Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h> /* IWYU pragma: keep */
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user