1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // For linux_syscall_support.h. This makes it safe to call embedded system 6 // calls when in seccomp mode. 7 8 #include "chrome/app/breakpad_linux.h" 9 10 #include <fcntl.h> 11 #include <poll.h> 12 #include <signal.h> 13 #include <stdlib.h> 14 #include <sys/socket.h> 15 #include <sys/time.h> 16 #include <sys/types.h> 17 #include <sys/uio.h> 18 #include <sys/wait.h> 19 #include <time.h> 20 #include <unistd.h> 21 22 #include <algorithm> 23 #include <string> 24 25 #include "base/base_switches.h" 26 #include "base/command_line.h" 27 #include "base/debug/crash_logging.h" 28 #include "base/files/file_path.h" 29 #include "base/linux_util.h" 30 #include "base/path_service.h" 31 #include "base/platform_file.h" 32 #include "base/posix/eintr_wrapper.h" 33 #include "base/posix/global_descriptors.h" 34 #include "base/process/memory.h" 35 #include "base/strings/string_util.h" 36 #include "breakpad/src/client/linux/handler/exception_handler.h" 37 #include "breakpad/src/client/linux/minidump_writer/directory_reader.h" 38 #include "breakpad/src/common/linux/linux_libc_support.h" 39 #include "breakpad/src/common/memory.h" 40 #include "chrome/app/breakpad_linux_impl.h" 41 #include "chrome/common/child_process_logging.h" 42 #include "components/breakpad/breakpad_client.h" 43 #include "content/public/common/content_descriptors.h" 44 #include "content/public/common/content_switches.h" 45 46 #if defined(OS_ANDROID) 47 #include <android/log.h> 48 #include <sys/stat.h> 49 50 #include "base/android/build_info.h" 51 #include "base/android/path_utils.h" 52 #endif 53 #include "third_party/lss/linux_syscall_support.h" 54 55 #if defined(ADDRESS_SANITIZER) 56 #include <ucontext.h> // for getcontext(). 57 #endif 58 59 #if defined(OS_ANDROID) 60 #define STAT_STRUCT struct stat 61 #define FSTAT_FUNC fstat 62 #else 63 #define STAT_STRUCT struct kernel_stat 64 #define FSTAT_FUNC sys_fstat 65 #endif 66 67 // Some versions of gcc are prone to warn about unused return values. In cases 68 // where we either a) know the call cannot fail, or b) there is nothing we 69 // can do when a call fails, we mark the return code as ignored. This avoids 70 // spurious compiler warnings. 71 #define IGNORE_RET(x) do { if (x); } while (0) 72 73 using google_breakpad::ExceptionHandler; 74 using google_breakpad::MinidumpDescriptor; 75 76 namespace { 77 78 const char kUploadURL[] = "https://clients2.google.com/cr/report"; 79 80 bool g_is_crash_reporter_enabled = false; 81 uint64_t g_process_start_time = 0; 82 char* g_crash_log_path = NULL; 83 ExceptionHandler* g_breakpad = NULL; 84 85 #if defined(ADDRESS_SANITIZER) 86 const char* g_asan_report_str = NULL; 87 #endif 88 #if defined(OS_ANDROID) 89 char* g_process_type = NULL; 90 #endif 91 92 CrashKeyStorage* g_crash_keys = NULL; 93 94 // Writes the value |v| as 16 hex characters to the memory pointed at by 95 // |output|. 96 void write_uint64_hex(char* output, uint64_t v) { 97 static const char hextable[] = "0123456789abcdef"; 98 99 for (int i = 15; i >= 0; --i) { 100 output[i] = hextable[v & 15]; 101 v >>= 4; 102 } 103 } 104 105 // The following helper functions are for calculating uptime. 106 107 // Converts a struct timeval to milliseconds. 108 uint64_t timeval_to_ms(struct timeval *tv) { 109 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. 110 ret *= 1000; 111 ret += tv->tv_usec / 1000; 112 return ret; 113 } 114 115 // Converts a struct timeval to milliseconds. 116 uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) { 117 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. 118 ret *= 1000; 119 ret += tv->tv_usec / 1000; 120 return ret; 121 } 122 123 // String buffer size to use to convert a uint64_t to string. 124 const size_t kUint64StringSize = 21; 125 126 void SetProcessStartTime() { 127 // Set the base process start time value. 128 struct timeval tv; 129 if (!gettimeofday(&tv, NULL)) 130 g_process_start_time = timeval_to_ms(&tv); 131 else 132 g_process_start_time = 0; 133 } 134 135 // uint64_t version of my_int_len() from 136 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the 137 // given, non-negative integer when expressed in base 10. 138 unsigned my_uint64_len(uint64_t i) { 139 if (!i) 140 return 1; 141 142 unsigned len = 0; 143 while (i) { 144 len++; 145 i /= 10; 146 } 147 148 return len; 149 } 150 151 // uint64_t version of my_uitos() from 152 // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative 153 // integer to a string (not null-terminated). 154 void my_uint64tos(char* output, uint64_t i, unsigned i_len) { 155 for (unsigned index = i_len; index; --index, i /= 10) 156 output[index - 1] = '0' + (i % 10); 157 } 158 159 #if defined(OS_ANDROID) 160 char* my_strncpy(char* dst, const char* src, size_t len) { 161 int i = len; 162 char* p = dst; 163 if (!dst || !src) 164 return dst; 165 while (i != 0 && *src != '\0') { 166 *p++ = *src++; 167 i--; 168 } 169 while (i != 0) { 170 *p++ = '\0'; 171 i--; 172 } 173 return dst; 174 } 175 176 char* my_strncat(char *dest, const char* src, size_t len) { 177 char* ret = dest; 178 while (*dest) 179 dest++; 180 while (len--) 181 if (!(*dest++ = *src++)) 182 return ret; 183 *dest = 0; 184 return ret; 185 } 186 #endif 187 188 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { 189 while (len > 0 && str[len - 1] == ' ') { 190 len--; 191 } 192 return len; 193 } 194 195 // Populates the passed in allocated strings and their sizes with the GUID, 196 // crash url and distro of the crashing process. 197 // The passed strings are expected to be at least kGuidSize, kMaxActiveURLSize 198 // and kDistroSize bytes long respectively. 199 void PopulateGUIDAndURLAndDistro(char* guid, size_t* guid_len_param, 200 char* crash_url, size_t* crash_url_len_param, 201 char* distro, size_t* distro_len_param) { 202 size_t guid_len = std::min(my_strlen(child_process_logging::g_client_id), 203 kGuidSize); 204 size_t crash_url_len = 205 std::min(my_strlen(child_process_logging::g_active_url), 206 kMaxActiveURLSize); 207 size_t distro_len = std::min(my_strlen(base::g_linux_distro), kDistroSize); 208 memcpy(guid, child_process_logging::g_client_id, guid_len); 209 memcpy(crash_url, child_process_logging::g_active_url, crash_url_len); 210 memcpy(distro, base::g_linux_distro, distro_len); 211 if (guid_len_param) 212 *guid_len_param = guid_len; 213 if (crash_url_len_param) 214 *crash_url_len_param = crash_url_len; 215 if (distro_len_param) 216 *distro_len_param = distro_len; 217 } 218 219 void SetClientIdFromCommandLine(const CommandLine& command_line) { 220 // Get the guid and linux distro from the command line switch. 221 std::string switch_value = 222 command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); 223 size_t separator = switch_value.find(","); 224 if (separator != std::string::npos) { 225 child_process_logging::SetClientId(switch_value.substr(0, separator)); 226 base::SetLinuxDistro(switch_value.substr(separator + 1)); 227 } else { 228 child_process_logging::SetClientId(switch_value); 229 } 230 } 231 232 // MIME substrings. 233 #if defined(OS_CHROMEOS) 234 const char g_sep[] = ":"; 235 #endif 236 const char g_rn[] = "\r\n"; 237 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; 238 const char g_quote_msg[] = "\""; 239 const char g_dashdash_msg[] = "--"; 240 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; 241 #if defined(ADDRESS_SANITIZER) 242 const char g_log_msg[] = "upload_file_log\"; filename=\"log\""; 243 #endif 244 const char g_content_type_msg[] = "Content-Type: application/octet-stream"; 245 246 // MimeWriter manages an iovec for writing MIMEs to a file. 247 class MimeWriter { 248 public: 249 static const int kIovCapacity = 30; 250 static const size_t kMaxCrashChunkSize = 64; 251 252 MimeWriter(int fd, const char* const mime_boundary); 253 ~MimeWriter(); 254 255 // Append boundary. 256 virtual void AddBoundary(); 257 258 // Append end of file boundary. 259 virtual void AddEnd(); 260 261 // Append key/value pair with specified sizes. 262 virtual void AddPairData(const char* msg_type, 263 size_t msg_type_size, 264 const char* msg_data, 265 size_t msg_data_size); 266 267 // Append key/value pair. 268 void AddPairString(const char* msg_type, 269 const char* msg_data) { 270 AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data)); 271 } 272 273 // Append key/value pair, splitting value into chunks no larger than 274 // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|. 275 // The msg_type string will have a counter suffix to distinguish each chunk. 276 virtual void AddPairDataInChunks(const char* msg_type, 277 size_t msg_type_size, 278 const char* msg_data, 279 size_t msg_data_size, 280 size_t chunk_size, 281 bool strip_trailing_spaces); 282 283 // Add binary file contents to be uploaded with the specified filename. 284 virtual void AddFileContents(const char* filename_msg, 285 uint8_t* file_data, 286 size_t file_size); 287 288 // Flush any pending iovecs to the output file. 289 void Flush() { 290 IGNORE_RET(sys_writev(fd_, iov_, iov_index_)); 291 iov_index_ = 0; 292 } 293 294 protected: 295 void AddItem(const void* base, size_t size); 296 // Minor performance trade-off for easier-to-maintain code. 297 void AddString(const char* str) { 298 AddItem(str, my_strlen(str)); 299 } 300 void AddItemWithoutTrailingSpaces(const void* base, size_t size); 301 302 struct kernel_iovec iov_[kIovCapacity]; 303 int iov_index_; 304 305 // Output file descriptor. 306 int fd_; 307 308 const char* const mime_boundary_; 309 310 DISALLOW_COPY_AND_ASSIGN(MimeWriter); 311 }; 312 313 MimeWriter::MimeWriter(int fd, const char* const mime_boundary) 314 : iov_index_(0), 315 fd_(fd), 316 mime_boundary_(mime_boundary) { 317 } 318 319 MimeWriter::~MimeWriter() { 320 } 321 322 void MimeWriter::AddBoundary() { 323 AddString(mime_boundary_); 324 AddString(g_rn); 325 } 326 327 void MimeWriter::AddEnd() { 328 AddString(mime_boundary_); 329 AddString(g_dashdash_msg); 330 AddString(g_rn); 331 } 332 333 void MimeWriter::AddPairData(const char* msg_type, 334 size_t msg_type_size, 335 const char* msg_data, 336 size_t msg_data_size) { 337 AddString(g_form_data_msg); 338 AddItem(msg_type, msg_type_size); 339 AddString(g_quote_msg); 340 AddString(g_rn); 341 AddString(g_rn); 342 AddItem(msg_data, msg_data_size); 343 AddString(g_rn); 344 } 345 346 void MimeWriter::AddPairDataInChunks(const char* msg_type, 347 size_t msg_type_size, 348 const char* msg_data, 349 size_t msg_data_size, 350 size_t chunk_size, 351 bool strip_trailing_spaces) { 352 if (chunk_size > kMaxCrashChunkSize) 353 return; 354 355 unsigned i = 0; 356 size_t done = 0, msg_length = msg_data_size; 357 358 while (msg_length) { 359 char num[kUint64StringSize]; 360 const unsigned num_len = my_uint_len(++i); 361 my_uitos(num, i, num_len); 362 363 size_t chunk_len = std::min(chunk_size, msg_length); 364 365 AddString(g_form_data_msg); 366 AddItem(msg_type, msg_type_size); 367 AddItem(num, num_len); 368 AddString(g_quote_msg); 369 AddString(g_rn); 370 AddString(g_rn); 371 if (strip_trailing_spaces) { 372 AddItemWithoutTrailingSpaces(msg_data + done, chunk_len); 373 } else { 374 AddItem(msg_data + done, chunk_len); 375 } 376 AddString(g_rn); 377 AddBoundary(); 378 Flush(); 379 380 done += chunk_len; 381 msg_length -= chunk_len; 382 } 383 } 384 385 void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data, 386 size_t file_size) { 387 AddString(g_form_data_msg); 388 AddString(filename_msg); 389 AddString(g_rn); 390 AddString(g_content_type_msg); 391 AddString(g_rn); 392 AddString(g_rn); 393 AddItem(file_data, file_size); 394 AddString(g_rn); 395 } 396 397 void MimeWriter::AddItem(const void* base, size_t size) { 398 // Check if the iovec is full and needs to be flushed to output file. 399 if (iov_index_ == kIovCapacity) { 400 Flush(); 401 } 402 iov_[iov_index_].iov_base = const_cast<void*>(base); 403 iov_[iov_index_].iov_len = size; 404 ++iov_index_; 405 } 406 407 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { 408 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base), 409 size)); 410 } 411 412 #if defined(OS_CHROMEOS) 413 // This subclass is used on Chromium OS to report crashes in a format easy for 414 // the central crash reporting facility to understand. 415 // Format is <name>:<data length in decimal>:<data> 416 class CrashReporterWriter : public MimeWriter 417 { 418 public: 419 explicit CrashReporterWriter(int fd); 420 421 virtual void AddBoundary() OVERRIDE; 422 423 virtual void AddEnd() OVERRIDE; 424 425 virtual void AddPairData(const char* msg_type, 426 size_t msg_type_size, 427 const char* msg_data, 428 size_t msg_data_size) OVERRIDE; 429 430 virtual void AddPairDataInChunks(const char* msg_type, 431 size_t msg_type_size, 432 const char* msg_data, 433 size_t msg_data_size, 434 size_t chunk_size, 435 bool strip_trailing_spaces) OVERRIDE; 436 437 virtual void AddFileContents(const char* filename_msg, 438 uint8_t* file_data, 439 size_t file_size) OVERRIDE; 440 441 private: 442 DISALLOW_COPY_AND_ASSIGN(CrashReporterWriter); 443 }; 444 445 446 CrashReporterWriter::CrashReporterWriter(int fd) : MimeWriter(fd, "") {} 447 448 // No-ops. 449 void CrashReporterWriter::AddBoundary() {} 450 void CrashReporterWriter::AddEnd() {} 451 452 void CrashReporterWriter::AddPairData(const char* msg_type, 453 size_t msg_type_size, 454 const char* msg_data, 455 size_t msg_data_size) { 456 char data[kUint64StringSize]; 457 const unsigned data_len = my_uint_len(msg_data_size); 458 my_uitos(data, msg_data_size, data_len); 459 460 AddItem(msg_type, msg_type_size); 461 AddString(g_sep); 462 AddItem(data, data_len); 463 AddString(g_sep); 464 AddItem(msg_data, msg_data_size); 465 Flush(); 466 } 467 468 void CrashReporterWriter::AddPairDataInChunks(const char* msg_type, 469 size_t msg_type_size, 470 const char* msg_data, 471 size_t msg_data_size, 472 size_t chunk_size, 473 bool strip_trailing_spaces) { 474 if (chunk_size > kMaxCrashChunkSize) 475 return; 476 477 unsigned i = 0; 478 size_t done = 0; 479 size_t msg_length = msg_data_size; 480 481 while (msg_length) { 482 char num[kUint64StringSize]; 483 const unsigned num_len = my_uint_len(++i); 484 my_uitos(num, i, num_len); 485 486 size_t chunk_len = std::min(chunk_size, msg_length); 487 488 size_t write_len = chunk_len; 489 if (strip_trailing_spaces) { 490 // Take care of this here because we need to know the exact length of 491 // what is going to be written. 492 write_len = LengthWithoutTrailingSpaces(msg_data + done, write_len); 493 } 494 495 char data[kUint64StringSize]; 496 const unsigned data_len = my_uint_len(write_len); 497 my_uitos(data, write_len, data_len); 498 499 AddItem(msg_type, msg_type_size); 500 AddItem(num, num_len); 501 AddString(g_sep); 502 AddItem(data, data_len); 503 AddString(g_sep); 504 AddItem(msg_data + done, write_len); 505 Flush(); 506 507 done += chunk_len; 508 msg_length -= chunk_len; 509 } 510 } 511 512 void CrashReporterWriter::AddFileContents(const char* filename_msg, 513 uint8_t* file_data, 514 size_t file_size) { 515 char data[kUint64StringSize]; 516 const unsigned data_len = my_uint_len(file_size); 517 my_uitos(data, file_size, data_len); 518 519 AddString(filename_msg); 520 AddString(g_sep); 521 AddItem(data, data_len); 522 AddString(g_sep); 523 AddItem(file_data, file_size); 524 Flush(); 525 } 526 #endif 527 528 void DumpProcess() { 529 if (g_breakpad) 530 g_breakpad->WriteMinidump(); 531 } 532 533 const char kGoogleBreakpad[] = "google-breakpad"; 534 535 size_t WriteLog(const char* buf, size_t nbytes) { 536 #if defined(OS_ANDROID) 537 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf); 538 #else 539 return sys_write(2, buf, nbytes); 540 #endif 541 } 542 543 #if defined(OS_ANDROID) 544 // Android's native crash handler outputs a diagnostic tombstone to the device 545 // log. By returning false from the HandlerCallbacks, breakpad will reinstall 546 // the previous (i.e. native) signal handlers before returning from its own 547 // handler. A Chrome build fingerprint is written to the log, so that the 548 // specific build of Chrome and the location of the archived Chrome symbols can 549 // be determined directly from it. 550 bool FinalizeCrashDoneAndroid() { 551 base::android::BuildInfo* android_build_info = 552 base::android::BuildInfo::GetInstance(); 553 554 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 555 "### ### ### ### ### ### ### ### ### ### ### ### ###"); 556 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 557 "Chrome build fingerprint:"); 558 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 559 android_build_info->package_version_name()); 560 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 561 android_build_info->package_version_code()); 562 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 563 CHROME_BUILD_ID); 564 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, 565 "### ### ### ### ### ### ### ### ### ### ### ### ###"); 566 return false; 567 } 568 #endif 569 570 bool CrashDone(const MinidumpDescriptor& minidump, 571 const bool upload, 572 const bool succeeded) { 573 // WARNING: this code runs in a compromised context. It may not call into 574 // libc nor allocate memory normally. 575 if (!succeeded) { 576 const char msg[] = "Failed to generate minidump."; 577 WriteLog(msg, sizeof(msg) - 1); 578 return false; 579 } 580 581 DCHECK(!minidump.IsFD()); 582 583 BreakpadInfo info = {0}; 584 info.filename = minidump.path(); 585 info.fd = minidump.fd(); 586 #if defined(ADDRESS_SANITIZER) 587 google_breakpad::PageAllocator allocator; 588 const size_t log_path_len = my_strlen(minidump.path()); 589 char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1)); 590 my_memcpy(log_path, minidump.path(), log_path_len); 591 my_memcpy(log_path + log_path_len - 4, ".log", 4); 592 log_path[log_path_len] = '\0'; 593 info.log_filename = log_path; 594 #endif 595 info.process_type = "browser"; 596 info.process_type_length = 7; 597 info.crash_url = NULL; 598 info.crash_url_length = 0; 599 info.guid = child_process_logging::g_client_id; 600 info.guid_length = my_strlen(child_process_logging::g_client_id); 601 info.distro = base::g_linux_distro; 602 info.distro_length = my_strlen(base::g_linux_distro); 603 info.upload = upload; 604 info.process_start_time = g_process_start_time; 605 info.oom_size = base::g_oom_size; 606 info.pid = 0; 607 info.crash_keys = g_crash_keys; 608 HandleCrashDump(info); 609 #if defined(OS_ANDROID) 610 return FinalizeCrashDoneAndroid(); 611 #else 612 return true; 613 #endif 614 } 615 616 // Wrapper function, do not add more code here. 617 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump, 618 void* context, 619 bool succeeded) { 620 return CrashDone(minidump, false, succeeded); 621 } 622 623 #if !defined(OS_ANDROID) 624 // Wrapper function, do not add more code here. 625 bool CrashDoneUpload(const MinidumpDescriptor& minidump, 626 void* context, 627 bool succeeded) { 628 return CrashDone(minidump, true, succeeded); 629 } 630 #endif 631 632 #if defined(ADDRESS_SANITIZER) 633 extern "C" 634 void __asan_set_error_report_callback(void (*cb)(const char*)); 635 636 extern "C" 637 void AsanLinuxBreakpadCallback(const char* report) { 638 g_asan_report_str = report; 639 // Send minidump here. 640 g_breakpad->SimulateSignalDelivery(SIGKILL); 641 } 642 #endif 643 644 void EnableCrashDumping(bool unattended) { 645 g_is_crash_reporter_enabled = true; 646 647 base::FilePath tmp_path("/tmp"); 648 PathService::Get(base::DIR_TEMP, &tmp_path); 649 650 base::FilePath dumps_path(tmp_path); 651 if (breakpad::GetBreakpadClient()->GetCrashDumpLocation(&dumps_path)) { 652 base::FilePath logfile = dumps_path.Append( 653 breakpad::GetBreakpadClient()->GetReporterLogFilename()); 654 std::string logfile_str = logfile.value(); 655 const size_t crash_log_path_len = logfile_str.size() + 1; 656 g_crash_log_path = new char[crash_log_path_len]; 657 strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len); 658 } 659 DCHECK(!g_breakpad); 660 MinidumpDescriptor minidump_descriptor(dumps_path.value()); 661 minidump_descriptor.set_size_limit(kMaxMinidumpFileSize); 662 #if defined(OS_ANDROID) 663 unattended = true; // Android never uploads directly. 664 #endif 665 if (unattended) { 666 g_breakpad = new ExceptionHandler( 667 minidump_descriptor, 668 NULL, 669 CrashDoneNoUpload, 670 NULL, 671 true, // Install handlers. 672 -1); // Server file descriptor. -1 for in-process. 673 return; 674 } 675 676 #if !defined(OS_ANDROID) 677 // Attended mode 678 g_breakpad = new ExceptionHandler( 679 minidump_descriptor, 680 NULL, 681 CrashDoneUpload, 682 NULL, 683 true, // Install handlers. 684 -1); // Server file descriptor. -1 for in-process. 685 #endif 686 } 687 688 #if defined(OS_ANDROID) 689 bool CrashDoneInProcessNoUpload( 690 const google_breakpad::MinidumpDescriptor& descriptor, 691 void* context, 692 const bool succeeded) { 693 // WARNING: this code runs in a compromised context. It may not call into 694 // libc nor allocate memory normally. 695 if (!succeeded) { 696 static const char msg[] = "Crash dump generation failed.\n"; 697 WriteLog(msg, sizeof(msg) - 1); 698 return false; 699 } 700 701 // Start constructing the message to send to the browser. 702 char guid[kGuidSize + 1] = {0}; 703 char crash_url[kMaxActiveURLSize + 1] = {0}; 704 char distro[kDistroSize + 1] = {0}; 705 size_t guid_length = 0; 706 size_t crash_url_length = 0; 707 size_t distro_length = 0; 708 PopulateGUIDAndURLAndDistro(guid, &guid_length, crash_url, &crash_url_length, 709 distro, &distro_length); 710 BreakpadInfo info = {0}; 711 info.filename = NULL; 712 info.fd = descriptor.fd(); 713 info.process_type = g_process_type; 714 info.process_type_length = my_strlen(g_process_type); 715 info.crash_url = crash_url; 716 info.crash_url_length = crash_url_length; 717 info.guid = guid; 718 info.guid_length = guid_length; 719 info.distro = distro; 720 info.distro_length = distro_length; 721 info.upload = false; 722 info.process_start_time = g_process_start_time; 723 HandleCrashDump(info); 724 return FinalizeCrashDoneAndroid(); 725 } 726 727 void EnableNonBrowserCrashDumping(int minidump_fd) { 728 // This will guarantee that the BuildInfo has been initialized and subsequent 729 // calls will not require memory allocation. 730 base::android::BuildInfo::GetInstance(); 731 SetClientIdFromCommandLine(*CommandLine::ForCurrentProcess()); 732 733 // On Android, the current sandboxing uses process isolation, in which the 734 // child process runs with a different UID. That breaks the normal crash 735 // reporting where the browser process generates the minidump by inspecting 736 // the child process. This is because the browser process now does not have 737 // the permission to access the states of the child process (as it has a 738 // different UID). 739 // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog 740 // process forked from the renderer process that generates the minidump. 741 if (minidump_fd == -1) { 742 LOG(ERROR) << "Minidump file descriptor not found, crash reporting will " 743 " not work."; 744 return; 745 } 746 SetProcessStartTime(); 747 748 g_is_crash_reporter_enabled = true; 749 // Save the process type (it is leaked). 750 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 751 const std::string process_type = 752 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); 753 const size_t process_type_len = process_type.size() + 1; 754 g_process_type = new char[process_type_len]; 755 strncpy(g_process_type, process_type.c_str(), process_type_len); 756 new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd), 757 NULL, CrashDoneInProcessNoUpload, NULL, true, -1); 758 } 759 #else 760 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer 761 bool NonBrowserCrashHandler(const void* crash_context, 762 size_t crash_context_size, 763 void* context) { 764 const int fd = reinterpret_cast<intptr_t>(context); 765 int fds[2] = { -1, -1 }; 766 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { 767 static const char msg[] = "Failed to create socket for crash dumping.\n"; 768 WriteLog(msg, sizeof(msg) - 1); 769 return false; 770 } 771 772 // Start constructing the message to send to the browser. 773 char guid[kGuidSize + 1] = {0}; 774 char crash_url[kMaxActiveURLSize + 1] = {0}; 775 char distro[kDistroSize + 1] = {0}; 776 PopulateGUIDAndURLAndDistro(guid, NULL, crash_url, NULL, distro, NULL); 777 778 char b; // Dummy variable for sys_read below. 779 const char* b_addr = &b; // Get the address of |b| so we can create the 780 // expected /proc/[pid]/syscall content in the 781 // browser to convert namespace tids. 782 783 // The length of the control message: 784 static const unsigned kControlMsgSize = sizeof(fds); 785 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); 786 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); 787 788 struct kernel_msghdr msg; 789 my_memset(&msg, 0, sizeof(struct kernel_msghdr)); 790 struct kernel_iovec iov[kCrashIovSize]; 791 iov[0].iov_base = const_cast<void*>(crash_context); 792 iov[0].iov_len = crash_context_size; 793 iov[1].iov_base = guid; 794 iov[1].iov_len = kGuidSize + 1; 795 iov[2].iov_base = crash_url; 796 iov[2].iov_len = kMaxActiveURLSize + 1; 797 iov[3].iov_base = distro; 798 iov[3].iov_len = kDistroSize + 1; 799 iov[4].iov_base = &b_addr; 800 iov[4].iov_len = sizeof(b_addr); 801 iov[5].iov_base = &fds[0]; 802 iov[5].iov_len = sizeof(fds[0]); 803 iov[6].iov_base = &g_process_start_time; 804 iov[6].iov_len = sizeof(g_process_start_time); 805 iov[7].iov_base = &base::g_oom_size; 806 iov[7].iov_len = sizeof(base::g_oom_size); 807 google_breakpad::SerializedNonAllocatingMap* serialized_map; 808 iov[8].iov_len = g_crash_keys->Serialize( 809 const_cast<const google_breakpad::SerializedNonAllocatingMap**>( 810 &serialized_map)); 811 iov[8].iov_base = serialized_map; 812 #if defined(ADDRESS_SANITIZER) 813 iov[9].iov_base = const_cast<char*>(g_asan_report_str); 814 iov[9].iov_len = kMaxAsanReportSize + 1; 815 #endif 816 817 msg.msg_iov = iov; 818 msg.msg_iovlen = kCrashIovSize; 819 char cmsg[kControlMsgSpaceSize]; 820 my_memset(cmsg, 0, kControlMsgSpaceSize); 821 msg.msg_control = cmsg; 822 msg.msg_controllen = sizeof(cmsg); 823 824 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); 825 hdr->cmsg_level = SOL_SOCKET; 826 hdr->cmsg_type = SCM_RIGHTS; 827 hdr->cmsg_len = kControlMsgLenSize; 828 ((int*) CMSG_DATA(hdr))[0] = fds[0]; 829 ((int*) CMSG_DATA(hdr))[1] = fds[1]; 830 831 if (HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)) < 0) { 832 static const char errmsg[] = "Failed to tell parent about crash.\n"; 833 WriteLog(errmsg, sizeof(errmsg) - 1); 834 IGNORE_RET(sys_close(fds[1])); 835 return false; 836 } 837 IGNORE_RET(sys_close(fds[1])); 838 839 if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) { 840 static const char errmsg[] = "Parent failed to complete crash dump.\n"; 841 WriteLog(errmsg, sizeof(errmsg) - 1); 842 } 843 844 return true; 845 } 846 847 void EnableNonBrowserCrashDumping() { 848 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal); 849 g_is_crash_reporter_enabled = true; 850 // We deliberately leak this object. 851 DCHECK(!g_breakpad); 852 853 g_breakpad = new ExceptionHandler( 854 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. 855 NULL, 856 NULL, 857 reinterpret_cast<void*>(fd), // Param passed to the crash handler. 858 true, 859 -1); 860 g_breakpad->set_crash_handler(NonBrowserCrashHandler); 861 } 862 #endif // defined(OS_ANDROID) 863 864 void SetCrashKeyValue(const base::StringPiece& key, 865 const base::StringPiece& value) { 866 g_crash_keys->SetKeyValue(key.data(), value.data()); 867 } 868 869 void ClearCrashKey(const base::StringPiece& key) { 870 g_crash_keys->RemoveKey(key.data()); 871 } 872 873 } // namespace 874 875 void LoadDataFromFD(google_breakpad::PageAllocator& allocator, 876 int fd, bool close_fd, uint8_t** file_data, size_t* size) { 877 STAT_STRUCT st; 878 if (FSTAT_FUNC(fd, &st) != 0) { 879 static const char msg[] = "Cannot upload crash dump: stat failed\n"; 880 WriteLog(msg, sizeof(msg) - 1); 881 if (close_fd) 882 IGNORE_RET(sys_close(fd)); 883 return; 884 } 885 886 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); 887 if (!(*file_data)) { 888 static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; 889 WriteLog(msg, sizeof(msg) - 1); 890 if (close_fd) 891 IGNORE_RET(sys_close(fd)); 892 return; 893 } 894 my_memset(*file_data, 0xf, st.st_size); 895 896 *size = st.st_size; 897 int byte_read = sys_read(fd, *file_data, *size); 898 if (byte_read == -1) { 899 static const char msg[] = "Cannot upload crash dump: read failed\n"; 900 WriteLog(msg, sizeof(msg) - 1); 901 if (close_fd) 902 IGNORE_RET(sys_close(fd)); 903 return; 904 } 905 906 if (close_fd) 907 IGNORE_RET(sys_close(fd)); 908 } 909 910 void LoadDataFromFile(google_breakpad::PageAllocator& allocator, 911 const char* filename, 912 int* fd, uint8_t** file_data, size_t* size) { 913 // WARNING: this code runs in a compromised context. It may not call into 914 // libc nor allocate memory normally. 915 *fd = sys_open(filename, O_RDONLY, 0); 916 *size = 0; 917 918 if (*fd < 0) { 919 static const char msg[] = "Cannot upload crash dump: failed to open\n"; 920 WriteLog(msg, sizeof(msg) - 1); 921 return; 922 } 923 924 LoadDataFromFD(allocator, *fd, true, file_data, size); 925 } 926 927 // Spawn the appropriate upload process for the current OS: 928 // - generic Linux invokes wget. 929 // - ChromeOS invokes crash_reporter. 930 // |dumpfile| is the path to the dump data file. 931 // |mime_boundary| is only used on Linux. 932 // |exe_buf| is only used on CrOS and is the crashing process' name. 933 void ExecUploadProcessOrTerminate(const BreakpadInfo& info, 934 const char* dumpfile, 935 const char* mime_boundary, 936 const char* exe_buf, 937 google_breakpad::PageAllocator* allocator) { 938 #if defined(OS_CHROMEOS) 939 // CrOS uses crash_reporter instead of wget to report crashes, 940 // it needs to know where the crash dump lives and the pid and uid of the 941 // crashing process. 942 static const char kCrashReporterBinary[] = "/sbin/crash_reporter"; 943 944 char pid_buf[kUint64StringSize]; 945 uint64_t pid_str_length = my_uint64_len(info.pid); 946 my_uint64tos(pid_buf, info.pid, pid_str_length); 947 pid_buf[pid_str_length] = '\0'; 948 949 char uid_buf[kUint64StringSize]; 950 uid_t uid = geteuid(); 951 uint64_t uid_str_length = my_uint64_len(uid); 952 my_uint64tos(uid_buf, uid, uid_str_length); 953 uid_buf[uid_str_length] = '\0'; 954 const char* args[] = { 955 kCrashReporterBinary, 956 "--chrome", 957 dumpfile, 958 "--pid", 959 pid_buf, 960 "--uid", 961 uid_buf, 962 "--exe", 963 exe_buf, 964 NULL, 965 }; 966 static const char msg[] = "Cannot upload crash dump: cannot exec " 967 "/sbin/crash_reporter\n"; 968 #else 969 // The --header argument to wget looks like: 970 // --header=Content-Type: multipart/form-data; boundary=XYZ 971 // where the boundary has two fewer leading '-' chars 972 static const char header_msg[] = 973 "--header=Content-Type: multipart/form-data; boundary="; 974 char* const header = reinterpret_cast<char*>(allocator->Alloc( 975 sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1)); 976 memcpy(header, header_msg, sizeof(header_msg) - 1); 977 memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2, 978 strlen(mime_boundary) - 2); 979 // We grab the NUL byte from the end of |mime_boundary|. 980 981 // The --post-file argument to wget looks like: 982 // --post-file=/tmp/... 983 static const char post_file_msg[] = "--post-file="; 984 char* const post_file = reinterpret_cast<char*>(allocator->Alloc( 985 sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1)); 986 memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1); 987 memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile)); 988 989 static const char kWgetBinary[] = "/usr/bin/wget"; 990 const char* args[] = { 991 kWgetBinary, 992 header, 993 post_file, 994 kUploadURL, 995 "--timeout=10", // Set a timeout so we don't hang forever. 996 "--tries=1", // Don't retry if the upload fails. 997 "-O", // output reply to fd 3 998 "/dev/fd/3", 999 NULL, 1000 }; 1001 static const char msg[] = "Cannot upload crash dump: cannot exec " 1002 "/usr/bin/wget\n"; 1003 #endif 1004 execve(args[0], const_cast<char**>(args), environ); 1005 WriteLog(msg, sizeof(msg) - 1); 1006 sys__exit(1); 1007 } 1008 1009 #if defined(OS_CHROMEOS) 1010 const char* GetCrashingProcessName(const BreakpadInfo& info, 1011 google_breakpad::PageAllocator* allocator) { 1012 // Symlink to process binary is at /proc/###/exe. 1013 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] = 1014 "/proc/"; 1015 uint64_t pid_value_len = my_uint64_len(info.pid); 1016 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len); 1017 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0'; 1018 my_strlcat(linkpath, "/exe", sizeof(linkpath)); 1019 1020 const int kMaxSize = 4096; 1021 char* link = reinterpret_cast<char*>(allocator->Alloc(kMaxSize)); 1022 if (link) { 1023 ssize_t size = readlink(linkpath, link, kMaxSize); 1024 if (size < kMaxSize && size > 0) { 1025 // readlink(2) doesn't add a terminating NUL, so do it now. 1026 link[size] = '\0'; 1027 1028 const char* name = my_strrchr(link, '/'); 1029 if (name) 1030 return name + 1; 1031 return link; 1032 } 1033 } 1034 // Either way too long, or a read error. 1035 return "chrome-crash-unknown-process"; 1036 } 1037 #endif 1038 1039 void HandleCrashDump(const BreakpadInfo& info) { 1040 int dumpfd; 1041 bool keep_fd = false; 1042 size_t dump_size; 1043 uint8_t* dump_data; 1044 google_breakpad::PageAllocator allocator; 1045 const char* exe_buf = NULL; 1046 1047 #if defined(OS_CHROMEOS) 1048 // Grab the crashing process' name now, when it should still be available. 1049 // If we try to do this later in our grandchild the crashing process has 1050 // already terminated. 1051 exe_buf = GetCrashingProcessName(info, &allocator); 1052 #endif 1053 1054 if (info.fd != -1) { 1055 // Dump is provided with an open FD. 1056 keep_fd = true; 1057 dumpfd = info.fd; 1058 1059 // The FD is pointing to the end of the file. 1060 // Rewind, we'll read the data next. 1061 if (lseek(dumpfd, 0, SEEK_SET) == -1) { 1062 static const char msg[] = "Cannot upload crash dump: failed to " 1063 "reposition minidump FD\n"; 1064 WriteLog(msg, sizeof(msg) - 1); 1065 IGNORE_RET(sys_close(dumpfd)); 1066 return; 1067 } 1068 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size); 1069 } else { 1070 // Dump is provided with a path. 1071 keep_fd = false; 1072 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size); 1073 } 1074 1075 // TODO(jcivelli): make log work when using FDs. 1076 #if defined(ADDRESS_SANITIZER) 1077 int logfd; 1078 size_t log_size; 1079 uint8_t* log_data; 1080 // Load the AddressSanitizer log into log_data. 1081 LoadDataFromFile(allocator, info.log_filename, &logfd, &log_data, &log_size); 1082 #endif 1083 1084 // We need to build a MIME block for uploading to the server. Since we are 1085 // going to fork and run wget, it needs to be written to a temp file. 1086 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); 1087 if (ufd < 0) { 1088 static const char msg[] = "Cannot upload crash dump because /dev/urandom" 1089 " is missing\n"; 1090 WriteLog(msg, sizeof(msg) - 1); 1091 return; 1092 } 1093 1094 static const char temp_file_template[] = 1095 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; 1096 char temp_file[sizeof(temp_file_template)]; 1097 int temp_file_fd = -1; 1098 if (keep_fd) { 1099 temp_file_fd = dumpfd; 1100 // Rewind the destination, we are going to overwrite it. 1101 if (lseek(dumpfd, 0, SEEK_SET) == -1) { 1102 static const char msg[] = "Cannot upload crash dump: failed to " 1103 "reposition minidump FD (2)\n"; 1104 WriteLog(msg, sizeof(msg) - 1); 1105 IGNORE_RET(sys_close(dumpfd)); 1106 return; 1107 } 1108 } else { 1109 if (info.upload) { 1110 memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); 1111 1112 for (unsigned i = 0; i < 10; ++i) { 1113 uint64_t t; 1114 sys_read(ufd, &t, sizeof(t)); 1115 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); 1116 1117 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); 1118 if (temp_file_fd >= 0) 1119 break; 1120 } 1121 1122 if (temp_file_fd < 0) { 1123 static const char msg[] = "Failed to create temporary file in /tmp: " 1124 "cannot upload crash dump\n"; 1125 WriteLog(msg, sizeof(msg) - 1); 1126 IGNORE_RET(sys_close(ufd)); 1127 return; 1128 } 1129 } else { 1130 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); 1131 if (temp_file_fd < 0) { 1132 static const char msg[] = "Failed to save crash dump: failed to open\n"; 1133 WriteLog(msg, sizeof(msg) - 1); 1134 IGNORE_RET(sys_close(ufd)); 1135 return; 1136 } 1137 } 1138 } 1139 1140 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. 1141 char mime_boundary[28 + 16 + 1]; 1142 my_memset(mime_boundary, '-', 28); 1143 uint64_t boundary_rand; 1144 sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); 1145 write_uint64_hex(mime_boundary + 28, boundary_rand); 1146 mime_boundary[28 + 16] = 0; 1147 IGNORE_RET(sys_close(ufd)); 1148 1149 // The MIME block looks like this: 1150 // BOUNDARY \r\n 1151 // Content-Disposition: form-data; name="prod" \r\n \r\n 1152 // Chrome_Linux \r\n 1153 // BOUNDARY \r\n 1154 // Content-Disposition: form-data; name="ver" \r\n \r\n 1155 // 1.2.3.4 \r\n 1156 // BOUNDARY \r\n 1157 // Content-Disposition: form-data; name="guid" \r\n \r\n 1158 // 1.2.3.4 \r\n 1159 // BOUNDARY \r\n 1160 // 1161 // zero or one: 1162 // Content-Disposition: form-data; name="ptime" \r\n \r\n 1163 // abcdef \r\n 1164 // BOUNDARY \r\n 1165 // 1166 // zero or one: 1167 // Content-Disposition: form-data; name="ptype" \r\n \r\n 1168 // abcdef \r\n 1169 // BOUNDARY \r\n 1170 // 1171 // zero or more gpu entries: 1172 // Content-Disposition: form-data; name="gpu-xxxxx" \r\n \r\n 1173 // <gpu-xxxxx> \r\n 1174 // BOUNDARY \r\n 1175 // 1176 // zero or one: 1177 // Content-Disposition: form-data; name="lsb-release" \r\n \r\n 1178 // abcdef \r\n 1179 // BOUNDARY \r\n 1180 // 1181 // zero or more: 1182 // Content-Disposition: form-data; name="url-chunk-1" \r\n \r\n 1183 // abcdef \r\n 1184 // BOUNDARY \r\n 1185 // 1186 // zero or one: 1187 // Content-Disposition: form-data; name="channel" \r\n \r\n 1188 // beta \r\n 1189 // BOUNDARY \r\n 1190 // 1191 // zero or one: 1192 // Content-Disposition: form-data; name="num-views" \r\n \r\n 1193 // 3 \r\n 1194 // BOUNDARY \r\n 1195 // 1196 // zero or one: 1197 // Content-Disposition: form-data; name="num-extensions" \r\n \r\n 1198 // 5 \r\n 1199 // BOUNDARY \r\n 1200 // 1201 // zero to 10: 1202 // Content-Disposition: form-data; name="extension-1" \r\n \r\n 1203 // abcdefghijklmnopqrstuvwxyzabcdef \r\n 1204 // BOUNDARY \r\n 1205 // 1206 // zero to 4: 1207 // Content-Disposition: form-data; name="prn-info-1" \r\n \r\n 1208 // abcdefghijklmnopqrstuvwxyzabcdef \r\n 1209 // BOUNDARY \r\n 1210 // 1211 // zero or one: 1212 // Content-Disposition: form-data; name="num-switches" \r\n \r\n 1213 // 5 \r\n 1214 // BOUNDARY \r\n 1215 // 1216 // zero to 15: 1217 // Content-Disposition: form-data; name="switch-1" \r\n \r\n 1218 // --foo \r\n 1219 // BOUNDARY \r\n 1220 // 1221 // zero or one: 1222 // Content-Disposition: form-data; name="oom-size" \r\n \r\n 1223 // 1234567890 \r\n 1224 // BOUNDARY \r\n 1225 // 1226 // zero or more (up to CrashKeyStorage::num_entries = 64): 1227 // Content-Disposition: form-data; name=crash-key-name \r\n 1228 // crash-key-value \r\n 1229 // BOUNDARY \r\n 1230 // 1231 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n 1232 // Content-Type: application/octet-stream \r\n \r\n 1233 // <dump contents> 1234 // \r\n BOUNDARY -- \r\n 1235 1236 #if defined(OS_CHROMEOS) 1237 CrashReporterWriter writer(temp_file_fd); 1238 #else 1239 MimeWriter writer(temp_file_fd, mime_boundary); 1240 #endif 1241 { 1242 std::string product_name; 1243 std::string version; 1244 1245 breakpad::GetBreakpadClient()->GetProductNameAndVersion(&product_name, 1246 &version); 1247 1248 writer.AddBoundary(); 1249 writer.AddPairString("prod", product_name.c_str()); 1250 writer.AddBoundary(); 1251 writer.AddPairString("ver", version.c_str()); 1252 writer.AddBoundary(); 1253 writer.AddPairString("guid", info.guid); 1254 writer.AddBoundary(); 1255 if (info.pid > 0) { 1256 char pid_value_buf[kUint64StringSize]; 1257 uint64_t pid_value_len = my_uint64_len(info.pid); 1258 my_uint64tos(pid_value_buf, info.pid, pid_value_len); 1259 static const char pid_key_name[] = "pid"; 1260 writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, 1261 pid_value_buf, pid_value_len); 1262 writer.AddBoundary(); 1263 } 1264 #if defined(OS_ANDROID) 1265 // Addtional MIME blocks are added for logging on Android devices. 1266 static const char android_build_id[] = "android_build_id"; 1267 static const char android_build_fp[] = "android_build_fp"; 1268 static const char device[] = "device"; 1269 static const char model[] = "model"; 1270 static const char brand[] = "brand"; 1271 static const char exception_info[] = "exception_info"; 1272 1273 base::android::BuildInfo* android_build_info = 1274 base::android::BuildInfo::GetInstance(); 1275 writer.AddPairString( 1276 android_build_id, android_build_info->android_build_id()); 1277 writer.AddBoundary(); 1278 writer.AddPairString( 1279 android_build_fp, android_build_info->android_build_fp()); 1280 writer.AddBoundary(); 1281 writer.AddPairString(device, android_build_info->device()); 1282 writer.AddBoundary(); 1283 writer.AddPairString(model, android_build_info->model()); 1284 writer.AddBoundary(); 1285 writer.AddPairString(brand, android_build_info->brand()); 1286 writer.AddBoundary(); 1287 if (android_build_info->java_exception_info() != NULL) { 1288 writer.AddPairString(exception_info, 1289 android_build_info->java_exception_info()); 1290 writer.AddBoundary(); 1291 } 1292 #endif 1293 writer.Flush(); 1294 } 1295 1296 if (info.process_start_time > 0) { 1297 struct kernel_timeval tv; 1298 if (!sys_gettimeofday(&tv, NULL)) { 1299 uint64_t time = kernel_timeval_to_ms(&tv); 1300 if (time > info.process_start_time) { 1301 time -= info.process_start_time; 1302 char time_str[kUint64StringSize]; 1303 const unsigned time_len = my_uint64_len(time); 1304 my_uint64tos(time_str, time, time_len); 1305 1306 static const char process_time_msg[] = "ptime"; 1307 writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1, 1308 time_str, time_len); 1309 writer.AddBoundary(); 1310 writer.Flush(); 1311 } 1312 } 1313 } 1314 1315 if (info.process_type_length) { 1316 writer.AddPairString("ptype", info.process_type); 1317 writer.AddBoundary(); 1318 writer.Flush(); 1319 } 1320 1321 // If GPU info is known, send it. 1322 if (*child_process_logging::g_gpu_vendor_id) { 1323 #if !defined(OS_ANDROID) 1324 static const char vendor_msg[] = "gpu-venid"; 1325 static const char device_msg[] = "gpu-devid"; 1326 #endif 1327 static const char gl_vendor_msg[] = "gpu-gl-vendor"; 1328 static const char gl_renderer_msg[] = "gpu-gl-renderer"; 1329 static const char driver_msg[] = "gpu-driver"; 1330 static const char psver_msg[] = "gpu-psver"; 1331 static const char vsver_msg[] = "gpu-vsver"; 1332 1333 #if !defined(OS_ANDROID) 1334 writer.AddPairString(vendor_msg, child_process_logging::g_gpu_vendor_id); 1335 writer.AddBoundary(); 1336 writer.AddPairString(device_msg, child_process_logging::g_gpu_device_id); 1337 writer.AddBoundary(); 1338 #endif 1339 writer.AddPairString(gl_vendor_msg, child_process_logging::g_gpu_gl_vendor); 1340 writer.AddBoundary(); 1341 writer.AddPairString(gl_renderer_msg, 1342 child_process_logging::g_gpu_gl_renderer); 1343 writer.AddBoundary(); 1344 writer.AddPairString(driver_msg, child_process_logging::g_gpu_driver_ver); 1345 writer.AddBoundary(); 1346 writer.AddPairString(psver_msg, child_process_logging::g_gpu_ps_ver); 1347 writer.AddBoundary(); 1348 writer.AddPairString(vsver_msg, child_process_logging::g_gpu_vs_ver); 1349 writer.AddBoundary(); 1350 writer.Flush(); 1351 } 1352 1353 if (info.distro_length) { 1354 static const char distro_msg[] = "lsb-release"; 1355 writer.AddPairString(distro_msg, info.distro); 1356 writer.AddBoundary(); 1357 writer.Flush(); 1358 } 1359 1360 // For renderers and plugins. 1361 if (info.crash_url_length) { 1362 static const char url_chunk_msg[] = "url-chunk-"; 1363 static const unsigned kMaxUrlLength = 8 * MimeWriter::kMaxCrashChunkSize; 1364 writer.AddPairDataInChunks(url_chunk_msg, sizeof(url_chunk_msg) - 1, 1365 info.crash_url, std::min(info.crash_url_length, kMaxUrlLength), 1366 MimeWriter::kMaxCrashChunkSize, false /* Don't strip whitespaces. */); 1367 } 1368 1369 if (*child_process_logging::g_channel) { 1370 writer.AddPairString("channel", child_process_logging::g_channel); 1371 writer.AddBoundary(); 1372 writer.Flush(); 1373 } 1374 1375 if (*child_process_logging::g_num_views) { 1376 writer.AddPairString("num-views", child_process_logging::g_num_views); 1377 writer.AddBoundary(); 1378 writer.Flush(); 1379 } 1380 1381 if (*child_process_logging::g_num_extensions) { 1382 writer.AddPairString("num-extensions", 1383 child_process_logging::g_num_extensions); 1384 writer.AddBoundary(); 1385 writer.Flush(); 1386 } 1387 1388 unsigned extension_ids_len = 1389 my_strlen(child_process_logging::g_extension_ids); 1390 if (extension_ids_len) { 1391 static const char extension_msg[] = "extension-"; 1392 static const unsigned kMaxExtensionsLen = 1393 kMaxReportedActiveExtensions * child_process_logging::kExtensionLen; 1394 writer.AddPairDataInChunks(extension_msg, sizeof(extension_msg) - 1, 1395 child_process_logging::g_extension_ids, 1396 std::min(extension_ids_len, kMaxExtensionsLen), 1397 child_process_logging::kExtensionLen, 1398 false /* Don't strip whitespace. */); 1399 } 1400 1401 unsigned printer_info_len = 1402 my_strlen(child_process_logging::g_printer_info); 1403 if (printer_info_len) { 1404 static const char printer_info_msg[] = "prn-info-"; 1405 static const unsigned kMaxPrnInfoLen = 1406 kMaxReportedPrinterRecords * child_process_logging::kPrinterInfoStrLen; 1407 writer.AddPairDataInChunks(printer_info_msg, sizeof(printer_info_msg) - 1, 1408 child_process_logging::g_printer_info, 1409 std::min(printer_info_len, kMaxPrnInfoLen), 1410 child_process_logging::kPrinterInfoStrLen, 1411 true); 1412 } 1413 1414 if (*child_process_logging::g_num_switches) { 1415 writer.AddPairString("num-switches", 1416 child_process_logging::g_num_switches); 1417 writer.AddBoundary(); 1418 writer.Flush(); 1419 } 1420 1421 unsigned switches_len = 1422 my_strlen(child_process_logging::g_switches); 1423 if (switches_len) { 1424 static const char switch_msg[] = "switch-"; 1425 static const unsigned kMaxSwitchLen = 1426 kMaxSwitches * child_process_logging::kSwitchLen; 1427 writer.AddPairDataInChunks(switch_msg, sizeof(switch_msg) - 1, 1428 child_process_logging::g_switches, 1429 std::min(switches_len, kMaxSwitchLen), 1430 child_process_logging::kSwitchLen, 1431 true /* Strip whitespace since switches are padded to kSwitchLen. */); 1432 } 1433 1434 if (*child_process_logging::g_num_variations) { 1435 writer.AddPairString("num-experiments", 1436 child_process_logging::g_num_variations); 1437 writer.AddBoundary(); 1438 writer.Flush(); 1439 } 1440 1441 unsigned variation_chunks_len = 1442 my_strlen(child_process_logging::g_variation_chunks); 1443 if (variation_chunks_len) { 1444 static const char variation_msg[] = "experiment-chunk-"; 1445 static const unsigned kMaxVariationsLen = 1446 kMaxReportedVariationChunks * kMaxVariationChunkSize; 1447 writer.AddPairDataInChunks(variation_msg, sizeof(variation_msg) - 1, 1448 child_process_logging::g_variation_chunks, 1449 std::min(variation_chunks_len, kMaxVariationsLen), 1450 kMaxVariationChunkSize, 1451 true /* Strip whitespace since variation chunks are padded. */); 1452 } 1453 1454 if (info.oom_size) { 1455 char oom_size_str[kUint64StringSize]; 1456 const unsigned oom_size_len = my_uint64_len(info.oom_size); 1457 my_uint64tos(oom_size_str, info.oom_size, oom_size_len); 1458 static const char oom_size_msg[] = "oom-size"; 1459 writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, 1460 oom_size_str, oom_size_len); 1461 writer.AddBoundary(); 1462 writer.Flush(); 1463 } 1464 1465 if (info.crash_keys) { 1466 CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys); 1467 const CrashKeyStorage::Entry* entry; 1468 while ((entry = crash_key_iterator.Next())) { 1469 writer.AddPairString(entry->key, entry->value); 1470 writer.AddBoundary(); 1471 writer.Flush(); 1472 } 1473 } 1474 1475 writer.AddFileContents(g_dump_msg, dump_data, dump_size); 1476 #if defined(ADDRESS_SANITIZER) 1477 // Append a multipart boundary and the contents of the AddressSanitizer log. 1478 writer.AddBoundary(); 1479 writer.AddFileContents(g_log_msg, log_data, log_size); 1480 #endif 1481 writer.AddEnd(); 1482 writer.Flush(); 1483 1484 IGNORE_RET(sys_close(temp_file_fd)); 1485 1486 #if defined(OS_ANDROID) 1487 if (info.filename) { 1488 int filename_length = my_strlen(info.filename); 1489 1490 // If this was a file, we need to copy it to the right place and use the 1491 // right file name so it gets uploaded by the browser. 1492 const char msg[] = "Output crash dump file:"; 1493 WriteLog(msg, sizeof(msg) - 1); 1494 WriteLog(info.filename, filename_length - 1); 1495 1496 char pid_buf[kUint64StringSize]; 1497 uint64_t pid_str_length = my_uint64_len(info.pid); 1498 my_uint64tos(pid_buf, info.pid, pid_str_length); 1499 1500 // -1 because we won't need the null terminator on the original filename. 1501 unsigned done_filename_len = filename_length - 1 + pid_str_length; 1502 char* done_filename = reinterpret_cast<char*>( 1503 allocator.Alloc(done_filename_len)); 1504 // Rename the file such that the pid is the suffix in order signal to other 1505 // processes that the minidump is complete. The advantage of using the pid 1506 // as the suffix is that it is trivial to associate the minidump with the 1507 // crashed process. 1508 // Finally, note strncpy prevents null terminators from 1509 // being copied. Pad the rest with 0's. 1510 my_strncpy(done_filename, info.filename, done_filename_len); 1511 // Append the suffix a null terminator should be added. 1512 my_strncat(done_filename, pid_buf, pid_str_length); 1513 // Rename the minidump file to signal that it is complete. 1514 if (rename(info.filename, done_filename)) { 1515 const char failed_msg[] = "Failed to rename:"; 1516 WriteLog(failed_msg, sizeof(failed_msg) - 1); 1517 WriteLog(info.filename, filename_length - 1); 1518 const char to_msg[] = "to"; 1519 WriteLog(to_msg, sizeof(to_msg) - 1); 1520 WriteLog(done_filename, done_filename_len - 1); 1521 } 1522 } 1523 #endif 1524 1525 if (!info.upload) 1526 return; 1527 1528 const pid_t child = sys_fork(); 1529 if (!child) { 1530 // Spawned helper process. 1531 // 1532 // This code is called both when a browser is crashing (in which case, 1533 // nothing really matters any more) and when a renderer/plugin crashes, in 1534 // which case we need to continue. 1535 // 1536 // Since we are a multithreaded app, if we were just to fork(), we might 1537 // grab file descriptors which have just been created in another thread and 1538 // hold them open for too long. 1539 // 1540 // Thus, we have to loop and try and close everything. 1541 const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); 1542 if (fd < 0) { 1543 for (unsigned i = 3; i < 8192; ++i) 1544 IGNORE_RET(sys_close(i)); 1545 } else { 1546 google_breakpad::DirectoryReader reader(fd); 1547 const char* name; 1548 while (reader.GetNextEntry(&name)) { 1549 int i; 1550 if (my_strtoui(&i, name) && i > 2 && i != fd) 1551 IGNORE_RET(sys_close(i)); 1552 reader.PopEntry(); 1553 } 1554 1555 IGNORE_RET(sys_close(fd)); 1556 } 1557 1558 IGNORE_RET(sys_setsid()); 1559 1560 // Leave one end of a pipe in the upload process and watch for it getting 1561 // closed by the upload process exiting. 1562 int fds[2]; 1563 if (sys_pipe(fds) >= 0) { 1564 const pid_t upload_child = sys_fork(); 1565 if (!upload_child) { 1566 // Upload process. 1567 IGNORE_RET(sys_close(fds[0])); 1568 IGNORE_RET(sys_dup2(fds[1], 3)); 1569 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, 1570 &allocator); 1571 } 1572 1573 // Helper process. 1574 if (upload_child > 0) { 1575 IGNORE_RET(sys_close(fds[1])); 1576 char id_buf[17]; // Crash report IDs are expected to be 16 chars. 1577 ssize_t len = -1; 1578 // Upload should finish in about 10 seconds. Add a few more 500 ms 1579 // internals to account for process startup time. 1580 for (size_t wait_count = 0; wait_count < 24; ++wait_count) { 1581 struct kernel_pollfd poll_fd; 1582 poll_fd.fd = fds[0]; 1583 poll_fd.events = POLLIN | POLLPRI | POLLERR; 1584 int ret = sys_poll(&poll_fd, 1, 500); 1585 if (ret < 0) { 1586 // Error 1587 break; 1588 } else if (ret > 0) { 1589 // There is data to read. 1590 len = HANDLE_EINTR(sys_read(fds[0], id_buf, sizeof(id_buf) - 1)); 1591 break; 1592 } 1593 // ret == 0 -> timed out, continue waiting. 1594 } 1595 if (len > 0) { 1596 // Write crash dump id to stderr. 1597 id_buf[len] = 0; 1598 static const char msg[] = "\nCrash dump id: "; 1599 WriteLog(msg, sizeof(msg) - 1); 1600 WriteLog(id_buf, my_strlen(id_buf)); 1601 WriteLog("\n", 1); 1602 1603 // Write crash dump id to crash log as: seconds_since_epoch,crash_id 1604 struct kernel_timeval tv; 1605 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) { 1606 uint64_t time = kernel_timeval_to_ms(&tv) / 1000; 1607 char time_str[kUint64StringSize]; 1608 const unsigned time_len = my_uint64_len(time); 1609 my_uint64tos(time_str, time, time_len); 1610 1611 int log_fd = sys_open(g_crash_log_path, 1612 O_CREAT | O_WRONLY | O_APPEND, 1613 0600); 1614 if (log_fd > 0) { 1615 sys_write(log_fd, time_str, time_len); 1616 sys_write(log_fd, ",", 1); 1617 sys_write(log_fd, id_buf, my_strlen(id_buf)); 1618 sys_write(log_fd, "\n", 1); 1619 IGNORE_RET(sys_close(log_fd)); 1620 } 1621 } 1622 } 1623 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { 1624 // Upload process is still around, kill it. 1625 sys_kill(upload_child, SIGKILL); 1626 } 1627 } 1628 } 1629 1630 // Helper process. 1631 IGNORE_RET(sys_unlink(info.filename)); 1632 #if defined(ADDRESS_SANITIZER) 1633 IGNORE_RET(sys_unlink(info.log_filename)); 1634 #endif 1635 IGNORE_RET(sys_unlink(temp_file)); 1636 sys__exit(0); 1637 } 1638 1639 // Main browser process. 1640 if (child <= 0) 1641 return; 1642 (void) HANDLE_EINTR(sys_waitpid(child, NULL, 0)); 1643 } 1644 1645 void InitCrashReporter() { 1646 #if defined(OS_ANDROID) 1647 // This will guarantee that the BuildInfo has been initialized and subsequent 1648 // calls will not require memory allocation. 1649 base::android::BuildInfo::GetInstance(); 1650 #endif 1651 // Determine the process type and take appropriate action. 1652 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 1653 if (parsed_command_line.HasSwitch(switches::kDisableBreakpad)) 1654 return; 1655 1656 const std::string process_type = 1657 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); 1658 if (process_type.empty()) { 1659 EnableCrashDumping(breakpad::GetBreakpadClient()->IsRunningUnattended()); 1660 } else if (process_type == switches::kRendererProcess || 1661 process_type == switches::kPluginProcess || 1662 process_type == switches::kPpapiPluginProcess || 1663 process_type == switches::kZygoteProcess || 1664 process_type == switches::kGpuProcess) { 1665 #if defined(OS_ANDROID) 1666 NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of " 1667 "InitNonBrowserCrashReporter in " << process_type << " process."; 1668 return; 1669 #else 1670 // We might be chrooted in a zygote or renderer process so we cannot call 1671 // GetCollectStatsConsent because that needs access the the user's home 1672 // dir. Instead, we set a command line flag for these processes. 1673 // Even though plugins are not chrooted, we share the same code path for 1674 // simplicity. 1675 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) 1676 return; 1677 SetClientIdFromCommandLine(parsed_command_line); 1678 EnableNonBrowserCrashDumping(); 1679 VLOG(1) << "Non Browser crash dumping enabled for: " << process_type; 1680 #endif // #if defined(OS_ANDROID) 1681 } 1682 1683 SetProcessStartTime(); 1684 1685 breakpad::GetBreakpadClient()->SetDumpWithoutCrashingFunction(&DumpProcess); 1686 #if defined(ADDRESS_SANITIZER) 1687 // Register the callback for AddressSanitizer error reporting. 1688 __asan_set_error_report_callback(AsanLinuxBreakpadCallback); 1689 #endif 1690 1691 g_crash_keys = new CrashKeyStorage; 1692 breakpad::GetBreakpadClient()->RegisterCrashKeys(); 1693 base::debug::SetCrashKeyReportingFunctions( 1694 &SetCrashKeyValue, &ClearCrashKey); 1695 } 1696 1697 #if defined(OS_ANDROID) 1698 void InitNonBrowserCrashReporterForAndroid() { 1699 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 1700 if (command_line->HasSwitch(switches::kEnableCrashReporter)) { 1701 // On Android we need to provide a FD to the file where the minidump is 1702 // generated as the renderer and browser run with different UIDs 1703 // (preventing the browser from inspecting the renderer process). 1704 int minidump_fd = base::GlobalDescriptors::GetInstance()-> 1705 MaybeGet(breakpad::GetBreakpadClient()->GetAndroidMinidumpDescriptor()); 1706 if (minidump_fd == base::kInvalidPlatformFileValue) { 1707 NOTREACHED() << "Could not find minidump FD, crash reporting disabled."; 1708 } else { 1709 EnableNonBrowserCrashDumping(minidump_fd); 1710 } 1711 } 1712 } 1713 #endif // OS_ANDROID 1714 1715 bool IsCrashReporterEnabled() { 1716 return g_is_crash_reporter_enabled; 1717 } 1718