OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // For linux_syscall_support.h. This makes it safe to call embedded system | 5 // For linux_syscall_support.h. This makes it safe to call embedded system |
6 // calls when in seccomp mode. | 6 // calls when in seccomp mode. |
7 | 7 |
8 #include "components/breakpad/app/breakpad_linux.h" | 8 #include "components/breakpad/app/breakpad_linux.h" |
9 | 9 |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 while (*dest) | 182 while (*dest) |
183 dest++; | 183 dest++; |
184 while (len--) | 184 while (len--) |
185 if (!(*dest++ = *src++)) | 185 if (!(*dest++ = *src++)) |
186 return ret; | 186 return ret; |
187 *dest = 0; | 187 *dest = 0; |
188 return ret; | 188 return ret; |
189 } | 189 } |
190 #endif | 190 #endif |
191 | 191 |
| 192 #if !defined(OS_CHROMEOS) |
| 193 bool my_isxdigit(char c) { |
| 194 return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); |
| 195 } |
| 196 #endif |
| 197 |
192 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { | 198 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { |
193 while (len > 0 && str[len - 1] == ' ') { | 199 while (len > 0 && str[len - 1] == ' ') { |
194 len--; | 200 len--; |
195 } | 201 } |
196 return len; | 202 return len; |
197 } | 203 } |
198 | 204 |
199 // Populates the passed in allocated string and its size with the distro of | 205 // Populates the passed in allocated string and its size with the distro of |
200 // the crashing process. | 206 // the crashing process. |
201 // The passed string is expected to be at least kDistroSize bytes long. | 207 // The passed string is expected to be at least kDistroSize bytes long. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 void AddItemWithoutTrailingSpaces(const void* base, size_t size); | 296 void AddItemWithoutTrailingSpaces(const void* base, size_t size); |
291 | 297 |
292 struct kernel_iovec iov_[kIovCapacity]; | 298 struct kernel_iovec iov_[kIovCapacity]; |
293 int iov_index_; | 299 int iov_index_; |
294 | 300 |
295 // Output file descriptor. | 301 // Output file descriptor. |
296 int fd_; | 302 int fd_; |
297 | 303 |
298 const char* const mime_boundary_; | 304 const char* const mime_boundary_; |
299 | 305 |
| 306 private: |
300 DISALLOW_COPY_AND_ASSIGN(MimeWriter); | 307 DISALLOW_COPY_AND_ASSIGN(MimeWriter); |
301 }; | 308 }; |
302 | 309 |
303 MimeWriter::MimeWriter(int fd, const char* const mime_boundary) | 310 MimeWriter::MimeWriter(int fd, const char* const mime_boundary) |
304 : iov_index_(0), | 311 : iov_index_(0), |
305 fd_(fd), | 312 fd_(fd), |
306 mime_boundary_(mime_boundary) { | 313 mime_boundary_(mime_boundary) { |
307 } | 314 } |
308 | 315 |
309 MimeWriter::~MimeWriter() { | 316 MimeWriter::~MimeWriter() { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 | 403 |
397 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { | 404 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { |
398 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base), | 405 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base), |
399 size)); | 406 size)); |
400 } | 407 } |
401 | 408 |
402 #if defined(OS_CHROMEOS) | 409 #if defined(OS_CHROMEOS) |
403 // This subclass is used on Chromium OS to report crashes in a format easy for | 410 // This subclass is used on Chromium OS to report crashes in a format easy for |
404 // the central crash reporting facility to understand. | 411 // the central crash reporting facility to understand. |
405 // Format is <name>:<data length in decimal>:<data> | 412 // Format is <name>:<data length in decimal>:<data> |
406 class CrashReporterWriter : public MimeWriter | 413 class CrashReporterWriter : public MimeWriter { |
407 { | |
408 public: | 414 public: |
409 explicit CrashReporterWriter(int fd); | 415 explicit CrashReporterWriter(int fd); |
410 | 416 |
411 virtual void AddBoundary() OVERRIDE; | 417 virtual void AddBoundary() OVERRIDE; |
412 | 418 |
413 virtual void AddEnd() OVERRIDE; | 419 virtual void AddEnd() OVERRIDE; |
414 | 420 |
415 virtual void AddPairData(const char* msg_type, | 421 virtual void AddPairData(const char* msg_type, |
416 size_t msg_type_size, | 422 size_t msg_type_size, |
417 const char* msg_data, | 423 const char* msg_data, |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 #endif | 531 #endif |
526 | 532 |
527 size_t WriteLog(const char* buf, size_t nbytes) { | 533 size_t WriteLog(const char* buf, size_t nbytes) { |
528 #if defined(OS_ANDROID) | 534 #if defined(OS_ANDROID) |
529 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf); | 535 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf); |
530 #else | 536 #else |
531 return sys_write(2, buf, nbytes); | 537 return sys_write(2, buf, nbytes); |
532 #endif | 538 #endif |
533 } | 539 } |
534 | 540 |
| 541 size_t WriteNewline() { |
| 542 return WriteLog("\n", 1); |
| 543 } |
| 544 |
535 #if defined(OS_ANDROID) | 545 #if defined(OS_ANDROID) |
536 // Android's native crash handler outputs a diagnostic tombstone to the device | 546 // Android's native crash handler outputs a diagnostic tombstone to the device |
537 // log. By returning false from the HandlerCallbacks, breakpad will reinstall | 547 // log. By returning false from the HandlerCallbacks, breakpad will reinstall |
538 // the previous (i.e. native) signal handlers before returning from its own | 548 // the previous (i.e. native) signal handlers before returning from its own |
539 // handler. A Chrome build fingerprint is written to the log, so that the | 549 // handler. A Chrome build fingerprint is written to the log, so that the |
540 // specific build of Chrome and the location of the archived Chrome symbols can | 550 // specific build of Chrome and the location of the archived Chrome symbols can |
541 // be determined directly from it. | 551 // be determined directly from it. |
542 bool FinalizeCrashDoneAndroid() { | 552 bool FinalizeCrashDoneAndroid() { |
543 base::android::BuildInfo* android_build_info = | 553 base::android::BuildInfo* android_build_info = |
544 base::android::BuildInfo::GetInstance(); | 554 base::android::BuildInfo::GetInstance(); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 info.distro_length = distro_length; | 709 info.distro_length = distro_length; |
700 info.upload = false; | 710 info.upload = false; |
701 info.process_start_time = g_process_start_time; | 711 info.process_start_time = g_process_start_time; |
702 info.pid = g_pid; | 712 info.pid = g_pid; |
703 info.crash_keys = g_crash_keys; | 713 info.crash_keys = g_crash_keys; |
704 HandleCrashDump(info); | 714 HandleCrashDump(info); |
705 bool finalize_result = FinalizeCrashDoneAndroid(); | 715 bool finalize_result = FinalizeCrashDoneAndroid(); |
706 base::android::BuildInfo* android_build_info = | 716 base::android::BuildInfo* android_build_info = |
707 base::android::BuildInfo::GetInstance(); | 717 base::android::BuildInfo::GetInstance(); |
708 if (android_build_info->sdk_int() >= 18 && | 718 if (android_build_info->sdk_int() >= 18 && |
709 strcmp(android_build_info->build_type(), "eng") != 0 && | 719 my_strcmp(android_build_info->build_type(), "eng") != 0 && |
710 strcmp(android_build_info->build_type(), "userdebug") != 0) { | 720 my_strcmp(android_build_info->build_type(), "userdebug") != 0) { |
711 // On JB MR2 and later, the system crash handler displays a dialog. For | 721 // On JB MR2 and later, the system crash handler displays a dialog. For |
712 // renderer crashes, this is a bad user experience and so this is disabled | 722 // renderer crashes, this is a bad user experience and so this is disabled |
713 // for user builds of Android. | 723 // for user builds of Android. |
714 // TODO(cjhopman): There should be some way to recover the crash stack from | 724 // TODO(cjhopman): There should be some way to recover the crash stack from |
715 // non-uploading user clients. See http://crbug.com/273706. | 725 // non-uploading user clients. See http://crbug.com/273706. |
716 __android_log_write(ANDROID_LOG_WARN, | 726 __android_log_write(ANDROID_LOG_WARN, |
717 kGoogleBreakpad, | 727 kGoogleBreakpad, |
718 "Tombstones are disabled on JB MR2+ user builds."); | 728 "Tombstones are disabled on JB MR2+ user builds."); |
719 __android_log_write(ANDROID_LOG_WARN, | 729 __android_log_write(ANDROID_LOG_WARN, |
720 kGoogleBreakpad, | 730 kGoogleBreakpad, |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 NULL, | 1023 NULL, |
1014 }; | 1024 }; |
1015 static const char msg[] = "Cannot upload crash dump: cannot exec " | 1025 static const char msg[] = "Cannot upload crash dump: cannot exec " |
1016 "/usr/bin/wget\n"; | 1026 "/usr/bin/wget\n"; |
1017 #endif | 1027 #endif |
1018 execve(args[0], const_cast<char**>(args), environ); | 1028 execve(args[0], const_cast<char**>(args), environ); |
1019 WriteLog(msg, sizeof(msg) - 1); | 1029 WriteLog(msg, sizeof(msg) - 1); |
1020 sys__exit(1); | 1030 sys__exit(1); |
1021 } | 1031 } |
1022 | 1032 |
| 1033 // Runs in the helper process to wait for the upload process running |
| 1034 // ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written |
| 1035 // to |fd| and save the written contents to |buf|. |
| 1036 // |buf| needs to be big enough to hold |bytes_to_read| + 1 characters. |
| 1037 size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read, |
| 1038 char* buf) { |
| 1039 size_t bytes_read = 0; |
| 1040 |
| 1041 // Upload should finish in about 10 seconds. Add a few more 500 ms |
| 1042 // internals to account for process startup time. |
| 1043 for (size_t wait_count = 0; wait_count < 24; ++wait_count) { |
| 1044 struct kernel_pollfd poll_fd; |
| 1045 poll_fd.fd = fd; |
| 1046 poll_fd.events = POLLIN | POLLPRI | POLLERR; |
| 1047 int ret = sys_poll(&poll_fd, 1, 500); |
| 1048 if (ret < 0) { |
| 1049 // Error |
| 1050 break; |
| 1051 } else if (ret > 0) { |
| 1052 // There is data to read. |
| 1053 ssize_t len = HANDLE_EINTR( |
| 1054 sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read)); |
| 1055 if (len < 0) |
| 1056 break; |
| 1057 bytes_read += len; |
| 1058 if (bytes_read == bytes_to_read) |
| 1059 break; |
| 1060 } |
| 1061 // |ret| == 0 -> timed out, continue waiting. |
| 1062 // or |bytes_read| < |bytes_to_read| still, keep reading. |
| 1063 } |
| 1064 buf[bytes_to_read] = 0; // Always NUL terminate the buffer. |
| 1065 return bytes_read; |
| 1066 } |
| 1067 |
| 1068 // |buf| should be |expected_len| + 1 characters in size and NULL terminated. |
| 1069 bool IsValidCrashReportId(const char* buf, size_t bytes_read, |
| 1070 size_t expected_len) { |
| 1071 if (bytes_read != expected_len) |
| 1072 return false; |
| 1073 #if defined(OS_CHROMEOS) |
| 1074 return my_strcmp(buf, "_sys_cr_finished") == 0; |
| 1075 #else |
| 1076 for (size_t i = 0; i <= bytes_read; ++i) { |
| 1077 if (!my_isxdigit(buf[i])) |
| 1078 return false; |
| 1079 } |
| 1080 return true; |
| 1081 #endif |
| 1082 } |
| 1083 |
| 1084 // |buf| should be |expected_len| + 1 characters in size and NULL terminated. |
| 1085 void HandleCrashReportId(const char* buf, size_t bytes_read, |
| 1086 size_t expected_len) { |
| 1087 WriteNewline(); |
| 1088 if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { |
| 1089 #if defined(OS_CHROMEOS) |
| 1090 static const char msg[] = "Crash_reporter failed to process crash report"; |
| 1091 #else |
| 1092 static const char msg[] = "Failed to get crash dump id."; |
| 1093 #endif |
| 1094 WriteLog(msg, sizeof(msg) - 1); |
| 1095 WriteNewline(); |
| 1096 return; |
| 1097 } |
| 1098 |
| 1099 #if defined(OS_CHROMEOS) |
| 1100 static const char msg[] = "Crash dump received by crash_reporter\n"; |
| 1101 WriteLog(msg, sizeof(msg) - 1); |
| 1102 #else |
| 1103 // Write crash dump id to stderr. |
| 1104 static const char msg[] = "Crash dump id: "; |
| 1105 WriteLog(msg, sizeof(msg) - 1); |
| 1106 WriteLog(buf, my_strlen(buf)); |
| 1107 WriteNewline(); |
| 1108 |
| 1109 // Write crash dump id to crash log as: seconds_since_epoch,crash_id |
| 1110 struct kernel_timeval tv; |
| 1111 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) { |
| 1112 uint64_t time = kernel_timeval_to_ms(&tv) / 1000; |
| 1113 char time_str[kUint64StringSize]; |
| 1114 const unsigned time_len = my_uint64_len(time); |
| 1115 my_uint64tos(time_str, time, time_len); |
| 1116 |
| 1117 const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC; |
| 1118 int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600); |
| 1119 if (log_fd > 0) { |
| 1120 sys_write(log_fd, time_str, time_len); |
| 1121 sys_write(log_fd, ",", 1); |
| 1122 sys_write(log_fd, buf, my_strlen(buf)); |
| 1123 sys_write(log_fd, "\n", 1); |
| 1124 IGNORE_RET(sys_close(log_fd)); |
| 1125 } |
| 1126 } |
| 1127 #endif |
| 1128 } |
| 1129 |
1023 #if defined(OS_CHROMEOS) | 1130 #if defined(OS_CHROMEOS) |
1024 const char* GetCrashingProcessName(const BreakpadInfo& info, | 1131 const char* GetCrashingProcessName(const BreakpadInfo& info, |
1025 google_breakpad::PageAllocator* allocator) { | 1132 google_breakpad::PageAllocator* allocator) { |
1026 // Symlink to process binary is at /proc/###/exe. | 1133 // Symlink to process binary is at /proc/###/exe. |
1027 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] = | 1134 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] = |
1028 "/proc/"; | 1135 "/proc/"; |
1029 uint64_t pid_value_len = my_uint64_len(info.pid); | 1136 uint64_t pid_value_len = my_uint64_len(info.pid); |
1030 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len); | 1137 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len); |
1031 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0'; | 1138 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0'; |
1032 my_strlcat(linkpath, "/exe", sizeof(linkpath)); | 1139 my_strlcat(linkpath, "/exe", sizeof(linkpath)); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1198 // Content-Type: application/octet-stream \r\n \r\n | 1305 // Content-Type: application/octet-stream \r\n \r\n |
1199 // <dump contents> | 1306 // <dump contents> |
1200 // \r\n BOUNDARY -- \r\n | 1307 // \r\n BOUNDARY -- \r\n |
1201 | 1308 |
1202 #if defined(OS_CHROMEOS) | 1309 #if defined(OS_CHROMEOS) |
1203 CrashReporterWriter writer(temp_file_fd); | 1310 CrashReporterWriter writer(temp_file_fd); |
1204 #else | 1311 #else |
1205 MimeWriter writer(temp_file_fd, mime_boundary); | 1312 MimeWriter writer(temp_file_fd, mime_boundary); |
1206 #endif | 1313 #endif |
1207 { | 1314 { |
| 1315 // TODO(thestig) Do not use this inside a compromised context. |
1208 std::string product_name; | 1316 std::string product_name; |
1209 std::string version; | 1317 std::string version; |
1210 | 1318 |
1211 GetBreakpadClient()->GetProductNameAndVersion(&product_name, &version); | 1319 GetBreakpadClient()->GetProductNameAndVersion(&product_name, &version); |
1212 | 1320 |
1213 writer.AddBoundary(); | 1321 writer.AddBoundary(); |
1214 writer.AddPairString("prod", product_name.c_str()); | 1322 writer.AddPairString("prod", product_name.c_str()); |
1215 writer.AddBoundary(); | 1323 writer.AddBoundary(); |
1216 writer.AddPairString("ver", version.c_str()); | 1324 writer.AddPairString("ver", version.c_str()); |
1217 writer.AddBoundary(); | 1325 writer.AddBoundary(); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 // Upload process. | 1511 // Upload process. |
1404 IGNORE_RET(sys_close(fds[0])); | 1512 IGNORE_RET(sys_close(fds[0])); |
1405 IGNORE_RET(sys_dup2(fds[1], 3)); | 1513 IGNORE_RET(sys_dup2(fds[1], 3)); |
1406 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, | 1514 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, |
1407 &allocator); | 1515 &allocator); |
1408 } | 1516 } |
1409 | 1517 |
1410 // Helper process. | 1518 // Helper process. |
1411 if (upload_child > 0) { | 1519 if (upload_child > 0) { |
1412 IGNORE_RET(sys_close(fds[1])); | 1520 IGNORE_RET(sys_close(fds[1])); |
1413 char id_buf[17]; // Crash report IDs are expected to be 16 chars. | |
1414 ssize_t len = -1; | |
1415 // Upload should finish in about 10 seconds. Add a few more 500 ms | |
1416 // internals to account for process startup time. | |
1417 for (size_t wait_count = 0; wait_count < 24; ++wait_count) { | |
1418 struct kernel_pollfd poll_fd; | |
1419 poll_fd.fd = fds[0]; | |
1420 poll_fd.events = POLLIN | POLLPRI | POLLERR; | |
1421 int ret = sys_poll(&poll_fd, 1, 500); | |
1422 if (ret < 0) { | |
1423 // Error | |
1424 break; | |
1425 } else if (ret > 0) { | |
1426 // There is data to read. | |
1427 len = HANDLE_EINTR(sys_read(fds[0], id_buf, sizeof(id_buf) - 1)); | |
1428 break; | |
1429 } | |
1430 // ret == 0 -> timed out, continue waiting. | |
1431 } | |
1432 if (len > 0) { | |
1433 // Write crash dump id to stderr. | |
1434 id_buf[len] = 0; | |
1435 static const char msg[] = "\nCrash dump id: "; | |
1436 WriteLog(msg, sizeof(msg) - 1); | |
1437 WriteLog(id_buf, my_strlen(id_buf)); | |
1438 WriteLog("\n", 1); | |
1439 | 1521 |
1440 // Write crash dump id to crash log as: seconds_since_epoch,crash_id | 1522 const size_t kCrashIdLength = 16; |
1441 struct kernel_timeval tv; | 1523 char id_buf[kCrashIdLength + 1]; |
1442 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) { | 1524 size_t bytes_read = |
1443 uint64_t time = kernel_timeval_to_ms(&tv) / 1000; | 1525 WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf); |
1444 char time_str[kUint64StringSize]; | 1526 HandleCrashReportId(id_buf, bytes_read, kCrashIdLength); |
1445 const unsigned time_len = my_uint64_len(time); | |
1446 my_uint64tos(time_str, time, time_len); | |
1447 | 1527 |
1448 int log_fd = sys_open(g_crash_log_path, | |
1449 O_CREAT | O_WRONLY | O_APPEND, | |
1450 0600); | |
1451 if (log_fd > 0) { | |
1452 sys_write(log_fd, time_str, time_len); | |
1453 sys_write(log_fd, ",", 1); | |
1454 sys_write(log_fd, id_buf, my_strlen(id_buf)); | |
1455 sys_write(log_fd, "\n", 1); | |
1456 IGNORE_RET(sys_close(log_fd)); | |
1457 } | |
1458 } | |
1459 } | |
1460 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { | 1528 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { |
1461 // Upload process is still around, kill it. | 1529 // Upload process is still around, kill it. |
1462 sys_kill(upload_child, SIGKILL); | 1530 sys_kill(upload_child, SIGKILL); |
1463 } | 1531 } |
1464 } | 1532 } |
1465 } | 1533 } |
1466 | 1534 |
1467 // Helper process. | 1535 // Helper process. |
1468 IGNORE_RET(sys_unlink(info.filename)); | 1536 IGNORE_RET(sys_unlink(info.filename)); |
1469 #if defined(ADDRESS_SANITIZER) | 1537 #if defined(ADDRESS_SANITIZER) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1545 } | 1613 } |
1546 } | 1614 } |
1547 } | 1615 } |
1548 #endif // OS_ANDROID | 1616 #endif // OS_ANDROID |
1549 | 1617 |
1550 bool IsCrashReporterEnabled() { | 1618 bool IsCrashReporterEnabled() { |
1551 return g_is_crash_reporter_enabled; | 1619 return g_is_crash_reporter_enabled; |
1552 } | 1620 } |
1553 | 1621 |
1554 } // namespace breakpad | 1622 } // namespace breakpad |
OLD | NEW |