aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/handler/exception_handler.cc
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-08-27 13:18:49 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-08-27 13:18:49 +0000
commit662b6da59dd0218ea5496c085cb010d59f2b4219 (patch)
treeced5b72093c58391401745b04260db1376aef2f4 /src/client/linux/handler/exception_handler.cc
parentLimit the number of frames we try to walk to prevent runaway processors. (diff)
downloadbreakpad-662b6da59dd0218ea5496c085cb010d59f2b4219.tar.xz
Allow Linux dumper to work on PTRACE-hardened kernels
A=Chris Coulson <chris.coulson@canonical.com> R=nealsid at http://breakpad.appspot.com/166001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@673 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/linux/handler/exception_handler.cc')
-rw-r--r--src/client/linux/handler/exception_handler.cc60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index f3a7aa85..87cfa3a2 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -89,6 +89,11 @@
#include "common/linux/memory.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/guid_creator.h"
+#include "common/linux/eintr_wrapper.h"
+
+#ifndef PR_SET_PTRACER
+#define PR_SET_PTRACER 0x59616d61
+#endif
// A wrapper for the tgkill syscall: send a signal to a specific thread.
static int tgkill(pid_t tgid, pid_t tid, int sig) {
@@ -301,6 +306,11 @@ struct ThreadArgument {
// static
int ExceptionHandler::ThreadEntry(void *arg) {
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
+
+ // Block here until the crashing process unblocks us when
+ // we're allowed to use ptrace
+ thread_arg->handler->WaitForContinueSignal();
+
return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
thread_arg->context_size) == false;
}
@@ -355,14 +365,35 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
+ // We need to explicitly enable ptrace of parent processes on some
+ // kernels, but we need to know the PID of the cloned process before we
+ // can do this. Create a pipe here which we can use to block the
+ // cloned process after creating it, until we have explicitly enabled ptrace
+ if(sys_pipe(fdes) == -1) {
+ // Creating the pipe failed. We'll log an error but carry on anyway,
+ // as we'll probably still get a useful crash report. All that will happen
+ // is the write() and read() calls will fail with EBADF
+ static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \
+ sys_pipe failed:";
+ sys_write(2, no_pipe_msg, sizeof(no_pipe_msg) - 1);
+ sys_write(2, strerror(errno), strlen(strerror(errno)));
+ sys_write(2, "\n", 1);
+ }
+
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
&thread_arg, NULL, NULL, NULL);
int r, status;
+ // Allow the child to ptrace us
+ prctl(PR_SET_PTRACER, child, 0, 0, 0);
+ SendContinueSignalToChild();
do {
r = sys_waitpid(child, &status, __WALL);
} while (r == -1 && errno == EINTR);
+ sys_close(fdes[0]);
+ sys_close(fdes[1]);
+
if (r == -1) {
static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:";
sys_write(2, msg, sizeof(msg) - 1);
@@ -380,6 +411,35 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
}
// This function runs in a compromised context: see the top of the file.
+void ExceptionHandler::SendContinueSignalToChild() {
+ static const char okToContinueMessage = 'a';
+ int r;
+ r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
+ if(r == -1) {
+ static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \
+ sys_write failed:";
+ sys_write(2, msg, sizeof(msg) - 1);
+ sys_write(2, strerror(errno), strlen(strerror(errno)));
+ sys_write(2, "\n", 1);
+ }
+}
+
+// This function runs in a compromised context: see the top of the file.
+// Runs on the cloned process.
+void ExceptionHandler::WaitForContinueSignal() {
+ int r;
+ char receivedMessage;
+ r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
+ if(r == -1) {
+ static const char msg[] = "ExceptionHandler::WaitForContinueSignal \
+ sys_read failed:";
+ sys_write(2, msg, sizeof(msg) - 1);
+ sys_write(2, strerror(errno), strlen(strerror(errno)));
+ sys_write(2, "\n", 1);
+ }
+}
+
+// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {