diff options
-rw-r--r-- | chrome/app/breakpad_linux.cc | 120 | ||||
-rw-r--r-- | chrome/app/breakpad_linux.h | 8 | ||||
-rw-r--r-- | chrome/browser/crash_handler_host_linux.cc | 42 | ||||
-rw-r--r-- | chrome/browser/crash_handler_host_linux.h | 4 |
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); }; |