blob: 302b1308a42d6d9e5c27a671fff51dbe50efcd80 [file] [log] [blame]
Mike Frysinger57b261c2012-04-11 14:47:09 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Sosae4a86032010-06-16 17:08:34 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ken Mixter03403162010-08-18 15:23:16 -07005#include "crash-reporter/user_collector.h"
6
Ben Chan6e709a12012-02-29 12:10:44 -08007#include <bits/wordsize.h>
8#include <elf.h>
9#include <fcntl.h>
Ken Mixter777484c2010-07-23 16:22:44 -070010#include <grp.h> // For struct group.
Ken Mixter1b8fe012011-01-25 13:33:05 -080011#include <pcrecpp.h>
Ken Mixter777484c2010-07-23 16:22:44 -070012#include <pwd.h> // For struct passwd.
Ben Chanf84ea212014-08-06 17:27:48 -070013#include <stdint.h>
Ken Mixter2953c3a2010-10-18 14:42:20 -070014#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
Ken Mixter777484c2010-07-23 16:22:44 -070015
Ben Chan7e776902014-06-18 13:19:51 -070016#include <set>
Chris Sosae4a86032010-06-16 17:08:34 -070017#include <string>
Ken Mixter2953c3a2010-10-18 14:42:20 -070018#include <vector>
Chris Sosae4a86032010-06-16 17:08:34 -070019
Ben Chanab6cc902014-09-05 08:21:06 -070020#include <base/files/file_util.h>
Ben Chan7e776902014-06-18 13:19:51 -070021#include <base/logging.h>
22#include <base/posix/eintr_wrapper.h>
23#include <base/stl_util.h>
24#include <base/strings/string_split.h>
25#include <base/strings/string_util.h>
26#include <base/strings/stringprintf.h>
27#include <chromeos/process.h>
28#include <chromeos/syslog_logging.h>
Ken Mixter207694d2010-10-28 15:42:37 -070029
30static const char kCollectionErrorSignature[] =
31 "crash_reporter-user-collection";
Chris Sosae4a86032010-06-16 17:08:34 -070032// This procfs file is used to cause kernel core file writing to
33// instead pipe the core file into a user space process. See
34// core(5) man page.
35static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern";
Ken Mixterc49dbd42010-12-14 17:44:11 -080036static const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit";
37// Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent
38// crashes, but finite to avoid infinitely recursing on crash handling.
39static const char kCorePipeLimit[] = "4";
Ken Mixter777484c2010-07-23 16:22:44 -070040static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md";
Ken Mixter777484c2010-07-23 16:22:44 -070041
Ben Chanf13bb582012-01-06 08:22:07 -080042static const char kStatePrefix[] = "State:\t";
Ken Mixterc49dbd42010-12-14 17:44:11 -080043
Michael Krebs1c57e9e2012-09-25 18:03:13 -070044// Define an otherwise invalid value that represents an unknown UID.
45static const uid_t kUnknownUid = -1;
46
Ken Mixter777484c2010-07-23 16:22:44 -070047const char *UserCollector::kUserId = "Uid:\t";
48const char *UserCollector::kGroupId = "Gid:\t";
Chris Sosae4a86032010-06-16 17:08:34 -070049
Simon Que9f90aca2013-02-19 17:19:52 -080050using base::FilePath;
Mike Frysingera557c112014-02-05 22:55:39 -050051using base::StringPrintf;
Simon Que9f90aca2013-02-19 17:19:52 -080052
Chris Sosae4a86032010-06-16 17:08:34 -070053UserCollector::UserCollector()
Ken Mixter777484c2010-07-23 16:22:44 -070054 : generate_diagnostics_(false),
55 core_pattern_file_(kCorePatternFile),
Ken Mixterc49dbd42010-12-14 17:44:11 -080056 core_pipe_limit_file_(kCorePipeLimitFile),
Ken Mixter03403162010-08-18 15:23:16 -070057 initialized_(false) {
Chris Sosae4a86032010-06-16 17:08:34 -070058}
59
60void UserCollector::Initialize(
61 UserCollector::CountCrashFunction count_crash_function,
62 const std::string &our_path,
63 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
Steve Fungd6169a22014-08-11 15:52:23 -070064 bool generate_diagnostics,
65 bool core2md_failure,
66 bool directory_failure,
67 const std::string &filter_in) {
Ken Mixter03403162010-08-18 15:23:16 -070068 CrashCollector::Initialize(count_crash_function,
Ken Mixtera3249322011-03-03 08:47:38 -080069 is_feedback_allowed_function);
Chris Sosae4a86032010-06-16 17:08:34 -070070 our_path_ = our_path;
Chris Sosae4a86032010-06-16 17:08:34 -070071 initialized_ = true;
Ken Mixter777484c2010-07-23 16:22:44 -070072 generate_diagnostics_ = generate_diagnostics;
Steve Fungd6169a22014-08-11 15:52:23 -070073 core2md_failure_ = core2md_failure;
74 directory_failure_ = directory_failure;
75 filter_in_ = filter_in;
Chris Sosae4a86032010-06-16 17:08:34 -070076}
77
78UserCollector::~UserCollector() {
79}
80
Ben Chan6e709a12012-02-29 12:10:44 -080081std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const {
82 switch (error_type) {
83 case kErrorSystemIssue:
84 return "system-issue";
85 case kErrorReadCoreData:
86 return "read-core-data";
87 case kErrorUnusableProcFiles:
88 return "unusable-proc-files";
89 case kErrorInvalidCoreFile:
90 return "invalid-core-file";
91 case kErrorUnsupported32BitCoreFile:
92 return "unsupported-32bit-core-file";
93 case kErrorCore2MinidumpConversion:
94 return "core2md-conversion";
95 default:
96 return "";
97 }
98}
99
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700100// Return the string that should be used for the kernel's core_pattern file.
101// Note that if you change the format of the enabled pattern, you'll probably
102// also need to change the ParseCrashAttributes() function below, the
103// user_collector_test.cc unittest, and the logging_UserCrash.py autotest.
Chris Sosae4a86032010-06-16 17:08:34 -0700104std::string UserCollector::GetPattern(bool enabled) const {
105 if (enabled) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700106 // Combine the four crash attributes into one parameter to try to reduce
107 // the size of the invocation line for crash_reporter, since the kernel
108 // has a fixed-sized (128B) buffer for it (before parameter expansion).
109 // Note that the kernel does not support quoted arguments in core_pattern.
Mike Frysingerbfdf4a82014-03-14 09:31:33 -0400110 return StringPrintf("|%s --user=%%P:%%s:%%u:%%e", our_path_.c_str());
Chris Sosae4a86032010-06-16 17:08:34 -0700111 } else {
112 return "core";
113 }
114}
115
116bool UserCollector::SetUpInternal(bool enabled) {
117 CHECK(initialized_);
Ken Mixtera3249322011-03-03 08:47:38 -0800118 LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
119
Ben Chanf30c6412014-05-22 23:09:01 -0700120 if (base::WriteFile(FilePath(core_pipe_limit_file_), kCorePipeLimit,
121 strlen(kCorePipeLimit)) !=
Ken Mixterc49dbd42010-12-14 17:44:11 -0800122 static_cast<int>(strlen(kCorePipeLimit))) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700123 PLOG(ERROR) << "Unable to write " << core_pipe_limit_file_;
Ken Mixterc49dbd42010-12-14 17:44:11 -0800124 return false;
125 }
Chris Sosae4a86032010-06-16 17:08:34 -0700126 std::string pattern = GetPattern(enabled);
Ben Chanf30c6412014-05-22 23:09:01 -0700127 if (base::WriteFile(FilePath(core_pattern_file_), pattern.c_str(),
128 pattern.length()) != static_cast<int>(pattern.length())) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700129 PLOG(ERROR) << "Unable to write " << core_pattern_file_;
Chris Sosae4a86032010-06-16 17:08:34 -0700130 return false;
131 }
132 return true;
133}
134
Ben Chanf13bb582012-01-06 08:22:07 -0800135bool UserCollector::GetFirstLineWithPrefix(
136 const std::vector<std::string> &lines,
137 const char *prefix, std::string *line) {
138 std::vector<std::string>::const_iterator line_iterator;
139 for (line_iterator = lines.begin(); line_iterator != lines.end();
140 ++line_iterator) {
141 if (line_iterator->find(prefix) == 0) {
142 *line = *line_iterator;
143 return true;
144 }
145 }
146 return false;
147}
148
149bool UserCollector::GetIdFromStatus(
150 const char *prefix, IdKind kind,
151 const std::vector<std::string> &status_lines, int *id) {
Ken Mixter777484c2010-07-23 16:22:44 -0700152 // From fs/proc/array.c:task_state(), this file contains:
153 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n
Ben Chanf13bb582012-01-06 08:22:07 -0800154 std::string id_line;
155 if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700156 return false;
157 }
Ben Chanf13bb582012-01-06 08:22:07 -0800158 std::string id_substring = id_line.substr(strlen(prefix), std::string::npos);
Ken Mixter777484c2010-07-23 16:22:44 -0700159 std::vector<std::string> ids;
Chris Masone3ba6c5b2011-05-13 16:57:09 -0700160 base::SplitString(id_substring, '\t', &ids);
Ken Mixter777484c2010-07-23 16:22:44 -0700161 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
162 return false;
163 }
164 const char *number = ids[kind].c_str();
Ben Chan262d7982014-09-18 08:05:20 -0700165 char *end_number = nullptr;
Ken Mixter777484c2010-07-23 16:22:44 -0700166 *id = strtol(number, &end_number, 10);
Ben Chanf13bb582012-01-06 08:22:07 -0800167 if (*end_number != '\0') {
Ken Mixter777484c2010-07-23 16:22:44 -0700168 return false;
Ben Chanf13bb582012-01-06 08:22:07 -0800169 }
170 return true;
171}
172
173bool UserCollector::GetStateFromStatus(
174 const std::vector<std::string> &status_lines, std::string *state) {
175 std::string state_line;
176 if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) {
177 return false;
178 }
179 *state = state_line.substr(strlen(kStatePrefix), std::string::npos);
Ken Mixter777484c2010-07-23 16:22:44 -0700180 return true;
181}
182
Ken Mixter207694d2010-10-28 15:42:37 -0700183void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
Ben Chan6e709a12012-02-29 12:10:44 -0800184 ErrorType error_type,
Ken Mixter207694d2010-10-28 15:42:37 -0700185 const std::string &exec) {
186 FilePath crash_path;
Ken Mixtera3249322011-03-03 08:47:38 -0800187 LOG(INFO) << "Writing conversion problems as separate crash report.";
Ben Chan262d7982014-09-18 08:05:20 -0700188 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800189 LOG(ERROR) << "Could not even get log directory; out of space?";
Ken Mixter207694d2010-10-28 15:42:37 -0700190 return;
191 }
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200192 AddCrashMetaData("sig", kCollectionErrorSignature);
193 AddCrashMetaData("error_type", GetErrorTypeSignature(error_type));
Ben Chan262d7982014-09-18 08:05:20 -0700194 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Ken Mixtera3249322011-03-03 08:47:38 -0800195 std::string error_log = chromeos::GetLog();
Ken Mixter1b8fe012011-01-25 13:33:05 -0800196 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
Simon Queacc79382012-05-04 18:10:09 -0700197 if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800198 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;
Mike Frysingera557c112014-02-05 22:55:39 -0500203 base::ReadFileToString(diag_log_path, &diag_log_contents);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800204 error_log.append(diag_log_contents);
Mike Frysingera557c112014-02-05 22:55:39 -0500205 base::DeleteFile(diag_log_path, false);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800206 }
Ken Mixter207694d2010-10-28 15:42:37 -0700207 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
208 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
Ben Chanf30c6412014-05-22 23:09:01 -0700209 // We must use WriteNewFile instead of base::WriteFile as we do
Ken Mixter9b346472010-11-07 13:45:45 -0800210 // not want to write with root access to a symlink that an attacker
211 // might have created.
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200212 if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) {
213 LOG(ERROR) << "Error writing new file " << log_path.value();
214 return;
215 }
Ken Mixter207694d2010-10-28 15:42:37 -0700216 WriteCrashMetaData(meta_path, exec, log_path.value());
217}
218
Ken Mixter777484c2010-07-23 16:22:44 -0700219bool UserCollector::CopyOffProcFiles(pid_t pid,
220 const FilePath &container_dir) {
Mike Frysingera557c112014-02-05 22:55:39 -0500221 if (!base::CreateDirectory(container_dir)) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700222 PLOG(ERROR) << "Could not create " << container_dir.value().c_str();
Ken Mixter777484c2010-07-23 16:22:44 -0700223 return false;
224 }
225 FilePath process_path = GetProcessPath(pid);
Mike Frysingera557c112014-02-05 22:55:39 -0500226 if (!base::PathExists(process_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800227 LOG(ERROR) << "Path " << process_path.value() << " does not exist";
Ken Mixter777484c2010-07-23 16:22:44 -0700228 return false;
229 }
230 static const char *proc_files[] = {
231 "auxv",
232 "cmdline",
233 "environ",
234 "maps",
235 "status"
236 };
237 for (unsigned i = 0; i < arraysize(proc_files); ++i) {
Mike Frysingera557c112014-02-05 22:55:39 -0500238 if (!base::CopyFile(process_path.Append(proc_files[i]),
239 container_dir.Append(proc_files[i]))) {
Ken Mixtera3249322011-03-03 08:47:38 -0800240 LOG(ERROR) << "Could not copy " << proc_files[i] << " file";
Ken Mixter777484c2010-07-23 16:22:44 -0700241 return false;
242 }
243 }
Ben Chanec7d7832012-01-09 10:29:58 -0800244 return true;
Ben Chanf13bb582012-01-06 08:22:07 -0800245}
246
Ben Chan6e709a12012-02-29 12:10:44 -0800247bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const {
Ben Chanf13bb582012-01-06 08:22:07 -0800248 // Check if the maps file is empty, which could be due to the crashed
249 // process being reaped by the kernel before finishing a core dump.
Ben Chanf84ea212014-08-06 17:27:48 -0700250 int64_t file_size = 0;
Mike Frysingera557c112014-02-05 22:55:39 -0500251 if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) {
Ben Chanf13bb582012-01-06 08:22:07 -0800252 LOG(ERROR) << "Could not get the size of maps file";
253 return false;
254 }
255 if (file_size == 0) {
256 LOG(ERROR) << "maps file is empty";
257 return false;
258 }
Ken Mixter777484c2010-07-23 16:22:44 -0700259 return true;
260}
261
Ben Chan6e709a12012-02-29 12:10:44 -0800262UserCollector::ErrorType UserCollector::ValidateCoreFile(
263 const FilePath &core_path) const {
264 int fd = HANDLE_EINTR(open(core_path.value().c_str(), O_RDONLY));
265 if (fd < 0) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700266 PLOG(ERROR) << "Could not open core file " << core_path.value();
Ben Chan6e709a12012-02-29 12:10:44 -0800267 return kErrorInvalidCoreFile;
268 }
269
270 char e_ident[EI_NIDENT];
Mike Frysingera557c112014-02-05 22:55:39 -0500271 bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident));
Mike Frysingerf1a50142014-05-14 16:05:09 -0400272 IGNORE_EINTR(close(fd));
Ben Chan6e709a12012-02-29 12:10:44 -0800273 if (!read_ok) {
274 LOG(ERROR) << "Could not read header of core file";
275 return kErrorInvalidCoreFile;
276 }
277
278 if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
279 e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
280 LOG(ERROR) << "Invalid core file";
281 return kErrorInvalidCoreFile;
282 }
283
284#if __WORDSIZE == 64
285 // TODO(benchan, mkrebs): Remove this check once core2md can
286 // handles both 32-bit and 64-bit ELF on a 64-bit platform.
287 if (e_ident[EI_CLASS] == ELFCLASS32) {
288 LOG(ERROR) << "Conversion of 32-bit core file on 64-bit platform is "
289 << "currently not supported";
290 return kErrorUnsupported32BitCoreFile;
291 }
292#endif
293
294 return kErrorNone;
295}
296
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700297bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
Ken Mixter207694d2010-10-28 15:42:37 -0700298 FilePath *crash_file_path,
299 bool *out_of_capacity) {
Ken Mixter777484c2010-07-23 16:22:44 -0700300 FilePath process_path = GetProcessPath(pid);
301 std::string status;
Steve Fungd6169a22014-08-11 15:52:23 -0700302 if (directory_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800303 LOG(ERROR) << "Purposefully failing to create spool directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700304 return false;
305 }
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700306
307 uid_t uid;
Mike Frysingera557c112014-02-05 22:55:39 -0500308 if (base::ReadFileToString(process_path.Append("status"), &status)) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700309 std::vector<std::string> status_lines;
310 base::SplitString(status, '\n', &status_lines);
311
312 std::string process_state;
313 if (!GetStateFromStatus(status_lines, &process_state)) {
314 LOG(ERROR) << "Could not find process state in status file";
315 return false;
316 }
317 LOG(INFO) << "State of crashed process [" << pid << "]: " << process_state;
318
319 // Get effective UID of crashing process.
320 int id;
321 if (!GetIdFromStatus(kUserId, kIdEffective, status_lines, &id)) {
322 LOG(ERROR) << "Could not find euid in status file";
323 return false;
324 }
325 uid = id;
326 } else if (supplied_ruid != kUnknownUid) {
327 LOG(INFO) << "Using supplied UID " << supplied_ruid
328 << " for crashed process [" << pid
329 << "] due to error reading status file";
330 uid = supplied_ruid;
331 } else {
332 LOG(ERROR) << "Could not read status file and kernel did not supply UID";
Ken Mixtera3249322011-03-03 08:47:38 -0800333 LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: "
Mike Frysingera557c112014-02-05 22:55:39 -0500334 << base::DirectoryExists(process_path);
Ken Mixter777484c2010-07-23 16:22:44 -0700335 return false;
336 }
Ben Chanf13bb582012-01-06 08:22:07 -0800337
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700338 if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800339 LOG(ERROR) << "Could not create crash directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700340 return false;
341 }
342 return true;
Ken Mixter777484c2010-07-23 16:22:44 -0700343}
344
345bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
346 // Copy off all stdin to a core file.
347 FilePath stdin_path("/dev/fd/0");
Mike Frysingera557c112014-02-05 22:55:39 -0500348 if (base::CopyFile(stdin_path, core_path)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700349 return true;
350 }
351
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700352 PLOG(ERROR) << "Could not write core file";
Ken Mixter777484c2010-07-23 16:22:44 -0700353 // If the file system was full, make sure we remove any remnants.
Mike Frysingera557c112014-02-05 22:55:39 -0500354 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700355 return false;
356}
357
Ken Mixter207694d2010-10-28 15:42:37 -0700358bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
359 const FilePath &procfs_directory,
360 const FilePath &minidump_path,
361 const FilePath &temp_directory) {
Ken Mixter777484c2010-07-23 16:22:44 -0700362 FilePath output_path = temp_directory.Append("output");
Ken Mixtera3249322011-03-03 08:47:38 -0800363 chromeos::ProcessImpl core2md;
364 core2md.RedirectOutput(output_path.value());
365 core2md.AddArg(kCoreToMinidumpConverterPath);
366 core2md.AddArg(core_path.value());
367 core2md.AddArg(procfs_directory.value());
Ken Mixter2953c3a2010-10-18 14:42:20 -0700368
Steve Fungd6169a22014-08-11 15:52:23 -0700369 if (!core2md_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800370 core2md.AddArg(minidump_path.value());
371 } else {
Ken Mixter207694d2010-10-28 15:42:37 -0700372 // To test how core2md errors are propagaged, cause an error
373 // by forgetting a required argument.
Ken Mixter207694d2010-10-28 15:42:37 -0700374 }
375
Ken Mixtera3249322011-03-03 08:47:38 -0800376 int errorlevel = core2md.Run();
Ken Mixter777484c2010-07-23 16:22:44 -0700377
378 std::string output;
Mike Frysingera557c112014-02-05 22:55:39 -0500379 base::ReadFileToString(output_path, &output);
Ken Mixter777484c2010-07-23 16:22:44 -0700380 if (errorlevel != 0) {
Ken Mixtera3249322011-03-03 08:47:38 -0800381 LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath
382 << " [result=" << errorlevel << "]: " << output;
Ken Mixter777484c2010-07-23 16:22:44 -0700383 return false;
384 }
385
Mike Frysingera557c112014-02-05 22:55:39 -0500386 if (!base::PathExists(minidump_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800387 LOG(ERROR) << "Minidump file " << minidump_path.value()
388 << " was not created";
Ken Mixter777484c2010-07-23 16:22:44 -0700389 return false;
390 }
391 return true;
392}
393
Ben Chan6e709a12012-02-29 12:10:44 -0800394UserCollector::ErrorType UserCollector::ConvertCoreToMinidump(
395 pid_t pid,
396 const FilePath &container_dir,
397 const FilePath &core_path,
398 const FilePath &minidump_path) {
Ben Chanec7d7832012-01-09 10:29:58 -0800399 // If proc files are unuable, we continue to read the core file from stdin,
400 // but only skip the core-to-minidump conversion, so that we may still use
401 // the core file for debugging.
402 bool proc_files_usable =
403 CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir);
404
405 if (!CopyStdinToCoreFile(core_path)) {
Ben Chan6e709a12012-02-29 12:10:44 -0800406 return kErrorReadCoreData;
Ken Mixter777484c2010-07-23 16:22:44 -0700407 }
408
Ben Chanec7d7832012-01-09 10:29:58 -0800409 if (!proc_files_usable) {
410 LOG(INFO) << "Skipped converting core file to minidump due to "
411 << "unusable proc files";
Ben Chan6e709a12012-02-29 12:10:44 -0800412 return kErrorUnusableProcFiles;
Ken Mixter777484c2010-07-23 16:22:44 -0700413 }
414
Ben Chan6e709a12012-02-29 12:10:44 -0800415 ErrorType error = ValidateCoreFile(core_path);
416 if (error != kErrorNone) {
417 return error;
Ken Mixter777484c2010-07-23 16:22:44 -0700418 }
419
Ben Chan6e709a12012-02-29 12:10:44 -0800420 if (!RunCoreToMinidump(core_path,
421 container_dir, // procfs directory
422 minidump_path,
423 container_dir)) { // temporary directory
424 return kErrorCore2MinidumpConversion;
425 }
426
427 LOG(INFO) << "Stored minidump to " << minidump_path.value();
428 return kErrorNone;
Ken Mixter207694d2010-10-28 15:42:37 -0700429}
430
Ben Chan6e709a12012-02-29 12:10:44 -0800431UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash(
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700432 pid_t pid, const std::string &exec, uid_t supplied_ruid,
433 bool *out_of_capacity) {
Ken Mixter207694d2010-10-28 15:42:37 -0700434 FilePath crash_path;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700435 if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path,
436 out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800437 LOG(ERROR) << "Unable to find/create process-specific crash path";
Ben Chan6e709a12012-02-29 12:10:44 -0800438 return kErrorSystemIssue;
Ken Mixter207694d2010-10-28 15:42:37 -0700439 }
440
Ben Chan294d5d12012-01-04 20:40:15 -0800441 // Directory like /tmp/crash_reporter/1234 which contains the
Ken Mixter207694d2010-10-28 15:42:37 -0700442 // procfs entries and other temporary files used during conversion.
Ben Chan7e776902014-06-18 13:19:51 -0700443 FilePath container_dir(StringPrintf("/tmp/crash_reporter/%d", pid));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800444 // Delete a pre-existing directory from crash reporter that may have
445 // been left around for diagnostics from a failed conversion attempt.
446 // If we don't, existing files can cause forking to fail.
Mike Frysingera557c112014-02-05 22:55:39 -0500447 base::DeleteFile(container_dir, true);
Ben Chan262d7982014-09-18 08:05:20 -0700448 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Ken Mixter207694d2010-10-28 15:42:37 -0700449 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
450 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
451 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
Ken Mixterc49dbd42010-12-14 17:44:11 -0800452 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
453
Simon Queacc79382012-05-04 18:10:09 -0700454 if (GetLogContents(FilePath(log_config_path_), exec, log_path))
Ken Mixterc49dbd42010-12-14 17:44:11 -0800455 AddCrashMetaData("log", log_path.value());
Ken Mixter207694d2010-10-28 15:42:37 -0700456
Ben Chan6e709a12012-02-29 12:10:44 -0800457 ErrorType error_type =
458 ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
459 if (error_type != kErrorNone) {
Ken Mixtera3249322011-03-03 08:47:38 -0800460 LOG(INFO) << "Leaving core file at " << core_path.value()
461 << " due to conversion error";
Ben Chan6e709a12012-02-29 12:10:44 -0800462 return error_type;
Ken Mixter207694d2010-10-28 15:42:37 -0700463 }
464
465 // Here we commit to sending this file. We must not return false
466 // after this point or we will generate a log report as well as a
467 // crash report.
468 WriteCrashMetaData(meta_path,
469 exec,
470 minidump_path.value());
471
Michael Krebs538ecbf2011-07-27 14:13:22 -0700472 if (!IsDeveloperImage()) {
Mike Frysingera557c112014-02-05 22:55:39 -0500473 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700474 } else {
Ken Mixtera3249322011-03-03 08:47:38 -0800475 LOG(INFO) << "Leaving core file at " << core_path.value()
476 << " due to developer image";
Ken Mixter777484c2010-07-23 16:22:44 -0700477 }
478
Mike Frysingera557c112014-02-05 22:55:39 -0500479 base::DeleteFile(container_dir, true);
Ben Chan6e709a12012-02-29 12:10:44 -0800480 return kErrorNone;
Ken Mixter777484c2010-07-23 16:22:44 -0700481}
482
Ken Mixter1b8fe012011-01-25 13:33:05 -0800483bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700484 pid_t *pid, int *signal, uid_t *uid,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800485 std::string *kernel_supplied_name) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700486 pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(.*)");
487 if (re.FullMatch(crash_attributes, pid, signal, uid, kernel_supplied_name))
488 return true;
489
490 LOG(INFO) << "Falling back to parsing crash attributes '"
491 << crash_attributes << "' without UID";
492 pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)");
493 *uid = kUnknownUid;
494 return re_without_uid.FullMatch(crash_attributes, pid, signal,
495 kernel_supplied_name);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800496}
497
Ben Chan7e776902014-06-18 13:19:51 -0700498// Returns true if the given executable name matches that of Chrome. This
499// includes checks for threads that Chrome has renamed.
Michael Krebs2f3ed032012-08-21 20:17:03 -0700500static bool IsChromeExecName(const std::string &exec) {
501 static const char *kChromeNames[] = {
502 "chrome",
Ben Chan7e776902014-06-18 13:19:51 -0700503 // These are additional thread names seen in http://crash/
Michael Krebsb1b91a52012-11-26 14:26:17 -0800504 "MediaPipeline",
Ben Chan7e776902014-06-18 13:19:51 -0700505 // These come from the use of base::PlatformThread::SetName() directly
Michael Krebs2f3ed032012-08-21 20:17:03 -0700506 "CrBrowserMain", "CrRendererMain", "CrUtilityMain", "CrPPAPIMain",
507 "CrPPAPIBrokerMain", "CrPluginMain", "CrWorkerMain", "CrGpuMain",
508 "BrokerEvent", "CrVideoRenderer", "CrShutdownDetector",
509 "UsbEventHandler", "CrNaClMain", "CrServiceMain",
Ben Chan7e776902014-06-18 13:19:51 -0700510 // These thread names come from the use of base::Thread
Michael Krebs2f3ed032012-08-21 20:17:03 -0700511 "Gamepad polling thread", "Chrome_InProcGpuThread",
512 "Chrome_DragDropThread", "Renderer::FILE", "VC manager",
513 "VideoCaptureModuleImpl", "JavaBridge", "VideoCaptureManagerThread",
514 "Geolocation", "Geolocation_wifi_provider",
515 "Device orientation polling thread", "Chrome_InProcRendererThread",
516 "NetworkChangeNotifier", "Watchdog", "inotify_reader",
517 "cf_iexplore_background_thread", "BrowserWatchdog",
518 "Chrome_HistoryThread", "Chrome_SyncThread", "Chrome_ShellDialogThread",
519 "Printing_Worker", "Chrome_SafeBrowsingThread", "SimpleDBThread",
520 "D-Bus thread", "AudioThread", "NullAudioThread", "V4L2Thread",
521 "ChromotingClientDecodeThread", "Profiling_Flush",
522 "worker_thread_ticker", "AudioMixerAlsa", "AudioMixerCras",
523 "FakeAudioRecordingThread", "CaptureThread",
524 "Chrome_WebSocketproxyThread", "ProcessWatcherThread",
525 "Chrome_CameraThread", "import_thread", "NaCl_IOThread",
526 "Chrome_CloudPrintJobPrintThread", "Chrome_CloudPrintProxyCoreThread",
527 "DaemonControllerFileIO", "ChromotingMainThread",
528 "ChromotingEncodeThread", "ChromotingDesktopThread",
529 "ChromotingIOThread", "ChromotingFileIOThread",
530 "Chrome_libJingle_WorkerThread", "Chrome_ChildIOThread",
531 "GLHelperThread", "RemotingHostPlugin",
532 // "PAC thread #%d", // not easy to check because of "%d"
533 "Chrome_DBThread", "Chrome_WebKitThread", "Chrome_FileThread",
534 "Chrome_FileUserBlockingThread", "Chrome_ProcessLauncherThread",
535 "Chrome_CacheThread", "Chrome_IOThread", "Cache Thread", "File Thread",
536 "ServiceProcess_IO", "ServiceProcess_File",
537 "extension_crash_uploader", "gpu-process_crash_uploader",
538 "plugin_crash_uploader", "renderer_crash_uploader",
Ben Chan7e776902014-06-18 13:19:51 -0700539 // These come from the use of webkit_glue::WebThreadImpl
Michael Krebs2f3ed032012-08-21 20:17:03 -0700540 "Compositor", "Browser Compositor",
541 // "WorkerPool/%d", // not easy to check because of "%d"
Ben Chan7e776902014-06-18 13:19:51 -0700542 // These come from the use of base::Watchdog
Michael Krebs2f3ed032012-08-21 20:17:03 -0700543 "Startup watchdog thread Watchdog", "Shutdown watchdog thread Watchdog",
Ben Chan7e776902014-06-18 13:19:51 -0700544 // These come from the use of AudioDeviceThread::Start
Michael Krebsa1cc3832012-09-13 13:24:12 -0700545 "AudioDevice", "AudioInputDevice", "AudioOutputDevice",
Ben Chan7e776902014-06-18 13:19:51 -0700546 // These come from the use of MessageLoopFactory::GetMessageLoop
Michael Krebs2f3ed032012-08-21 20:17:03 -0700547 "GpuVideoDecoder", "RtcVideoDecoderThread", "PipelineThread",
548 "AudioDecoderThread", "VideoDecoderThread",
Ben Chan7e776902014-06-18 13:19:51 -0700549 // These come from the use of MessageLoopFactory::GetMessageLoopProxy
Michael Krebs2f3ed032012-08-21 20:17:03 -0700550 "CaptureVideoDecoderThread", "CaptureVideoDecoder",
Ben Chan7e776902014-06-18 13:19:51 -0700551 // These come from the use of base::SimpleThread
Michael Krebs2f3ed032012-08-21 20:17:03 -0700552 "LocalInputMonitor/%d", // "%d" gets lopped off for kernel-supplied
Ben Chan7e776902014-06-18 13:19:51 -0700553 // These come from the use of base::DelegateSimpleThread
Michael Krebs2f3ed032012-08-21 20:17:03 -0700554 "ipc_channel_nacl reader thread/%d", "plugin_audio_input_thread/%d",
555 "plugin_audio_thread/%d",
Ben Chan7e776902014-06-18 13:19:51 -0700556 // These come from the use of base::SequencedWorkerPool
Michael Krebs2f3ed032012-08-21 20:17:03 -0700557 "BrowserBlockingWorker%d/%d", // "%d" gets lopped off for kernel-supplied
558 };
559 static std::set<std::string> chrome_names;
560
Ben Chan7e776902014-06-18 13:19:51 -0700561 // Initialize a set of chrome names, for efficient lookup
Michael Krebs2f3ed032012-08-21 20:17:03 -0700562 if (chrome_names.empty()) {
563 for (size_t i = 0; i < arraysize(kChromeNames); i++) {
564 std::string check_name(kChromeNames[i]);
565 chrome_names.insert(check_name);
566 // When checking a kernel-supplied name, it should be truncated to 15
567 // chars. See PR_SET_NAME in
568 // http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html,
569 // although that page misleads by saying "16 bytes".
570 chrome_names.insert("supplied_" + std::string(check_name, 0, 15));
571 }
572 }
573
574 return ContainsKey(chrome_names, exec);
575}
576
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700577bool UserCollector::ShouldDump(bool has_owner_consent,
578 bool is_developer,
Michael Krebs4fe30db2011-08-05 13:54:52 -0700579 bool handle_chrome_crashes,
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700580 const std::string &exec,
581 std::string *reason) {
582 reason->clear();
583
584 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome
585 // crashes towards user crashes, so user crashes really mean non-Chrome
586 // user-space crashes.
Michael Krebs2f3ed032012-08-21 20:17:03 -0700587 if (!handle_chrome_crashes && IsChromeExecName(exec)) {
Mike Frysingerd2db5ff2013-10-08 19:03:23 -0400588 *reason = "ignoring call by kernel - chrome crash; "
589 "waiting for chrome to call us directly";
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700590 return false;
591 }
592
593 // For developer builds, we always want to keep the crash reports unless
594 // we're testing the crash facilities themselves. This overrides
595 // feedback. Crash sending still obeys consent.
Michael Krebs538ecbf2011-07-27 14:13:22 -0700596 if (is_developer) {
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700597 *reason = "developer build - not testing - always dumping";
598 return true;
599 }
600
601 if (!has_owner_consent) {
602 *reason = "ignoring - no consent";
603 return false;
604 }
605
606 *reason = "handling";
607 return true;
608}
609
Ken Mixter1b8fe012011-01-25 13:33:05 -0800610bool UserCollector::HandleCrash(const std::string &crash_attributes,
611 const char *force_exec) {
Chris Sosae4a86032010-06-16 17:08:34 -0700612 CHECK(initialized_);
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700613 pid_t pid = 0;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800614 int signal = 0;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700615 uid_t supplied_ruid = kUnknownUid;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800616 std::string kernel_supplied_name;
617
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700618 if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800619 &kernel_supplied_name)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800620 LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800621 return false;
622 }
623
Ken Mixter777484c2010-07-23 16:22:44 -0700624 std::string exec;
625 if (force_exec) {
626 exec.assign(force_exec);
627 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800628 // If we cannot find the exec name, use the kernel supplied name.
629 // We don't always use the kernel's since it truncates the name to
630 // 16 characters.
631 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700632 }
Ken Mixterc6a58e02010-11-01 18:05:30 -0700633
634 // Allow us to test the crash reporting mechanism successfully even if
635 // other parts of the system crash.
Steve Fungd6169a22014-08-11 15:52:23 -0700636 if (!filter_in_.empty() &&
637 (filter_in_ == "none" ||
638 filter_in_ != exec)) {
Ken Mixterc6a58e02010-11-01 18:05:30 -0700639 // We use a different format message to make it more obvious in tests
640 // which crashes are test generated and which are real.
Ken Mixtera3249322011-03-03 08:47:38 -0800641 LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while "
Steve Fungd6169a22014-08-11 15:52:23 -0700642 << "filter_in=" << filter_in_ << ".";
Ken Mixterc6a58e02010-11-01 18:05:30 -0700643 return true;
644 }
645
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700646 std::string reason;
647 bool dump = ShouldDump(is_feedback_allowed_function_(),
Michael Krebs538ecbf2011-07-27 14:13:22 -0700648 IsDeveloperImage(),
Michael Krebs4fe30db2011-08-05 13:54:52 -0700649 ShouldHandleChromeCrashes(),
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700650 exec,
651 &reason);
Ken Mixter2105b492010-11-09 16:14:38 -0800652
Ken Mixtera3249322011-03-03 08:47:38 -0800653 LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700654 << "] sig " << signal << ", user " << supplied_ruid
655 << " (" << reason << ")";
Chris Sosae4a86032010-06-16 17:08:34 -0700656
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700657 if (dump) {
Chris Sosae4a86032010-06-16 17:08:34 -0700658 count_crash_function_();
Ken Mixter777484c2010-07-23 16:22:44 -0700659
Ken Mixter03403162010-08-18 15:23:16 -0700660 if (generate_diagnostics_) {
Ken Mixter207694d2010-10-28 15:42:37 -0700661 bool out_of_capacity = false;
Ben Chan6e709a12012-02-29 12:10:44 -0800662 ErrorType error_type =
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700663 ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity);
Ben Chan6e709a12012-02-29 12:10:44 -0800664 if (error_type != kErrorNone) {
Ken Mixter207694d2010-10-28 15:42:37 -0700665 if (!out_of_capacity)
Ben Chan6e709a12012-02-29 12:10:44 -0800666 EnqueueCollectionErrorLog(pid, error_type, exec);
Ken Mixter207694d2010-10-28 15:42:37 -0700667 return false;
668 }
Ken Mixter03403162010-08-18 15:23:16 -0700669 }
Ken Mixter777484c2010-07-23 16:22:44 -0700670 }
Ken Mixter207694d2010-10-28 15:42:37 -0700671
Ken Mixter777484c2010-07-23 16:22:44 -0700672 return true;
Chris Sosae4a86032010-06-16 17:08:34 -0700673}