Mike Frysinger | 57b261c | 2012-04-11 14:47:09 -0400 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 5 | #include "crash-reporter/user_collector.h" |
| 6 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 7 | #include <bits/wordsize.h> |
| 8 | #include <elf.h> |
| 9 | #include <fcntl.h> |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 10 | #include <grp.h> // For struct group. |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 11 | #include <pcrecpp.h> |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 12 | #include <pwd.h> // For struct passwd. |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 13 | #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 14 | |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 15 | #include <string> |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 16 | #include <vector> |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 17 | |
| 18 | #include "base/file_util.h" |
| 19 | #include "base/logging.h" |
Mike Frysinger | 1a8780d | 2013-02-14 22:39:57 -0500 | [diff] [blame] | 20 | #include "base/posix/eintr_wrapper.h" |
Michael Krebs | 2f3ed03 | 2012-08-21 20:17:03 -0700 | [diff] [blame] | 21 | #include "base/stl_util.h" |
Chris Masone | 8a68c7c | 2011-05-14 11:44:04 -0700 | [diff] [blame] | 22 | #include "base/string_split.h" |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 23 | #include "base/string_util.h" |
Mike Frysinger | 57b261c | 2012-04-11 14:47:09 -0400 | [diff] [blame] | 24 | #include "base/stringprintf.h" |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 25 | #include "chromeos/process.h" |
| 26 | #include "chromeos/syslog_logging.h" |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 27 | #include "gflags/gflags.h" |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 28 | |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 29 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 30 | DEFINE_bool(core2md_failure, false, "Core2md failure test"); |
| 31 | DEFINE_bool(directory_failure, false, "Spool directory failure test"); |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 32 | DEFINE_string(filter_in, "", |
| 33 | "Ignore all crashes but this for testing"); |
| 34 | #pragma GCC diagnostic error "-Wstrict-aliasing" |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 35 | |
| 36 | static const char kCollectionErrorSignature[] = |
| 37 | "crash_reporter-user-collection"; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 38 | // This procfs file is used to cause kernel core file writing to |
| 39 | // instead pipe the core file into a user space process. See |
| 40 | // core(5) man page. |
| 41 | static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern"; |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 42 | static const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit"; |
| 43 | // Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent |
| 44 | // crashes, but finite to avoid infinitely recursing on crash handling. |
| 45 | static const char kCorePipeLimit[] = "4"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 46 | static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 47 | |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 48 | static const char kStatePrefix[] = "State:\t"; |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 49 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 50 | // Define an otherwise invalid value that represents an unknown UID. |
| 51 | static const uid_t kUnknownUid = -1; |
| 52 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 53 | const char *UserCollector::kUserId = "Uid:\t"; |
| 54 | const char *UserCollector::kGroupId = "Gid:\t"; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 55 | |
Simon Que | 9f90aca | 2013-02-19 17:19:52 -0800 | [diff] [blame] | 56 | using base::FilePath; |
| 57 | |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 58 | UserCollector::UserCollector() |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 59 | : generate_diagnostics_(false), |
| 60 | core_pattern_file_(kCorePatternFile), |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 61 | core_pipe_limit_file_(kCorePipeLimitFile), |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 62 | initialized_(false) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | void UserCollector::Initialize( |
| 66 | UserCollector::CountCrashFunction count_crash_function, |
| 67 | const std::string &our_path, |
| 68 | UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 69 | bool generate_diagnostics) { |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 70 | CrashCollector::Initialize(count_crash_function, |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 71 | is_feedback_allowed_function); |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 72 | our_path_ = our_path; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 73 | initialized_ = true; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 74 | generate_diagnostics_ = generate_diagnostics; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | UserCollector::~UserCollector() { |
| 78 | } |
| 79 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 80 | std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const { |
| 81 | switch (error_type) { |
| 82 | case kErrorSystemIssue: |
| 83 | return "system-issue"; |
| 84 | case kErrorReadCoreData: |
| 85 | return "read-core-data"; |
| 86 | case kErrorUnusableProcFiles: |
| 87 | return "unusable-proc-files"; |
| 88 | case kErrorInvalidCoreFile: |
| 89 | return "invalid-core-file"; |
| 90 | case kErrorUnsupported32BitCoreFile: |
| 91 | return "unsupported-32bit-core-file"; |
| 92 | case kErrorCore2MinidumpConversion: |
| 93 | return "core2md-conversion"; |
| 94 | default: |
| 95 | return ""; |
| 96 | } |
| 97 | } |
| 98 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 99 | // Return the string that should be used for the kernel's core_pattern file. |
| 100 | // Note that if you change the format of the enabled pattern, you'll probably |
| 101 | // also need to change the ParseCrashAttributes() function below, the |
| 102 | // user_collector_test.cc unittest, and the logging_UserCrash.py autotest. |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 103 | std::string UserCollector::GetPattern(bool enabled) const { |
| 104 | if (enabled) { |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 105 | // Combine the four crash attributes into one parameter to try to reduce |
| 106 | // the size of the invocation line for crash_reporter, since the kernel |
| 107 | // has a fixed-sized (128B) buffer for it (before parameter expansion). |
| 108 | // Note that the kernel does not support quoted arguments in core_pattern. |
| 109 | return StringPrintf("|%s --user=%%p:%%s:%%u:%%e", our_path_.c_str()); |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 110 | } else { |
| 111 | return "core"; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | bool UserCollector::SetUpInternal(bool enabled) { |
| 116 | CHECK(initialized_); |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 117 | LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling"; |
| 118 | |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 119 | if (file_util::WriteFile(FilePath(core_pipe_limit_file_), |
| 120 | kCorePipeLimit, |
| 121 | strlen(kCorePipeLimit)) != |
| 122 | static_cast<int>(strlen(kCorePipeLimit))) { |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 123 | PLOG(ERROR) << "Unable to write " << core_pipe_limit_file_; |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 124 | return false; |
| 125 | } |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 126 | std::string pattern = GetPattern(enabled); |
| 127 | if (file_util::WriteFile(FilePath(core_pattern_file_), |
| 128 | pattern.c_str(), |
| 129 | pattern.length()) != |
| 130 | static_cast<int>(pattern.length())) { |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 131 | PLOG(ERROR) << "Unable to write " << core_pattern_file_; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 132 | return false; |
| 133 | } |
| 134 | return true; |
| 135 | } |
| 136 | |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 137 | bool UserCollector::GetFirstLineWithPrefix( |
| 138 | const std::vector<std::string> &lines, |
| 139 | const char *prefix, std::string *line) { |
| 140 | std::vector<std::string>::const_iterator line_iterator; |
| 141 | for (line_iterator = lines.begin(); line_iterator != lines.end(); |
| 142 | ++line_iterator) { |
| 143 | if (line_iterator->find(prefix) == 0) { |
| 144 | *line = *line_iterator; |
| 145 | return true; |
| 146 | } |
| 147 | } |
| 148 | return false; |
| 149 | } |
| 150 | |
| 151 | bool UserCollector::GetIdFromStatus( |
| 152 | const char *prefix, IdKind kind, |
| 153 | const std::vector<std::string> &status_lines, int *id) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 154 | // From fs/proc/array.c:task_state(), this file contains: |
| 155 | // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 156 | std::string id_line; |
| 157 | if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 158 | return false; |
| 159 | } |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 160 | std::string id_substring = id_line.substr(strlen(prefix), std::string::npos); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 161 | std::vector<std::string> ids; |
Chris Masone | 3ba6c5b | 2011-05-13 16:57:09 -0700 | [diff] [blame] | 162 | base::SplitString(id_substring, '\t', &ids); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 163 | if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) { |
| 164 | return false; |
| 165 | } |
| 166 | const char *number = ids[kind].c_str(); |
| 167 | char *end_number = NULL; |
| 168 | *id = strtol(number, &end_number, 10); |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 169 | if (*end_number != '\0') { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 170 | return false; |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 171 | } |
| 172 | return true; |
| 173 | } |
| 174 | |
| 175 | bool UserCollector::GetStateFromStatus( |
| 176 | const std::vector<std::string> &status_lines, std::string *state) { |
| 177 | std::string state_line; |
| 178 | if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) { |
| 179 | return false; |
| 180 | } |
| 181 | *state = state_line.substr(strlen(kStatePrefix), std::string::npos); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 182 | return true; |
| 183 | } |
| 184 | |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 185 | void UserCollector::EnqueueCollectionErrorLog(pid_t pid, |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 186 | ErrorType error_type, |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 187 | const std::string &exec) { |
| 188 | FilePath crash_path; |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 189 | LOG(INFO) << "Writing conversion problems as separate crash report."; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 190 | if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 191 | LOG(ERROR) << "Could not even get log directory; out of space?"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 192 | return; |
| 193 | } |
| 194 | std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 195 | std::string error_log = chromeos::GetLog(); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 196 | FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog"); |
Simon Que | acc7938 | 2012-05-04 18:10:09 -0700 | [diff] [blame] | 197 | if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature, |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 198 | diag_log_path)) { |
| 199 | // We load the contents of diag_log into memory and append it to |
| 200 | // the error log. We cannot just append to files because we need |
| 201 | // to always create new files to prevent attack. |
| 202 | std::string diag_log_contents; |
| 203 | file_util::ReadFileToString(diag_log_path, &diag_log_contents); |
| 204 | error_log.append(diag_log_contents); |
| 205 | file_util::Delete(diag_log_path, false); |
| 206 | } |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 207 | FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); |
| 208 | FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
Ken Mixter | 9b34647 | 2010-11-07 13:45:45 -0800 | [diff] [blame] | 209 | // We must use WriteNewFile instead of file_util::WriteFile as we do |
| 210 | // not want to write with root access to a symlink that an attacker |
| 211 | // might have created. |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 212 | WriteNewFile(log_path, error_log.data(), error_log.length()); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 213 | AddCrashMetaData("sig", kCollectionErrorSignature); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 214 | AddCrashMetaData("error_type", GetErrorTypeSignature(error_type)); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 215 | WriteCrashMetaData(meta_path, exec, log_path.value()); |
| 216 | } |
| 217 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 218 | bool UserCollector::CopyOffProcFiles(pid_t pid, |
| 219 | const FilePath &container_dir) { |
| 220 | if (!file_util::CreateDirectory(container_dir)) { |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 221 | PLOG(ERROR) << "Could not create " << container_dir.value().c_str(); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 222 | return false; |
| 223 | } |
| 224 | FilePath process_path = GetProcessPath(pid); |
| 225 | if (!file_util::PathExists(process_path)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 226 | LOG(ERROR) << "Path " << process_path.value() << " does not exist"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 227 | return false; |
| 228 | } |
| 229 | static const char *proc_files[] = { |
| 230 | "auxv", |
| 231 | "cmdline", |
| 232 | "environ", |
| 233 | "maps", |
| 234 | "status" |
| 235 | }; |
| 236 | for (unsigned i = 0; i < arraysize(proc_files); ++i) { |
| 237 | if (!file_util::CopyFile(process_path.Append(proc_files[i]), |
| 238 | container_dir.Append(proc_files[i]))) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 239 | LOG(ERROR) << "Could not copy " << proc_files[i] << " file"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 240 | return false; |
| 241 | } |
| 242 | } |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 243 | return true; |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 244 | } |
| 245 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 246 | bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const { |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 247 | // Check if the maps file is empty, which could be due to the crashed |
| 248 | // process being reaped by the kernel before finishing a core dump. |
| 249 | int64 file_size = 0; |
| 250 | if (!file_util::GetFileSize(container_dir.Append("maps"), &file_size)) { |
| 251 | LOG(ERROR) << "Could not get the size of maps file"; |
| 252 | return false; |
| 253 | } |
| 254 | if (file_size == 0) { |
| 255 | LOG(ERROR) << "maps file is empty"; |
| 256 | return false; |
| 257 | } |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 258 | return true; |
| 259 | } |
| 260 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 261 | UserCollector::ErrorType UserCollector::ValidateCoreFile( |
| 262 | const FilePath &core_path) const { |
| 263 | int fd = HANDLE_EINTR(open(core_path.value().c_str(), O_RDONLY)); |
| 264 | if (fd < 0) { |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 265 | PLOG(ERROR) << "Could not open core file " << core_path.value(); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 266 | return kErrorInvalidCoreFile; |
| 267 | } |
| 268 | |
| 269 | char e_ident[EI_NIDENT]; |
| 270 | bool read_ok = file_util::ReadFromFD(fd, e_ident, sizeof(e_ident)); |
| 271 | HANDLE_EINTR(close(fd)); |
| 272 | if (!read_ok) { |
| 273 | LOG(ERROR) << "Could not read header of core file"; |
| 274 | return kErrorInvalidCoreFile; |
| 275 | } |
| 276 | |
| 277 | if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || |
| 278 | e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) { |
| 279 | LOG(ERROR) << "Invalid core file"; |
| 280 | return kErrorInvalidCoreFile; |
| 281 | } |
| 282 | |
| 283 | #if __WORDSIZE == 64 |
| 284 | // TODO(benchan, mkrebs): Remove this check once core2md can |
| 285 | // handles both 32-bit and 64-bit ELF on a 64-bit platform. |
| 286 | if (e_ident[EI_CLASS] == ELFCLASS32) { |
| 287 | LOG(ERROR) << "Conversion of 32-bit core file on 64-bit platform is " |
| 288 | << "currently not supported"; |
| 289 | return kErrorUnsupported32BitCoreFile; |
| 290 | } |
| 291 | #endif |
| 292 | |
| 293 | return kErrorNone; |
| 294 | } |
| 295 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 296 | bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid, |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 297 | FilePath *crash_file_path, |
| 298 | bool *out_of_capacity) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 299 | FilePath process_path = GetProcessPath(pid); |
| 300 | std::string status; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 301 | if (FLAGS_directory_failure) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 302 | LOG(ERROR) << "Purposefully failing to create spool directory"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 303 | return false; |
| 304 | } |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 305 | |
| 306 | uid_t uid; |
| 307 | if (file_util::ReadFileToString(process_path.Append("status"), &status)) { |
| 308 | std::vector<std::string> status_lines; |
| 309 | base::SplitString(status, '\n', &status_lines); |
| 310 | |
| 311 | std::string process_state; |
| 312 | if (!GetStateFromStatus(status_lines, &process_state)) { |
| 313 | LOG(ERROR) << "Could not find process state in status file"; |
| 314 | return false; |
| 315 | } |
| 316 | LOG(INFO) << "State of crashed process [" << pid << "]: " << process_state; |
| 317 | |
| 318 | // Get effective UID of crashing process. |
| 319 | int id; |
| 320 | if (!GetIdFromStatus(kUserId, kIdEffective, status_lines, &id)) { |
| 321 | LOG(ERROR) << "Could not find euid in status file"; |
| 322 | return false; |
| 323 | } |
| 324 | uid = id; |
| 325 | } else if (supplied_ruid != kUnknownUid) { |
| 326 | LOG(INFO) << "Using supplied UID " << supplied_ruid |
| 327 | << " for crashed process [" << pid |
| 328 | << "] due to error reading status file"; |
| 329 | uid = supplied_ruid; |
| 330 | } else { |
| 331 | LOG(ERROR) << "Could not read status file and kernel did not supply UID"; |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 332 | LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: " |
| 333 | << file_util::DirectoryExists(process_path); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 334 | return false; |
| 335 | } |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 336 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 337 | if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 338 | LOG(ERROR) << "Could not create crash directory"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 339 | return false; |
| 340 | } |
| 341 | return true; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 342 | } |
| 343 | |
| 344 | bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { |
| 345 | // Copy off all stdin to a core file. |
| 346 | FilePath stdin_path("/dev/fd/0"); |
| 347 | if (file_util::CopyFile(stdin_path, core_path)) { |
| 348 | return true; |
| 349 | } |
| 350 | |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 351 | PLOG(ERROR) << "Could not write core file"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 352 | // If the file system was full, make sure we remove any remnants. |
| 353 | file_util::Delete(core_path, false); |
| 354 | return false; |
| 355 | } |
| 356 | |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 357 | bool UserCollector::RunCoreToMinidump(const FilePath &core_path, |
| 358 | const FilePath &procfs_directory, |
| 359 | const FilePath &minidump_path, |
| 360 | const FilePath &temp_directory) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 361 | FilePath output_path = temp_directory.Append("output"); |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 362 | chromeos::ProcessImpl core2md; |
| 363 | core2md.RedirectOutput(output_path.value()); |
| 364 | core2md.AddArg(kCoreToMinidumpConverterPath); |
| 365 | core2md.AddArg(core_path.value()); |
| 366 | core2md.AddArg(procfs_directory.value()); |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 367 | |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 368 | if (!FLAGS_core2md_failure) { |
| 369 | core2md.AddArg(minidump_path.value()); |
| 370 | } else { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 371 | // To test how core2md errors are propagaged, cause an error |
| 372 | // by forgetting a required argument. |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 373 | } |
| 374 | |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 375 | int errorlevel = core2md.Run(); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 376 | |
| 377 | std::string output; |
| 378 | file_util::ReadFileToString(output_path, &output); |
| 379 | if (errorlevel != 0) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 380 | LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath |
| 381 | << " [result=" << errorlevel << "]: " << output; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 382 | return false; |
| 383 | } |
| 384 | |
| 385 | if (!file_util::PathExists(minidump_path)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 386 | LOG(ERROR) << "Minidump file " << minidump_path.value() |
| 387 | << " was not created"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 388 | return false; |
| 389 | } |
| 390 | return true; |
| 391 | } |
| 392 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 393 | UserCollector::ErrorType UserCollector::ConvertCoreToMinidump( |
| 394 | pid_t pid, |
| 395 | const FilePath &container_dir, |
| 396 | const FilePath &core_path, |
| 397 | const FilePath &minidump_path) { |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 398 | // If proc files are unuable, we continue to read the core file from stdin, |
| 399 | // but only skip the core-to-minidump conversion, so that we may still use |
| 400 | // the core file for debugging. |
| 401 | bool proc_files_usable = |
| 402 | CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir); |
| 403 | |
| 404 | if (!CopyStdinToCoreFile(core_path)) { |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 405 | return kErrorReadCoreData; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 406 | } |
| 407 | |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 408 | if (!proc_files_usable) { |
| 409 | LOG(INFO) << "Skipped converting core file to minidump due to " |
| 410 | << "unusable proc files"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 411 | return kErrorUnusableProcFiles; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 412 | } |
| 413 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 414 | ErrorType error = ValidateCoreFile(core_path); |
| 415 | if (error != kErrorNone) { |
| 416 | return error; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 417 | } |
| 418 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 419 | if (!RunCoreToMinidump(core_path, |
| 420 | container_dir, // procfs directory |
| 421 | minidump_path, |
| 422 | container_dir)) { // temporary directory |
| 423 | return kErrorCore2MinidumpConversion; |
| 424 | } |
| 425 | |
| 426 | LOG(INFO) << "Stored minidump to " << minidump_path.value(); |
| 427 | return kErrorNone; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 428 | } |
| 429 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 430 | UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash( |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 431 | pid_t pid, const std::string &exec, uid_t supplied_ruid, |
| 432 | bool *out_of_capacity) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 433 | FilePath crash_path; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 434 | if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path, |
| 435 | out_of_capacity)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 436 | LOG(ERROR) << "Unable to find/create process-specific crash path"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 437 | return kErrorSystemIssue; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 438 | } |
| 439 | |
Ben Chan | 294d5d1 | 2012-01-04 20:40:15 -0800 | [diff] [blame] | 440 | // Directory like /tmp/crash_reporter/1234 which contains the |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 441 | // procfs entries and other temporary files used during conversion. |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 442 | FilePath container_dir(StringPrintf("/tmp/crash_reporter/%d", (int)pid)); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 443 | // Delete a pre-existing directory from crash reporter that may have |
| 444 | // been left around for diagnostics from a failed conversion attempt. |
| 445 | // If we don't, existing files can cause forking to fail. |
| 446 | file_util::Delete(container_dir, true); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 447 | std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); |
| 448 | FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); |
| 449 | FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
| 450 | FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp"); |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 451 | FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); |
| 452 | |
Simon Que | acc7938 | 2012-05-04 18:10:09 -0700 | [diff] [blame] | 453 | if (GetLogContents(FilePath(log_config_path_), exec, log_path)) |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 454 | AddCrashMetaData("log", log_path.value()); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 455 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 456 | ErrorType error_type = |
| 457 | ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path); |
| 458 | if (error_type != kErrorNone) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 459 | LOG(INFO) << "Leaving core file at " << core_path.value() |
| 460 | << " due to conversion error"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 461 | return error_type; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 462 | } |
| 463 | |
| 464 | // Here we commit to sending this file. We must not return false |
| 465 | // after this point or we will generate a log report as well as a |
| 466 | // crash report. |
| 467 | WriteCrashMetaData(meta_path, |
| 468 | exec, |
| 469 | minidump_path.value()); |
| 470 | |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 471 | if (!IsDeveloperImage()) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 472 | file_util::Delete(core_path, false); |
| 473 | } else { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 474 | LOG(INFO) << "Leaving core file at " << core_path.value() |
| 475 | << " due to developer image"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 476 | } |
| 477 | |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 478 | file_util::Delete(container_dir, true); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 479 | return kErrorNone; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 480 | } |
| 481 | |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 482 | bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes, |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 483 | pid_t *pid, int *signal, uid_t *uid, |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 484 | std::string *kernel_supplied_name) { |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 485 | pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(.*)"); |
| 486 | if (re.FullMatch(crash_attributes, pid, signal, uid, kernel_supplied_name)) |
| 487 | return true; |
| 488 | |
| 489 | LOG(INFO) << "Falling back to parsing crash attributes '" |
| 490 | << crash_attributes << "' without UID"; |
| 491 | pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)"); |
| 492 | *uid = kUnknownUid; |
| 493 | return re_without_uid.FullMatch(crash_attributes, pid, signal, |
| 494 | kernel_supplied_name); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 495 | } |
| 496 | |
Michael Krebs | 2f3ed03 | 2012-08-21 20:17:03 -0700 | [diff] [blame] | 497 | /* Returns true if the given executable name matches that of Chrome. This |
| 498 | * includes checks for threads that Chrome has renamed. */ |
| 499 | static bool IsChromeExecName(const std::string &exec) { |
| 500 | static const char *kChromeNames[] = { |
| 501 | "chrome", |
Michael Krebs | b1b91a5 | 2012-11-26 14:26:17 -0800 | [diff] [blame] | 502 | /* These are additional thread names seen in http://crash/ */ |
| 503 | "MediaPipeline", |
Michael Krebs | 2f3ed03 | 2012-08-21 20:17:03 -0700 | [diff] [blame] | 504 | /* These come from the use of base::PlatformThread::SetName() directly */ |
| 505 | "CrBrowserMain", "CrRendererMain", "CrUtilityMain", "CrPPAPIMain", |
| 506 | "CrPPAPIBrokerMain", "CrPluginMain", "CrWorkerMain", "CrGpuMain", |
| 507 | "BrokerEvent", "CrVideoRenderer", "CrShutdownDetector", |
| 508 | "UsbEventHandler", "CrNaClMain", "CrServiceMain", |
| 509 | /* These thread names come from the use of base::Thread */ |
| 510 | "Gamepad polling thread", "Chrome_InProcGpuThread", |
| 511 | "Chrome_DragDropThread", "Renderer::FILE", "VC manager", |
| 512 | "VideoCaptureModuleImpl", "JavaBridge", "VideoCaptureManagerThread", |
| 513 | "Geolocation", "Geolocation_wifi_provider", |
| 514 | "Device orientation polling thread", "Chrome_InProcRendererThread", |
| 515 | "NetworkChangeNotifier", "Watchdog", "inotify_reader", |
| 516 | "cf_iexplore_background_thread", "BrowserWatchdog", |
| 517 | "Chrome_HistoryThread", "Chrome_SyncThread", "Chrome_ShellDialogThread", |
| 518 | "Printing_Worker", "Chrome_SafeBrowsingThread", "SimpleDBThread", |
| 519 | "D-Bus thread", "AudioThread", "NullAudioThread", "V4L2Thread", |
| 520 | "ChromotingClientDecodeThread", "Profiling_Flush", |
| 521 | "worker_thread_ticker", "AudioMixerAlsa", "AudioMixerCras", |
| 522 | "FakeAudioRecordingThread", "CaptureThread", |
| 523 | "Chrome_WebSocketproxyThread", "ProcessWatcherThread", |
| 524 | "Chrome_CameraThread", "import_thread", "NaCl_IOThread", |
| 525 | "Chrome_CloudPrintJobPrintThread", "Chrome_CloudPrintProxyCoreThread", |
| 526 | "DaemonControllerFileIO", "ChromotingMainThread", |
| 527 | "ChromotingEncodeThread", "ChromotingDesktopThread", |
| 528 | "ChromotingIOThread", "ChromotingFileIOThread", |
| 529 | "Chrome_libJingle_WorkerThread", "Chrome_ChildIOThread", |
| 530 | "GLHelperThread", "RemotingHostPlugin", |
| 531 | // "PAC thread #%d", // not easy to check because of "%d" |
| 532 | "Chrome_DBThread", "Chrome_WebKitThread", "Chrome_FileThread", |
| 533 | "Chrome_FileUserBlockingThread", "Chrome_ProcessLauncherThread", |
| 534 | "Chrome_CacheThread", "Chrome_IOThread", "Cache Thread", "File Thread", |
| 535 | "ServiceProcess_IO", "ServiceProcess_File", |
| 536 | "extension_crash_uploader", "gpu-process_crash_uploader", |
| 537 | "plugin_crash_uploader", "renderer_crash_uploader", |
| 538 | /* These come from the use of webkit_glue::WebThreadImpl */ |
| 539 | "Compositor", "Browser Compositor", |
| 540 | // "WorkerPool/%d", // not easy to check because of "%d" |
| 541 | /* These come from the use of base::Watchdog */ |
| 542 | "Startup watchdog thread Watchdog", "Shutdown watchdog thread Watchdog", |
| 543 | /* These come from the use of AudioDeviceThread::Start */ |
Michael Krebs | a1cc383 | 2012-09-13 13:24:12 -0700 | [diff] [blame] | 544 | "AudioDevice", "AudioInputDevice", "AudioOutputDevice", |
Michael Krebs | 2f3ed03 | 2012-08-21 20:17:03 -0700 | [diff] [blame] | 545 | /* These come from the use of MessageLoopFactory::GetMessageLoop */ |
| 546 | "GpuVideoDecoder", "RtcVideoDecoderThread", "PipelineThread", |
| 547 | "AudioDecoderThread", "VideoDecoderThread", |
| 548 | /* These come from the use of MessageLoopFactory::GetMessageLoopProxy */ |
| 549 | "CaptureVideoDecoderThread", "CaptureVideoDecoder", |
| 550 | /* These come from the use of base::SimpleThread */ |
| 551 | "LocalInputMonitor/%d", // "%d" gets lopped off for kernel-supplied |
| 552 | /* These come from the use of base::DelegateSimpleThread */ |
| 553 | "ipc_channel_nacl reader thread/%d", "plugin_audio_input_thread/%d", |
| 554 | "plugin_audio_thread/%d", |
| 555 | /* These come from the use of base::SequencedWorkerPool */ |
| 556 | "BrowserBlockingWorker%d/%d", // "%d" gets lopped off for kernel-supplied |
| 557 | }; |
| 558 | static std::set<std::string> chrome_names; |
| 559 | |
| 560 | /* Initialize a set of chrome names, for efficient lookup */ |
| 561 | if (chrome_names.empty()) { |
| 562 | for (size_t i = 0; i < arraysize(kChromeNames); i++) { |
| 563 | std::string check_name(kChromeNames[i]); |
| 564 | chrome_names.insert(check_name); |
| 565 | // When checking a kernel-supplied name, it should be truncated to 15 |
| 566 | // chars. See PR_SET_NAME in |
| 567 | // http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html, |
| 568 | // although that page misleads by saying "16 bytes". |
| 569 | chrome_names.insert("supplied_" + std::string(check_name, 0, 15)); |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | return ContainsKey(chrome_names, exec); |
| 574 | } |
| 575 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 576 | bool UserCollector::ShouldDump(bool has_owner_consent, |
| 577 | bool is_developer, |
Michael Krebs | 4fe30db | 2011-08-05 13:54:52 -0700 | [diff] [blame] | 578 | bool handle_chrome_crashes, |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 579 | const std::string &exec, |
| 580 | std::string *reason) { |
| 581 | reason->clear(); |
| 582 | |
| 583 | // Treat Chrome crashes as if the user opted-out. We stop counting Chrome |
| 584 | // crashes towards user crashes, so user crashes really mean non-Chrome |
| 585 | // user-space crashes. |
Michael Krebs | 2f3ed03 | 2012-08-21 20:17:03 -0700 | [diff] [blame] | 586 | if (!handle_chrome_crashes && IsChromeExecName(exec)) { |
Mike Frysinger | d2db5ff | 2013-10-08 19:03:23 -0400 | [diff] [blame^] | 587 | *reason = "ignoring call by kernel - chrome crash; " |
| 588 | "waiting for chrome to call us directly"; |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 589 | return false; |
| 590 | } |
| 591 | |
| 592 | // For developer builds, we always want to keep the crash reports unless |
| 593 | // we're testing the crash facilities themselves. This overrides |
| 594 | // feedback. Crash sending still obeys consent. |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 595 | if (is_developer) { |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 596 | *reason = "developer build - not testing - always dumping"; |
| 597 | return true; |
| 598 | } |
| 599 | |
| 600 | if (!has_owner_consent) { |
| 601 | *reason = "ignoring - no consent"; |
| 602 | return false; |
| 603 | } |
| 604 | |
| 605 | *reason = "handling"; |
| 606 | return true; |
| 607 | } |
| 608 | |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 609 | bool UserCollector::HandleCrash(const std::string &crash_attributes, |
| 610 | const char *force_exec) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 611 | CHECK(initialized_); |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 612 | pid_t pid = 0; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 613 | int signal = 0; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 614 | uid_t supplied_ruid = kUnknownUid; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 615 | std::string kernel_supplied_name; |
| 616 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 617 | if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid, |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 618 | &kernel_supplied_name)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 619 | LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 620 | return false; |
| 621 | } |
| 622 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 623 | std::string exec; |
| 624 | if (force_exec) { |
| 625 | exec.assign(force_exec); |
| 626 | } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 627 | // If we cannot find the exec name, use the kernel supplied name. |
| 628 | // We don't always use the kernel's since it truncates the name to |
| 629 | // 16 characters. |
| 630 | exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str()); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 631 | } |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 632 | |
| 633 | // Allow us to test the crash reporting mechanism successfully even if |
| 634 | // other parts of the system crash. |
| 635 | if (!FLAGS_filter_in.empty() && |
| 636 | (FLAGS_filter_in == "none" || |
| 637 | FLAGS_filter_in != exec)) { |
| 638 | // We use a different format message to make it more obvious in tests |
| 639 | // which crashes are test generated and which are real. |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 640 | LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while " |
| 641 | << "filter_in=" << FLAGS_filter_in << "."; |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 642 | return true; |
| 643 | } |
| 644 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 645 | std::string reason; |
| 646 | bool dump = ShouldDump(is_feedback_allowed_function_(), |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 647 | IsDeveloperImage(), |
Michael Krebs | 4fe30db | 2011-08-05 13:54:52 -0700 | [diff] [blame] | 648 | ShouldHandleChromeCrashes(), |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 649 | exec, |
| 650 | &reason); |
Ken Mixter | 2105b49 | 2010-11-09 16:14:38 -0800 | [diff] [blame] | 651 | |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 652 | LOG(WARNING) << "Received crash notification for " << exec << "[" << pid |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 653 | << "] sig " << signal << ", user " << supplied_ruid |
| 654 | << " (" << reason << ")"; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 655 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 656 | if (dump) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 657 | count_crash_function_(); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 658 | |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 659 | if (generate_diagnostics_) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 660 | bool out_of_capacity = false; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 661 | ErrorType error_type = |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 662 | ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 663 | if (error_type != kErrorNone) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 664 | if (!out_of_capacity) |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 665 | EnqueueCollectionErrorLog(pid, error_type, exec); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 666 | return false; |
| 667 | } |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 668 | } |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 669 | } |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 670 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 671 | return true; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 672 | } |