commit: 746d68ae5972575d5fd87b7bd82e318d56352d9e Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> AuthorDate: Wed Nov 3 06:40:08 2021 +0000 Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> CommitDate: Wed Nov 3 06:40:08 2021 +0000 URL: https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=746d68ae
libsandbox: add YAMA checks and skip ptrace when active The YAMA ptrace_scope knob restricts access to different ptrace calls depending on the capabilities the current process holds. For now, do not try to ptrace processes when the YAMA level is incompatible with the capabilities that we have. This means we basically cannot protect against processes when they get into this state, so for now, we release them rather than abort. Bug: https://bugs.gentoo.org/771360 Bug: https://bugs.gentoo.org/821403 Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org> libsandbox/trace.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/libsandbox/trace.c b/libsandbox/trace.c index 2110a46..f3390d9 100644 --- a/libsandbox/trace.c +++ b/libsandbox/trace.c @@ -46,6 +46,26 @@ pid_t trace_pid; # define sb_openat_pre_check sb_openat64_pre_check #endif +static int trace_yama_level(void) +{ + char ch; + int fd; + + /* ptrace scope binds access to specific capabilities. Lets use uid==0 as a + * lazy proxy for "we have all capabilities" until we can refine this. + */ + if (getuid() == 0) + return 0; + + fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY | O_CLOEXEC); + if (fd == -1) + return 0; + + RETRY_EINTR(read(fd, &ch, 1)); + close(fd); + return ch - '0'; +} + static void trace_exit(int status) { /* if we were vfork-ed, clear trace_pid and exit */ @@ -526,6 +546,16 @@ static void trace_loop(void) sb_debug("following forking event %i; pid=%li %i\n", event, newpid, before_syscall); + /* If YAMA ptrace_scope is active, then we can't hand off the child + * to a new tracer. Give up. #821403 + */ + int yama = trace_yama_level(); + if (yama >= 1) { + sb_eqawarn("Unable to trace children due to YAMA ptrace_scope=%i\n", yama); + ptrace(PTRACE_DETACH, newpid, NULL, NULL); + continue; + } + /* Pipe for synchronizing detach & attach events. */ int fds[2]; ret = pipe(fds); @@ -674,6 +704,13 @@ static char *flatten_args(char *const argv[]) bool trace_possible(const char *filename, char *const argv[], const void *data) { + /* If YAMA ptrace_scope is very high, then we can't trace at all. #771360 */ + int yama = trace_yama_level(); + if (yama >= 2) { + sb_eqawarn("YAMA ptrace_scope=%i\n", yama); + goto fail; + } + if (_trace_possible(data)) { /* If we're in an environment like QEMU where ptrace doesn't work, then * don't try to use it. If ptrace does work, this should fail with ESRCH. @@ -683,6 +720,7 @@ bool trace_possible(const char *filename, char *const argv[], const void *data) return errno == ENOSYS ? false : true; } + fail: char *args = flatten_args(argv); sb_eqawarn("Unable to trace static ELF: %s: %s\n", filename, args); free(args);
