From cc9e86db61e2ffb6c54b09e8c41e8fdad50b3ef3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 10 Apr 2014 15:44:52 -0400 Subject: Log a backtrace when the sandbox finds a failure This involves some duplicate code between backtrace.c and sandbox.c, but I don't see a way around it: calling more functions would mean adding more steps to our call stack, and running clean_backtrace() against the wrong point on the stack. --- src/common/backtrace.c | 18 ++++++++++++++++-- src/common/backtrace.h | 6 ++++++ src/common/sandbox.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) (limited to 'src/common') diff --git a/src/common/backtrace.c b/src/common/backtrace.c index 239c65782..3a073a8ff 100644 --- a/src/common/backtrace.c +++ b/src/common/backtrace.c @@ -5,7 +5,6 @@ #define _GNU_SOURCE 1 #include "orconfig.h" -#include "backtrace.h" #include "compat.h" #include "util.h" #include "torlog.h" @@ -31,6 +30,9 @@ #include #endif +#define EXPOSE_CLEAN_BACKTRACE +#include "backtrace.h" + #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) #define USE_BACKTRACE @@ -59,7 +61,7 @@ static tor_mutex_t cb_buf_mutex; * onto the stack. Fortunately, we usually have the program counter in the * ucontext_t structure. */ -static void +void clean_backtrace(void **stack, int depth, const ucontext_t *ctx) { #ifdef PC_FROM_UCONTEXT @@ -165,6 +167,18 @@ install_bt_handler(void) rv = -1; } } + + { + /* Now, generate (but do not log) a backtrace. This ensures that + * libc has pre-loaded the symbols we need to dump things, so that later + * reads won't be denied by the sandbox code */ + char **symbols; + int depth = backtrace(cb_buf, MAX_DEPTH); + symbols = backtrace_symbols(cb_buf, depth); + if (symbols) + free(symbols); + } + return rv; } diff --git a/src/common/backtrace.h b/src/common/backtrace.h index 765436fee..b1df28165 100644 --- a/src/common/backtrace.h +++ b/src/common/backtrace.h @@ -4,9 +4,15 @@ #ifndef TOR_BACKTRACE_H #define TOR_BACKTRACE_H +#include "orconfig.h" + void log_backtrace(int severity, int domain, const char *msg); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); +#ifdef EXPOSE_CLEAN_BACKTRACE +void clean_backtrace(void **stack, int depth, const ucontext_t *ctx); +#endif + #endif diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 0a7a129b5..0548f3edd 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -56,6 +56,17 @@ #include #include +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) +#define USE_BACKTRACE +#define EXPOSE_CLEAN_BACKTRACE +#include "backtrace.h" +#endif + +#ifdef USE_BACKTRACE +#include +#endif + /**Determines if at least one sandbox is active.*/ static int sandbox_active = 0; /** Holds the parameter list configuration for the sandbox.*/ @@ -1308,6 +1319,11 @@ install_syscall_filter(sandbox_cfg_t* cfg) return (rc < 0 ? -rc : rc); } +#ifdef USE_BACKTRACE +#define MAX_DEPTH 256 +static void *syscall_cb_buf[MAX_DEPTH]; +#endif + /** * Function called when a SIGSYS is caught by the application. It notifies the * user that an error has occurred and either terminates or allows the @@ -1319,6 +1335,12 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) ucontext_t *ctx = (ucontext_t *) (void_context); char number[32]; int syscall; +#ifdef USE_BACKTRACE + int depth; + int n_fds, i; + const int *fds = NULL; +#endif + (void) nr; if (info->si_code != SYS_SECCOMP) @@ -1329,12 +1351,25 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) syscall = (int) ctx->uc_mcontext.gregs[REG_SYSCALL]; +#ifdef USE_BACKTRACE + depth = backtrace(syscall_cb_buf, MAX_DEPTH); + /* Clean up the top stack frame so we get the real function + * name for the most recently failing function. */ + clean_backtrace(syscall_cb_buf, depth, ctx); +#endif + format_dec_number_sigsafe(syscall, number, sizeof(number)); tor_log_err_sigsafe("(Sandbox) Caught a bad syscall attempt (syscall ", number, ")\n", NULL); +#ifdef USE_BACKTRACE + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i=0; i < n_fds; ++i) + backtrace_symbols_fd(syscall_cb_buf, depth, fds[i]); +#endif + #if defined(DEBUGGING_CLOSE) _exit(1); #endif // DEBUGGING_CLOSE -- cgit v1.2.3