aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2014-04-10 15:44:52 -0400
committerNick Mathewson <nickm@torproject.org>2014-04-10 15:44:52 -0400
commitcc9e86db61e2ffb6c54b09e8c41e8fdad50b3ef3 (patch)
tree14a025fd59522d8c2baac100764d8a664756b587 /src/common
parent196895ed7ed1bd4c93c4c3cdd12893cfa4e4cc41 (diff)
downloadtor-cc9e86db61e2ffb6c54b09e8c41e8fdad50b3ef3.tar
tor-cc9e86db61e2ffb6c54b09e8c41e8fdad50b3ef3.tar.gz
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.
Diffstat (limited to 'src/common')
-rw-r--r--src/common/backtrace.c18
-rw-r--r--src/common/backtrace.h6
-rw-r--r--src/common/sandbox.c35
3 files changed, 57 insertions, 2 deletions
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 <ucontext.h>
#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 <time.h>
#include <poll.h>
+#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 <execinfo.h>
+#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