Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Unified Diff: components/crash/content/app/breakpad_linux.cc

Issue 2676023003: breakpad: Fix crash_reporter upload success handling on Chrome OS (Closed)
Patch Set: add trailing \n Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/crash/content/app/breakpad_linux.cc
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index 6e5058e9563ebfbe932835c763dc04712d682979..b621143ecbf2d3fd153272fbfe3b35b49efc4376 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -100,6 +100,7 @@ ExceptionHandler* g_breakpad = nullptr;
#if defined(ADDRESS_SANITIZER)
const char* g_asan_report_str = nullptr;
#endif
+
#if defined(OS_ANDROID)
#define G_DUMPS_SUPPRESSED_MAGIC 0x5AFECEDE
uint32_t g_dumps_suppressed = 0;
@@ -1157,16 +1158,41 @@ void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
LoadDataFromFD(allocator, *fd, true, file_data, size);
}
+// Concatenates a |prefix| and a |number| to get a string like "--foo=123" or
+// "/dev/fd/4". Safe to run in a compromised context. The returned memory is
+// internally owned by |allocator|.
+char* StringFromPrefixAndUint(const char* prefix,
+ uint64_t number,
+ google_breakpad::PageAllocator* allocator) {
+ // Convert the number to a string.
+ char number_buf[kUint64StringSize];
+ const unsigned number_len = my_uint64_len(number);
+ my_uint64tos(number_buf, number, number_len);
+ number_buf[number_len] = '\0';
+
+ // Concatenate the prefix and number.
+ size_t output_len = my_strlen(prefix) + my_strlen(number_buf) + 1;
+ char* output = reinterpret_cast<char*>(allocator->Alloc(output_len));
+ my_strlcpy(output, prefix, output_len);
+ my_strlcat(output, number_buf, output_len);
+ return output;
+}
+
// Spawn the appropriate upload process for the current OS:
// - generic Linux invokes wget.
-// - ChromeOS invokes crash_reporter.
+// - Chrome OS invokes crash_reporter. Crashes are uploaded by a separate
+// crash_sender script that runs periodically.
// |dumpfile| is the path to the dump data file.
// |mime_boundary| is only used on Linux.
// |exe_buf| is only used on CrOS and is the crashing process' name.
+// |upload_status_fd| is the file descriptor of a pipe that will receive:
+// - On Linux, the crash report id
+// - On Chrome OS, the magic crash complete string.
void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
const char* dumpfile,
const char* mime_boundary,
const char* exe_buf,
+ int upload_status_fd,
google_breakpad::PageAllocator* allocator) {
#if defined(OS_CHROMEOS)
// CrOS uses crash_reporter instead of wget to report crashes,
@@ -1174,16 +1200,13 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
// crashing process.
static const char kCrashReporterBinary[] = "/sbin/crash_reporter";
- char pid_buf[kUint64StringSize];
- uint64_t pid_str_length = my_uint64_len(info.pid);
- my_uint64tos(pid_buf, info.pid, pid_str_length);
- pid_buf[pid_str_length] = '\0';
-
- char uid_buf[kUint64StringSize];
- uid_t uid = geteuid();
- uint64_t uid_str_length = my_uint64_len(uid);
- my_uint64tos(uid_buf, uid, uid_str_length);
- uid_buf[uid_str_length] = '\0';
+ // crash_reporter writes output to stdout. Connect it to the status pipe fd.
+ if (sys_dup2(upload_status_fd, STDOUT_FILENO) == -1) {
+ const char err[] = "dup2 failed\n";
+ WriteLog(err, sizeof(err) - 1);
+ // Continue anyway, as crash_report may succeed even if we can't read its
+ // status.
+ }
const char kChromeFlag[] = "--chrome=";
size_t buf_len = my_strlen(dumpfile) + sizeof(kChromeFlag);
@@ -1192,19 +1215,8 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
my_strlcat(chrome_flag, kChromeFlag, buf_len);
my_strlcat(chrome_flag, dumpfile, buf_len);
- const char kPidFlag[] = "--pid=";
- buf_len = my_strlen(pid_buf) + sizeof(kPidFlag);
- char* pid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
- pid_flag[0] = '\0';
- my_strlcat(pid_flag, kPidFlag, buf_len);
- my_strlcat(pid_flag, pid_buf, buf_len);
-
- const char kUidFlag[] = "--uid=";
- buf_len = my_strlen(uid_buf) + sizeof(kUidFlag);
- char* uid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
- uid_flag[0] = '\0';
- my_strlcat(uid_flag, kUidFlag, buf_len);
- my_strlcat(uid_flag, uid_buf, buf_len);
+ char* pid_flag = StringFromPrefixAndUint("--pid=", info.pid, allocator);
+ char* uid_flag = StringFromPrefixAndUint("--uid=", geteuid(), allocator);
const char kExeBuf[] = "--exe=";
buf_len = my_strlen(exe_buf) + sizeof(kExeBuf);
@@ -1223,7 +1235,9 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
};
static const char msg[] = "Cannot upload crash dump: cannot exec "
"/sbin/crash_reporter\n";
-#else
+
+#else // defined(OS_CHROMEOS)
+
// Compress |dumpfile| with gzip.
const pid_t gzip_child = sys_fork();
if (gzip_child < 0) {
@@ -1293,6 +1307,10 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
my_strlcpy(post_file, post_file_msg, post_file_size);
my_strlcat(post_file, dumpfile, post_file_size);
+ // Write the wget status output to the status pipe file descriptor path.
+ char* status_fd_path =
+ StringFromPrefixAndUint("/dev/fd/", upload_status_fd, allocator);
+
static const char kWgetBinary[] = "/usr/bin/wget";
const char* args[] = {
kWgetBinary,
@@ -1302,13 +1320,14 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
kUploadURL,
"--timeout=10", // Set a timeout so we don't hang forever.
"--tries=1", // Don't retry if the upload fails.
- "-O", // output reply to fd 3
- "/dev/fd/3",
+ "-O", // Output reply to the file descriptor path.
+ status_fd_path,
nullptr,
};
static const char msg[] = "Cannot upload crash dump: cannot exec "
"/usr/bin/wget\n";
-#endif
+#endif // defined(OS_CHROMEOS)
+
execve(args[0], const_cast<char**>(args), environ);
WriteLog(msg, sizeof(msg) - 1);
sys__exit(1);
@@ -1352,9 +1371,13 @@ size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read,
// |buf| should be |expected_len| + 1 characters in size and nullptr terminated.
bool IsValidCrashReportId(const char* buf, size_t bytes_read,
size_t expected_len) {
- if (bytes_read != expected_len)
+ if (bytes_read != expected_len) {
+ static const char msg[] = "Unexpected crash report id length\n";
+ WriteLog(msg, sizeof(msg) - 1);
return false;
+ }
#if defined(OS_CHROMEOS)
+ // See kSuccessMagic in platform2/crash-reporter/chrome_collector.cc.
return my_strcmp(buf, "_sys_cr_finished") == 0;
#else
for (size_t i = 0; i < bytes_read; ++i) {
@@ -1372,7 +1395,7 @@ void HandleCrashReportId(const char* buf, size_t bytes_read,
if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
#if defined(OS_CHROMEOS)
static const char msg[] =
- "System crash-reporter failed to process crash report.";
+ "System crash_reporter failed to process crash report.";
#else
static const char msg[] = "Failed to get crash dump id.";
#endif
@@ -1447,6 +1470,27 @@ const char* GetCrashingProcessName(const BreakpadInfo& info,
}
#endif
+// Attempts to close all open file descriptors other than stdin, stdout and
+// stderr (0, 1, and 2).
+void CloseAllFileDescriptors() {
+ const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
+ if (fd < 0) {
+ for (unsigned i = 3; i < 8192; ++i)
+ IGNORE_RET(sys_close(i));
+ } else {
+ google_breakpad::DirectoryReader reader(fd);
+ const char* name;
+ while (reader.GetNextEntry(&name)) {
+ int i;
+ if (my_strtoui(&i, name) && i > 2 && i != fd)
+ IGNORE_RET(sys_close(i));
+ reader.PopEntry();
+ }
+
+ IGNORE_RET(sys_close(fd));
+ }
+}
+
void HandleCrashDump(const BreakpadInfo& info) {
int dumpfd;
bool keep_fd = false;
@@ -1779,22 +1823,7 @@ void HandleCrashDump(const BreakpadInfo& info) {
// hold them open for too long.
//
// Thus, we have to loop and try and close everything.
- const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
- if (fd < 0) {
- for (unsigned i = 3; i < 8192; ++i)
- IGNORE_RET(sys_close(i));
- } else {
- google_breakpad::DirectoryReader reader(fd);
- const char* name;
- while (reader.GetNextEntry(&name)) {
- int i;
- if (my_strtoui(&i, name) && i > 2 && i != fd)
- IGNORE_RET(sys_close(i));
- reader.PopEntry();
- }
-
- IGNORE_RET(sys_close(fd));
- }
+ CloseAllFileDescriptors();
IGNORE_RET(sys_setsid());
@@ -1805,15 +1834,15 @@ void HandleCrashDump(const BreakpadInfo& info) {
const pid_t upload_child = sys_fork();
if (!upload_child) {
// Upload process.
- IGNORE_RET(sys_close(fds[0]));
- IGNORE_RET(sys_dup2(fds[1], 3));
+ IGNORE_RET(sys_close(fds[0])); // Close read end of pipe.
+ // Write status to the pipe.
ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
- &allocator);
+ fds[1], &allocator);
}
// Helper process.
if (upload_child > 0) {
- IGNORE_RET(sys_close(fds[1]));
+ IGNORE_RET(sys_close(fds[1])); // Close write end of pipe.
const size_t kCrashIdLength = 16;
char id_buf[kCrashIdLength + 1];
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698