Merge "Override SIGSYS during profiling signal handler"
diff --git a/libc/bionic/android_profiling_dynamic.cpp b/libc/bionic/android_profiling_dynamic.cpp
index 183a614..54f896c 100644
--- a/libc/bionic/android_profiling_dynamic.cpp
+++ b/libc/bionic/android_profiling_dynamic.cpp
@@ -36,6 +36,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/ucontext.h>
#include <sys/un.h>
#include <async_safe/log.h>
@@ -64,10 +65,10 @@
sigaction(BIONIC_SIGNAL_PROFILER, &action, nullptr);
}
+static void HandleSigsysSeccompOverride(int, siginfo_t*, void*);
static void HandleTracedPerfSignal();
static void HandleProfilingSignal(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
- // Avoid clobbering errno.
ErrnoRestorer errno_restorer;
if (info->si_code != SI_QUEUE) {
@@ -86,6 +87,21 @@
return;
}
+ // Temporarily override SIGSYS handling, in a best-effort attempt at not
+ // crashing if we happen to be running in a process with a seccomp filter that
+ // disallows some of the syscalls done by this signal handler. This protects
+ // against SECCOMP_RET_TRAP with a crashing SIGSYS handler (typical of android
+ // minijails). Won't help if the filter is using SECCOMP_RET_KILL_*.
+ // Note: the override is process-wide, but short-lived. The syscalls are still
+ // blocked, but the overridden handler recovers from SIGSYS, and fakes the
+ // syscall return value as ENOSYS.
+ struct sigaction sigsys_override = {};
+ sigsys_override.sa_sigaction = &HandleSigsysSeccompOverride;
+ sigsys_override.sa_flags = SA_SIGINFO;
+
+ struct sigaction old_act = {};
+ sigaction(SIGSYS, &sigsys_override, &old_act);
+
if (signal_value == kHeapprofdSignalValue) {
HandleHeapprofdSignal();
} else if (signal_value == kTracedPerfSignalValue) {
@@ -94,6 +110,7 @@
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "unrecognized profiling signal si_value: %d",
signal_value);
}
+ sigaction(SIGSYS, &old_act, nullptr);
}
// Open /proc/self/{maps,mem}, connect to traced_perf, send the fds over the
@@ -150,3 +167,33 @@
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to sendmsg: %s", strerror(errno));
}
}
+
+static void HandleSigsysSeccompOverride(int /*signal_number*/, siginfo_t* info,
+ void* void_context) {
+ ErrnoRestorer errno_restorer;
+ if (info->si_code != SYS_SECCOMP) {
+ return;
+ }
+
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+ "Profiling setup: trapped seccomp SIGSYS for syscall %d. Returning ENOSYS to caller.",
+ info->si_syscall);
+
+ // The handler is responsible for setting the return value as if the system
+ // call happened (which is arch-specific). Use a plausible unsuccessful value.
+ auto ret = -ENOSYS;
+ ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+
+#if defined(__arm__)
+ ctx->uc_mcontext.arm_r0 = ret;
+#elif defined(__aarch64__)
+ ctx->uc_mcontext.regs[0] = ret; // x0
+#elif defined(__i386__)
+ ctx->uc_mcontext.gregs[REG_EAX] = ret;
+#elif defined(__x86_64__)
+ ctx->uc_mcontext.gregs[REG_RAX] = ret;
+#else
+#error "unsupported architecture"
+#endif
+}