summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorglider@chromium.org <glider@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-23 14:39:45 +0000
committerglider@chromium.org <glider@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-23 14:39:45 +0000
commita83291d61f1e36f773e59303f55de9b3e9599470 (patch)
tree9f6fd49c92eeb815b9f5cd74f4c3f0985682949d
parenta27065b54c973b8b568e201878fe1fac68e568a8 (diff)
downloadchromium_src-a83291d61f1e36f773e59303f55de9b3e9599470.zip
chromium_src-a83291d61f1e36f773e59303f55de9b3e9599470.tar.gz
chromium_src-a83291d61f1e36f773e59303f55de9b3e9599470.tar.bz2
Breakpad support for ASan: take 2.
This is an updated version of https://chromiumcodereview.appspot.com/10703116/ which got reverted. When the code is built with ASan, Chrome should register a callback which notifies the browser about a memory error. The error report message is passed to the crash handler and is then sent to the crash server along with the minidump. BUG=143657 Review URL: https://chromiumcodereview.appspot.com/10860006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152989 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/breakpad_linux.cc120
-rw-r--r--chrome/app/breakpad_linux.h8
-rw-r--r--chrome/browser/crash_handler_host_linux.cc42
-rw-r--r--chrome/browser/crash_handler_host_linux.h4
4 files changed, 152 insertions, 22 deletions
diff --git a/chrome/app/breakpad_linux.cc b/chrome/app/breakpad_linux.cc
index 11dbbe9..18bac08 100644
--- a/chrome/app/breakpad_linux.cc
+++ b/chrome/app/breakpad_linux.cc
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <poll.h>
+#include <signal.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -54,6 +55,10 @@
#include "sandbox/linux/seccomp-legacy/linux_syscall_support.h"
#endif
+#if defined(ADDRESS_SANITIZER)
+#include <ucontext.h> // for getcontext().
+#endif
+
#if defined(OS_ANDROID)
#define STAT_STRUCT struct stat
#define FSTAT_FUNC fstat
@@ -73,12 +78,21 @@ using google_breakpad::MinidumpDescriptor;
namespace {
+#if !defined(ADDRESS_SANITIZER)
const char kUploadURL[] = "https://clients2.google.com/cr/report";
+#else
+// AddressSanitizer should currently upload the crash reports to the staging
+// crash server.
+const char kUploadURL[] = "https://clients2.google.com/cr/staging_report";
+#endif
bool g_is_crash_reporter_enabled = false;
uint64_t g_process_start_time = 0;
char* g_crash_log_path = NULL;
ExceptionHandler* g_breakpad = NULL;
+#if defined(ADDRESS_SANITIZER)
+const char* g_asan_report_str = NULL;
+#endif
// Writes the value |v| as 16 hex characters to the memory pointed at by
// |output|.
@@ -171,6 +185,9 @@ const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
const char g_quote_msg[] = "\"";
const char g_dashdash_msg[] = "--";
const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
+#if defined(ADDRESS_SANITIZER)
+const char g_log_msg[] = "upload_file_log\"; filename=\"log\"";
+#endif
const char g_content_type_msg[] = "Content-Type: application/octet-stream";
// MimeWriter manages an iovec for writing MIMEs to a file.
@@ -210,10 +227,10 @@ class MimeWriter {
size_t chunk_size,
bool strip_trailing_spaces);
- // Add binary file dump. Currently this is only done once, so the name is
- // fixed.
- void AddFileDump(uint8_t* file_data,
- size_t file_size);
+ // Add binary file contents to be uploaded with the specified filename.
+ void AddFileContents(const char* filename_msg,
+ uint8_t* file_data,
+ size_t file_size);
// Flush any pending iovecs to the output file.
void Flush() {
@@ -312,10 +329,10 @@ void MimeWriter::AddPairDataInChunks(const char* msg_type,
}
}
-void MimeWriter::AddFileDump(uint8_t* file_data,
- size_t file_size) {
+void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data,
+ size_t file_size) {
AddString(g_form_data_msg);
- AddString(g_dump_msg);
+ AddString(filename_msg);
AddString(g_rn);
AddString(g_content_type_msg);
AddString(g_rn);
@@ -372,6 +389,15 @@ bool CrashDone(const MinidumpDescriptor& minidump,
BreakpadInfo info;
info.filename = minidump.path();
+#if defined(ADDRESS_SANITIZER)
+ google_breakpad::PageAllocator allocator;
+ const size_t log_path_len = my_strlen(minidump.path());
+ char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1));
+ my_memcpy(log_path, minidump.path(), log_path_len);
+ my_memcpy(log_path + log_path_len - 4, ".log", 4);
+ log_path[log_path_len] = '\0';
+ info.log_filename = log_path;
+#endif
info.process_type = "browser";
info.process_type_length = 7;
info.crash_url = NULL;
@@ -404,6 +430,18 @@ bool CrashDoneUpload(const MinidumpDescriptor& minidump,
}
#endif
+#if defined(ADDRESS_SANITIZER)
+extern "C"
+void __asan_set_error_report_callback(void (*cb)(const char*));
+
+extern "C"
+void AsanLinuxBreakpadCallback(const char* report) {
+ g_asan_report_str = report;
+ // Send minidump here.
+ g_breakpad->SimulateSignalDelivery(SIGKILL);
+}
+#endif
+
void EnableCrashDumping(bool unattended) {
g_is_crash_reporter_enabled = true;
@@ -483,7 +521,12 @@ bool NonBrowserCrashHandler(const void* crash_context,
static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize);
static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize);
+#if !defined(ADDRESS_SANITIZER)
const size_t kIovSize = 8;
+#else
+ // Additional field to pass the AddressSanitizer log to the crash handler.
+ const size_t kIovSize = 9;
+#endif
struct kernel_msghdr msg;
my_memset(&msg, 0, sizeof(struct kernel_msghdr));
struct kernel_iovec iov[kIovSize];
@@ -503,6 +546,10 @@ bool NonBrowserCrashHandler(const void* crash_context,
iov[6].iov_len = sizeof(g_process_start_time);
iov[7].iov_base = &base::g_oom_size;
iov[7].iov_len = sizeof(base::g_oom_size);
+#if defined(ADDRESS_SANITIZER)
+ iov[8].iov_base = const_cast<char*>(g_asan_report_str);
+ iov[8].iov_len = kMaxAsanReportSize + 1;
+#endif
msg.msg_iov = iov;
msg.msg_iovlen = kIovSize;
@@ -551,40 +598,59 @@ void EnableNonBrowserCrashDumping() {
} // namespace
-void HandleCrashDump(const BreakpadInfo& info) {
+void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
+ const BreakpadInfo& info, const char* filename,
+ int* fd, uint8_t** file_data, size_t* size) {
// WARNING: this code runs in a compromised context. It may not call into
// libc nor allocate memory normally.
+ *fd = sys_open(filename, O_RDONLY, 0);
+ *size = 0;
- const int dumpfd = sys_open(info.filename, O_RDONLY, 0);
- if (dumpfd < 0) {
+ if (*fd < 0) {
static const char msg[] = "Cannot upload crash dump: failed to open\n";
WriteLog(msg, sizeof(msg));
return;
}
STAT_STRUCT st;
- if (FSTAT_FUNC(dumpfd, &st) != 0) {
+ if (FSTAT_FUNC(*fd, &st) != 0) {
static const char msg[] = "Cannot upload crash dump: stat failed\n";
WriteLog(msg, sizeof(msg));
- IGNORE_RET(sys_close(dumpfd));
+ IGNORE_RET(sys_close(*fd));
return;
}
- google_breakpad::PageAllocator allocator;
-
- uint8_t* dump_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
- if (!dump_data) {
+ *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
+ if (!(*file_data)) {
static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
WriteLog(msg, sizeof(msg));
- IGNORE_RET(sys_close(dumpfd));
+ IGNORE_RET(sys_close(*fd));
return;
}
+ my_memset(*file_data, 0xf, st.st_size);
- sys_read(dumpfd, dump_data, st.st_size);
- IGNORE_RET(sys_close(dumpfd));
+ *size = st.st_size;
+ sys_read(*fd, *file_data, *size);
+ IGNORE_RET(sys_close(*fd));
+}
+
+void HandleCrashDump(const BreakpadInfo& info) {
+ int dumpfd;
+ size_t dump_size;
+ uint8_t *dump_data;
+ google_breakpad::PageAllocator allocator;
+ LoadDataFromFile(allocator, info, info.filename,
+ &dumpfd, &dump_data, &dump_size);
+#if defined(ADDRESS_SANITIZER)
+ int logfd;
+ size_t log_size;
+ uint8_t *log_data;
+ // Load the AddressSanitizer log into log_data.
+ LoadDataFromFile(allocator, info, info.log_filename,
+ &logfd, &log_data, &log_size);
+#endif
// We need to build a MIME block for uploading to the server. Since we are
// going to fork and run wget, it needs to be written to a temp file.
-
const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
if (ufd < 0) {
static const char msg[] = "Cannot upload crash dump because /dev/urandom"
@@ -916,7 +982,12 @@ void HandleCrashDump(const BreakpadInfo& info) {
writer.Flush();
}
- writer.AddFileDump(dump_data, st.st_size);
+ writer.AddFileContents(g_dump_msg, dump_data, dump_size);
+#if defined(ADDRESS_SANITIZER)
+ // Append a multipart boundary and the contents of the AddressSanitizer log.
+ writer.AddBoundary();
+ writer.AddFileContents(g_log_msg, log_data, log_size);
+#endif
writer.AddEnd();
writer.Flush();
@@ -1097,6 +1168,9 @@ void HandleCrashDump(const BreakpadInfo& info) {
// Helper process.
IGNORE_RET(sys_unlink(info.filename));
+#if defined(ADDRESS_SANITIZER)
+ IGNORE_RET(sys_unlink(info.log_filename));
+#endif
IGNORE_RET(sys_unlink(temp_file));
sys__exit(0);
}
@@ -1158,6 +1232,10 @@ void InitCrashReporter() {
g_process_start_time = 0;
logging::SetDumpWithoutCrashingFunction(&DumpProcess);
+#if defined(ADDRESS_SANITIZER)
+ // Register the callback for AddressSanitizer error reporting.
+ __asan_set_error_report_callback(AsanLinuxBreakpadCallback);
+#endif
}
bool IsCrashReporterEnabled() {
diff --git a/chrome/app/breakpad_linux.h b/chrome/app/breakpad_linux.h
index 85b966f..7819653 100644
--- a/chrome/app/breakpad_linux.h
+++ b/chrome/app/breakpad_linux.h
@@ -13,9 +13,17 @@ bool IsCrashReporterEnabled();
static const size_t kMaxActiveURLSize = 1024;
static const size_t kGuidSize = 32; // 128 bits = 32 chars in hex.
static const size_t kDistroSize = 128;
+#if defined(ADDRESS_SANITIZER)
+static const size_t kMaxAsanReportSize = 1 << 16;
+#endif
struct BreakpadInfo {
const char* filename; // Path to the Breakpad dump data.
+#if defined(ADDRESS_SANITIZER)
+ const char* log_filename; // Path to the ASan log file.
+ const char* asan_report_str; // ASan report.
+ unsigned asan_report_length; // Length of |asan_report_length|.
+#endif
const char* process_type; // Process type, e.g. "renderer".
unsigned process_type_length; // Length of |process_type|.
const char* crash_url; // Active URL in the crashing process.
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index 2e67285..8b6afd973 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -128,7 +128,12 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
//
// The message sender is in chrome/app/breakpad_linux.cc.
+#if !defined(ADDRESS_SANITIZER)
const size_t kIovSize = 8;
+#else
+ const size_t kIovSize = 9;
+#endif
+
struct msghdr msg = {0};
struct iovec iov[kIovSize];
@@ -138,6 +143,9 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
char* guid = new char[kGuidSize + 1];
char* crash_url = new char[kMaxActiveURLSize + 1];
char* distro = new char[kDistroSize + 1];
+#if defined(ADDRESS_SANITIZER)
+ asan_report_str_ = new char[kMaxAsanReportSize + 1];
+#endif
char* tid_buf_addr = NULL;
int tid_fd = -1;
@@ -151,8 +159,10 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
kDistroSize + 1 +
sizeof(tid_buf_addr) + sizeof(tid_fd) +
sizeof(uptime) +
+#if defined(ADDRESS_SANITIZER)
+ kMaxAsanReportSize + 1 +
+#endif
sizeof(oom_size);
-
iov[0].iov_base = crash_context;
iov[0].iov_len = kCrashContextSize;
iov[1].iov_base = guid;
@@ -169,6 +179,10 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
iov[6].iov_len = sizeof(uptime);
iov[7].iov_base = &oom_size;
iov[7].iov_len = sizeof(oom_size);
+#if defined(ADDRESS_SANITIZER)
+ iov[8].iov_base = asan_report_str_;
+ iov[8].iov_len = kMaxAsanReportSize + 1;
+#endif
msg.msg_iov = iov;
msg.msg_iovlen = kIovSize;
msg.msg_control = control;
@@ -330,6 +344,11 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
#else
info->upload = (getenv(env_vars::kHeadless) == NULL);
#endif
+
+#if defined(ADDRESS_SANITIZER)
+ info->asan_report_str = asan_report_str_;
+ info->asan_report_length = strlen(asan_report_str_);
+#endif
info->process_start_time = uptime;
info->oom_size = oom_size;
@@ -359,11 +378,25 @@ void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
dumps_path.value().c_str(),
process_type_.c_str(),
rand);
+
if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
crashing_pid, crash_context,
kCrashContextSize)) {
LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
}
+#if defined(ADDRESS_SANITIZER)
+ // Create a temporary file holding the AddressSanitizer report.
+ const std::string log_filename =
+ base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".log",
+ dumps_path.value().c_str(),
+ process_type_.c_str(),
+ rand);
+ FILE* logfile = fopen(log_filename.c_str(), "w");
+ CHECK(logfile);
+ fprintf(logfile, "%s", asan_report_str_);
+ fclose(logfile);
+#endif
+
delete[] crash_context;
// Freed in CrashDumpTask();
@@ -371,6 +404,13 @@ void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
minidump_filename.copy(minidump_filename_str, minidump_filename.length());
minidump_filename_str[minidump_filename.length()] = '\0';
info->filename = minidump_filename_str;
+#if defined(ADDRESS_SANITIZER)
+ char* minidump_log_filename_str = new char[minidump_filename.length() + 1];
+ minidump_filename.copy(minidump_log_filename_str, minidump_filename.length());
+ memcpy(minidump_log_filename_str + minidump_filename.length() - 3, "log", 3);
+ minidump_log_filename_str[minidump_filename.length()] = '\0';
+ info->log_filename = minidump_log_filename_str;
+#endif
info->pid = crashing_pid;
BrowserThread::PostTask(
diff --git a/chrome/browser/crash_handler_host_linux.h b/chrome/browser/crash_handler_host_linux.h
index 17d04f0..f0db83e 100644
--- a/chrome/browser/crash_handler_host_linux.h
+++ b/chrome/browser/crash_handler_host_linux.h
@@ -92,6 +92,10 @@ class CrashHandlerHostLinux : public MessageLoopForIO::Watcher,
bool shutting_down_;
#endif
+#if defined(ADDRESS_SANITIZER)
+ char* asan_report_str_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(CrashHandlerHostLinux);
};