blob: 61ccc37bd6ba2273237c316b87075fc20fab5a2e [file] [log] [blame]
Steve Fung6c34c252015-08-20 00:27:30 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Chris Sosae4a86032010-06-16 17:08:34 -070016
Steve Fung129bea52015-07-23 13:11:15 -070017#include "user_collector.h"
Ken Mixter03403162010-08-18 15:23:16 -070018
Ben Chan6e709a12012-02-29 12:10:44 -080019#include <elf.h>
20#include <fcntl.h>
Ken Mixter777484c2010-07-23 16:22:44 -070021#include <grp.h> // For struct group.
Ken Mixter1b8fe012011-01-25 13:33:05 -080022#include <pcrecpp.h>
Ken Mixter777484c2010-07-23 16:22:44 -070023#include <pwd.h> // For struct passwd.
Ben Chanf84ea212014-08-06 17:27:48 -070024#include <stdint.h>
Steve Fung8bafb3d2015-08-07 13:22:46 -070025#include <sys/cdefs.h> // For __WORDSIZE
Ken Mixter2953c3a2010-10-18 14:42:20 -070026#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
Steve Fungb440e502015-08-21 02:12:34 -070027#include <unistd.h> // For setgroups
Ken Mixter777484c2010-07-23 16:22:44 -070028
Chris Sosae4a86032010-06-16 17:08:34 -070029#include <string>
Ken Mixter2953c3a2010-10-18 14:42:20 -070030#include <vector>
Chris Sosae4a86032010-06-16 17:08:34 -070031
Ben Chanab6cc902014-09-05 08:21:06 -070032#include <base/files/file_util.h>
Ben Chan7e776902014-06-18 13:19:51 -070033#include <base/logging.h>
34#include <base/posix/eintr_wrapper.h>
Ben Chan7e776902014-06-18 13:19:51 -070035#include <base/strings/string_split.h>
36#include <base/strings/string_util.h>
37#include <base/strings/stringprintf.h>
38#include <chromeos/process.h>
39#include <chromeos/syslog_logging.h>
Steve Fungab2ac7d2015-08-14 17:58:05 -070040#include <cutils/properties.h>
Steve Fungb440e502015-08-21 02:12:34 -070041#include <private/android_filesystem_config.h>
Ken Mixter207694d2010-10-28 15:42:37 -070042
43static const char kCollectionErrorSignature[] =
44 "crash_reporter-user-collection";
Steve Fungab2ac7d2015-08-14 17:58:05 -070045static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled";
46static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md";
Ken Mixter777484c2010-07-23 16:22:44 -070047
Ben Chanf13bb582012-01-06 08:22:07 -080048static const char kStatePrefix[] = "State:\t";
Ken Mixterc49dbd42010-12-14 17:44:11 -080049
Steve Fungda981332015-08-23 17:18:23 -070050static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
Steve Fungab2ac7d2015-08-14 17:58:05 -070051
Michael Krebs1c57e9e2012-09-25 18:03:13 -070052// Define an otherwise invalid value that represents an unknown UID.
53static const uid_t kUnknownUid = -1;
54
Ken Mixter777484c2010-07-23 16:22:44 -070055const char *UserCollector::kUserId = "Uid:\t";
56const char *UserCollector::kGroupId = "Gid:\t";
Chris Sosae4a86032010-06-16 17:08:34 -070057
Simon Que9f90aca2013-02-19 17:19:52 -080058using base::FilePath;
Mike Frysingera557c112014-02-05 22:55:39 -050059using base::StringPrintf;
Simon Que9f90aca2013-02-19 17:19:52 -080060
Chris Sosae4a86032010-06-16 17:08:34 -070061UserCollector::UserCollector()
Ken Mixter777484c2010-07-23 16:22:44 -070062 : generate_diagnostics_(false),
Ken Mixter03403162010-08-18 15:23:16 -070063 initialized_(false) {
Chris Sosae4a86032010-06-16 17:08:34 -070064}
65
66void UserCollector::Initialize(
67 UserCollector::CountCrashFunction count_crash_function,
68 const std::string &our_path,
69 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
Steve Fungd6169a22014-08-11 15:52:23 -070070 bool generate_diagnostics,
71 bool core2md_failure,
72 bool directory_failure,
73 const std::string &filter_in) {
Ken Mixter03403162010-08-18 15:23:16 -070074 CrashCollector::Initialize(count_crash_function,
Ken Mixtera3249322011-03-03 08:47:38 -080075 is_feedback_allowed_function);
Chris Sosae4a86032010-06-16 17:08:34 -070076 our_path_ = our_path;
Chris Sosae4a86032010-06-16 17:08:34 -070077 initialized_ = true;
Ken Mixter777484c2010-07-23 16:22:44 -070078 generate_diagnostics_ = generate_diagnostics;
Steve Fungd6169a22014-08-11 15:52:23 -070079 core2md_failure_ = core2md_failure;
80 directory_failure_ = directory_failure;
81 filter_in_ = filter_in;
Steve Fungb440e502015-08-21 02:12:34 -070082
83 gid_t groups[] = { AID_SYSTEM, AID_DBUS };
84 if (setgroups(arraysize(groups), groups) != 0) {
85 PLOG(FATAL) << "Unable to set groups to system and dbus";
86 }
Chris Sosae4a86032010-06-16 17:08:34 -070087}
88
89UserCollector::~UserCollector() {
90}
91
Ben Chan6e709a12012-02-29 12:10:44 -080092std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const {
93 switch (error_type) {
94 case kErrorSystemIssue:
95 return "system-issue";
96 case kErrorReadCoreData:
97 return "read-core-data";
98 case kErrorUnusableProcFiles:
99 return "unusable-proc-files";
100 case kErrorInvalidCoreFile:
101 return "invalid-core-file";
102 case kErrorUnsupported32BitCoreFile:
103 return "unsupported-32bit-core-file";
104 case kErrorCore2MinidumpConversion:
105 return "core2md-conversion";
106 default:
107 return "";
108 }
109}
110
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700111// Return the string that should be used for the kernel's core_pattern file.
112// Note that if you change the format of the enabled pattern, you'll probably
113// also need to change the ParseCrashAttributes() function below, the
114// user_collector_test.cc unittest, and the logging_UserCrash.py autotest.
Chris Sosae4a86032010-06-16 17:08:34 -0700115std::string UserCollector::GetPattern(bool enabled) const {
116 if (enabled) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700117 // Combine the four crash attributes into one parameter to try to reduce
118 // the size of the invocation line for crash_reporter, since the kernel
119 // has a fixed-sized (128B) buffer for it (before parameter expansion).
120 // Note that the kernel does not support quoted arguments in core_pattern.
Mike Frysingerbfdf4a82014-03-14 09:31:33 -0400121 return StringPrintf("|%s --user=%%P:%%s:%%u:%%e", our_path_.c_str());
Chris Sosae4a86032010-06-16 17:08:34 -0700122 } else {
123 return "core";
124 }
125}
126
127bool UserCollector::SetUpInternal(bool enabled) {
128 CHECK(initialized_);
Ken Mixtera3249322011-03-03 08:47:38 -0800129 LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
130
Steve Fungab2ac7d2015-08-14 17:58:05 -0700131 property_set(kCorePatternProperty, enabled ? "1" : "0");
132
Chris Sosae4a86032010-06-16 17:08:34 -0700133 return true;
134}
135
Ben Chanf13bb582012-01-06 08:22:07 -0800136bool UserCollector::GetFirstLineWithPrefix(
137 const std::vector<std::string> &lines,
138 const char *prefix, std::string *line) {
139 std::vector<std::string>::const_iterator line_iterator;
140 for (line_iterator = lines.begin(); line_iterator != lines.end();
141 ++line_iterator) {
142 if (line_iterator->find(prefix) == 0) {
143 *line = *line_iterator;
144 return true;
145 }
146 }
147 return false;
148}
149
150bool UserCollector::GetIdFromStatus(
151 const char *prefix, IdKind kind,
152 const std::vector<std::string> &status_lines, int *id) {
Ken Mixter777484c2010-07-23 16:22:44 -0700153 // From fs/proc/array.c:task_state(), this file contains:
154 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n
Ben Chanf13bb582012-01-06 08:22:07 -0800155 std::string id_line;
156 if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700157 return false;
158 }
Ben Chanf13bb582012-01-06 08:22:07 -0800159 std::string id_substring = id_line.substr(strlen(prefix), std::string::npos);
Ken Mixter777484c2010-07-23 16:22:44 -0700160 std::vector<std::string> ids;
Chris Masone3ba6c5b2011-05-13 16:57:09 -0700161 base::SplitString(id_substring, '\t', &ids);
Ken Mixter777484c2010-07-23 16:22:44 -0700162 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
163 return false;
164 }
165 const char *number = ids[kind].c_str();
Ben Chan262d7982014-09-18 08:05:20 -0700166 char *end_number = nullptr;
Ken Mixter777484c2010-07-23 16:22:44 -0700167 *id = strtol(number, &end_number, 10);
Ben Chanf13bb582012-01-06 08:22:07 -0800168 if (*end_number != '\0') {
Ken Mixter777484c2010-07-23 16:22:44 -0700169 return false;
Ben Chanf13bb582012-01-06 08:22:07 -0800170 }
171 return true;
172}
173
174bool UserCollector::GetStateFromStatus(
175 const std::vector<std::string> &status_lines, std::string *state) {
176 std::string state_line;
177 if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) {
178 return false;
179 }
180 *state = state_line.substr(strlen(kStatePrefix), std::string::npos);
Ken Mixter777484c2010-07-23 16:22:44 -0700181 return true;
182}
183
Ken Mixter207694d2010-10-28 15:42:37 -0700184void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
Ben Chan6e709a12012-02-29 12:10:44 -0800185 ErrorType error_type,
Ken Mixter207694d2010-10-28 15:42:37 -0700186 const std::string &exec) {
187 FilePath crash_path;
Ken Mixtera3249322011-03-03 08:47:38 -0800188 LOG(INFO) << "Writing conversion problems as separate crash report.";
Ben Chan262d7982014-09-18 08:05:20 -0700189 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800190 LOG(ERROR) << "Could not even get log directory; out of space?";
Ken Mixter207694d2010-10-28 15:42:37 -0700191 return;
192 }
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200193 AddCrashMetaData("sig", kCollectionErrorSignature);
194 AddCrashMetaData("error_type", GetErrorTypeSignature(error_type));
Ben Chan262d7982014-09-18 08:05:20 -0700195 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Ken Mixtera3249322011-03-03 08:47:38 -0800196 std::string error_log = chromeos::GetLog();
Ken Mixter1b8fe012011-01-25 13:33:05 -0800197 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
Simon Queacc79382012-05-04 18:10:09 -0700198 if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800199 diag_log_path)) {
200 // We load the contents of diag_log into memory and append it to
201 // the error log. We cannot just append to files because we need
202 // to always create new files to prevent attack.
203 std::string diag_log_contents;
Mike Frysingera557c112014-02-05 22:55:39 -0500204 base::ReadFileToString(diag_log_path, &diag_log_contents);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800205 error_log.append(diag_log_contents);
Mike Frysingera557c112014-02-05 22:55:39 -0500206 base::DeleteFile(diag_log_path, false);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800207 }
Ken Mixter207694d2010-10-28 15:42:37 -0700208 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
209 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
Ben Chanf30c6412014-05-22 23:09:01 -0700210 // We must use WriteNewFile instead of base::WriteFile as we do
Ken Mixter9b346472010-11-07 13:45:45 -0800211 // not want to write with root access to a symlink that an attacker
212 // might have created.
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200213 if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) {
214 LOG(ERROR) << "Error writing new file " << log_path.value();
215 return;
216 }
Ken Mixter207694d2010-10-28 15:42:37 -0700217 WriteCrashMetaData(meta_path, exec, log_path.value());
218}
219
Ken Mixter777484c2010-07-23 16:22:44 -0700220bool UserCollector::CopyOffProcFiles(pid_t pid,
221 const FilePath &container_dir) {
Mike Frysingera557c112014-02-05 22:55:39 -0500222 if (!base::CreateDirectory(container_dir)) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700223 PLOG(ERROR) << "Could not create " << container_dir.value().c_str();
Ken Mixter777484c2010-07-23 16:22:44 -0700224 return false;
225 }
226 FilePath process_path = GetProcessPath(pid);
Mike Frysingera557c112014-02-05 22:55:39 -0500227 if (!base::PathExists(process_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800228 LOG(ERROR) << "Path " << process_path.value() << " does not exist";
Ken Mixter777484c2010-07-23 16:22:44 -0700229 return false;
230 }
231 static const char *proc_files[] = {
232 "auxv",
233 "cmdline",
234 "environ",
235 "maps",
236 "status"
237 };
238 for (unsigned i = 0; i < arraysize(proc_files); ++i) {
Mike Frysingera557c112014-02-05 22:55:39 -0500239 if (!base::CopyFile(process_path.Append(proc_files[i]),
240 container_dir.Append(proc_files[i]))) {
Ken Mixtera3249322011-03-03 08:47:38 -0800241 LOG(ERROR) << "Could not copy " << proc_files[i] << " file";
Ken Mixter777484c2010-07-23 16:22:44 -0700242 return false;
243 }
244 }
Ben Chanec7d7832012-01-09 10:29:58 -0800245 return true;
Ben Chanf13bb582012-01-06 08:22:07 -0800246}
247
Ben Chan6e709a12012-02-29 12:10:44 -0800248bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const {
Ben Chanf13bb582012-01-06 08:22:07 -0800249 // Check if the maps file is empty, which could be due to the crashed
250 // process being reaped by the kernel before finishing a core dump.
Ben Chanf84ea212014-08-06 17:27:48 -0700251 int64_t file_size = 0;
Mike Frysingera557c112014-02-05 22:55:39 -0500252 if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) {
Ben Chanf13bb582012-01-06 08:22:07 -0800253 LOG(ERROR) << "Could not get the size of maps file";
254 return false;
255 }
256 if (file_size == 0) {
257 LOG(ERROR) << "maps file is empty";
258 return false;
259 }
Ken Mixter777484c2010-07-23 16:22:44 -0700260 return true;
261}
262
Ben Chan6e709a12012-02-29 12:10:44 -0800263UserCollector::ErrorType UserCollector::ValidateCoreFile(
264 const FilePath &core_path) const {
265 int fd = HANDLE_EINTR(open(core_path.value().c_str(), O_RDONLY));
266 if (fd < 0) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700267 PLOG(ERROR) << "Could not open core file " << core_path.value();
Ben Chan6e709a12012-02-29 12:10:44 -0800268 return kErrorInvalidCoreFile;
269 }
270
271 char e_ident[EI_NIDENT];
Mike Frysingera557c112014-02-05 22:55:39 -0500272 bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident));
Mike Frysingerf1a50142014-05-14 16:05:09 -0400273 IGNORE_EINTR(close(fd));
Ben Chan6e709a12012-02-29 12:10:44 -0800274 if (!read_ok) {
275 LOG(ERROR) << "Could not read header of core file";
276 return kErrorInvalidCoreFile;
277 }
278
279 if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
280 e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
281 LOG(ERROR) << "Invalid core file";
282 return kErrorInvalidCoreFile;
283 }
284
285#if __WORDSIZE == 64
286 // TODO(benchan, mkrebs): Remove this check once core2md can
287 // handles both 32-bit and 64-bit ELF on a 64-bit platform.
288 if (e_ident[EI_CLASS] == ELFCLASS32) {
289 LOG(ERROR) << "Conversion of 32-bit core file on 64-bit platform is "
290 << "currently not supported";
291 return kErrorUnsupported32BitCoreFile;
292 }
293#endif
294
295 return kErrorNone;
296}
297
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700298bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
Ken Mixter207694d2010-10-28 15:42:37 -0700299 FilePath *crash_file_path,
300 bool *out_of_capacity) {
Ken Mixter777484c2010-07-23 16:22:44 -0700301 FilePath process_path = GetProcessPath(pid);
302 std::string status;
Steve Fungd6169a22014-08-11 15:52:23 -0700303 if (directory_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800304 LOG(ERROR) << "Purposefully failing to create spool directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700305 return false;
306 }
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700307
308 uid_t uid;
Mike Frysingera557c112014-02-05 22:55:39 -0500309 if (base::ReadFileToString(process_path.Append("status"), &status)) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700310 std::vector<std::string> status_lines;
311 base::SplitString(status, '\n', &status_lines);
312
313 std::string process_state;
314 if (!GetStateFromStatus(status_lines, &process_state)) {
315 LOG(ERROR) << "Could not find process state in status file";
316 return false;
317 }
318 LOG(INFO) << "State of crashed process [" << pid << "]: " << process_state;
319
320 // Get effective UID of crashing process.
321 int id;
322 if (!GetIdFromStatus(kUserId, kIdEffective, status_lines, &id)) {
323 LOG(ERROR) << "Could not find euid in status file";
324 return false;
325 }
326 uid = id;
327 } else if (supplied_ruid != kUnknownUid) {
328 LOG(INFO) << "Using supplied UID " << supplied_ruid
329 << " for crashed process [" << pid
330 << "] due to error reading status file";
331 uid = supplied_ruid;
332 } else {
333 LOG(ERROR) << "Could not read status file and kernel did not supply UID";
Ken Mixtera3249322011-03-03 08:47:38 -0800334 LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: "
Mike Frysingera557c112014-02-05 22:55:39 -0500335 << base::DirectoryExists(process_path);
Ken Mixter777484c2010-07-23 16:22:44 -0700336 return false;
337 }
Ben Chanf13bb582012-01-06 08:22:07 -0800338
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700339 if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800340 LOG(ERROR) << "Could not create crash directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700341 return false;
342 }
343 return true;
Ken Mixter777484c2010-07-23 16:22:44 -0700344}
345
346bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
347 // Copy off all stdin to a core file.
Steve Fungab2ac7d2015-08-14 17:58:05 -0700348 FilePath stdin_path("/proc/self/fd/0");
Mike Frysingera557c112014-02-05 22:55:39 -0500349 if (base::CopyFile(stdin_path, core_path)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700350 return true;
351 }
352
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700353 PLOG(ERROR) << "Could not write core file";
Ken Mixter777484c2010-07-23 16:22:44 -0700354 // If the file system was full, make sure we remove any remnants.
Mike Frysingera557c112014-02-05 22:55:39 -0500355 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700356 return false;
357}
358
Ken Mixter207694d2010-10-28 15:42:37 -0700359bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
360 const FilePath &procfs_directory,
361 const FilePath &minidump_path,
362 const FilePath &temp_directory) {
Ken Mixter777484c2010-07-23 16:22:44 -0700363 FilePath output_path = temp_directory.Append("output");
Ken Mixtera3249322011-03-03 08:47:38 -0800364 chromeos::ProcessImpl core2md;
365 core2md.RedirectOutput(output_path.value());
366 core2md.AddArg(kCoreToMinidumpConverterPath);
367 core2md.AddArg(core_path.value());
368 core2md.AddArg(procfs_directory.value());
Ken Mixter2953c3a2010-10-18 14:42:20 -0700369
Steve Fungd6169a22014-08-11 15:52:23 -0700370 if (!core2md_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800371 core2md.AddArg(minidump_path.value());
372 } else {
Ken Mixter207694d2010-10-28 15:42:37 -0700373 // To test how core2md errors are propagaged, cause an error
374 // by forgetting a required argument.
Ken Mixter207694d2010-10-28 15:42:37 -0700375 }
376
Ken Mixtera3249322011-03-03 08:47:38 -0800377 int errorlevel = core2md.Run();
Ken Mixter777484c2010-07-23 16:22:44 -0700378
379 std::string output;
Mike Frysingera557c112014-02-05 22:55:39 -0500380 base::ReadFileToString(output_path, &output);
Ken Mixter777484c2010-07-23 16:22:44 -0700381 if (errorlevel != 0) {
Ken Mixtera3249322011-03-03 08:47:38 -0800382 LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath
383 << " [result=" << errorlevel << "]: " << output;
Ken Mixter777484c2010-07-23 16:22:44 -0700384 return false;
385 }
386
Mike Frysingera557c112014-02-05 22:55:39 -0500387 if (!base::PathExists(minidump_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800388 LOG(ERROR) << "Minidump file " << minidump_path.value()
389 << " was not created";
Ken Mixter777484c2010-07-23 16:22:44 -0700390 return false;
391 }
392 return true;
393}
394
Ben Chan6e709a12012-02-29 12:10:44 -0800395UserCollector::ErrorType UserCollector::ConvertCoreToMinidump(
396 pid_t pid,
397 const FilePath &container_dir,
398 const FilePath &core_path,
399 const FilePath &minidump_path) {
Ben Chanec7d7832012-01-09 10:29:58 -0800400 // If proc files are unuable, we continue to read the core file from stdin,
401 // but only skip the core-to-minidump conversion, so that we may still use
402 // the core file for debugging.
403 bool proc_files_usable =
404 CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir);
405
406 if (!CopyStdinToCoreFile(core_path)) {
Ben Chan6e709a12012-02-29 12:10:44 -0800407 return kErrorReadCoreData;
Ken Mixter777484c2010-07-23 16:22:44 -0700408 }
409
Ben Chanec7d7832012-01-09 10:29:58 -0800410 if (!proc_files_usable) {
411 LOG(INFO) << "Skipped converting core file to minidump due to "
412 << "unusable proc files";
Ben Chan6e709a12012-02-29 12:10:44 -0800413 return kErrorUnusableProcFiles;
Ken Mixter777484c2010-07-23 16:22:44 -0700414 }
415
Ben Chan6e709a12012-02-29 12:10:44 -0800416 ErrorType error = ValidateCoreFile(core_path);
417 if (error != kErrorNone) {
418 return error;
Ken Mixter777484c2010-07-23 16:22:44 -0700419 }
420
Ben Chan6e709a12012-02-29 12:10:44 -0800421 if (!RunCoreToMinidump(core_path,
422 container_dir, // procfs directory
423 minidump_path,
424 container_dir)) { // temporary directory
425 return kErrorCore2MinidumpConversion;
426 }
427
428 LOG(INFO) << "Stored minidump to " << minidump_path.value();
429 return kErrorNone;
Ken Mixter207694d2010-10-28 15:42:37 -0700430}
431
Ben Chan6e709a12012-02-29 12:10:44 -0800432UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash(
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700433 pid_t pid, const std::string &exec, uid_t supplied_ruid,
434 bool *out_of_capacity) {
Ken Mixter207694d2010-10-28 15:42:37 -0700435 FilePath crash_path;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700436 if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path,
437 out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800438 LOG(ERROR) << "Unable to find/create process-specific crash path";
Ben Chan6e709a12012-02-29 12:10:44 -0800439 return kErrorSystemIssue;
Ken Mixter207694d2010-10-28 15:42:37 -0700440 }
441
Ben Chan294d5d12012-01-04 20:40:15 -0800442 // Directory like /tmp/crash_reporter/1234 which contains the
Ken Mixter207694d2010-10-28 15:42:37 -0700443 // procfs entries and other temporary files used during conversion.
Steve Fungab2ac7d2015-08-14 17:58:05 -0700444 FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800445 // Delete a pre-existing directory from crash reporter that may have
446 // been left around for diagnostics from a failed conversion attempt.
447 // If we don't, existing files can cause forking to fail.
Mike Frysingera557c112014-02-05 22:55:39 -0500448 base::DeleteFile(container_dir, true);
Ben Chan262d7982014-09-18 08:05:20 -0700449 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Ken Mixter207694d2010-10-28 15:42:37 -0700450 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
451 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
452 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
Ken Mixterc49dbd42010-12-14 17:44:11 -0800453 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
454
Simon Queacc79382012-05-04 18:10:09 -0700455 if (GetLogContents(FilePath(log_config_path_), exec, log_path))
Ken Mixterc49dbd42010-12-14 17:44:11 -0800456 AddCrashMetaData("log", log_path.value());
Ken Mixter207694d2010-10-28 15:42:37 -0700457
Ben Chan6e709a12012-02-29 12:10:44 -0800458 ErrorType error_type =
459 ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
460 if (error_type != kErrorNone) {
Ken Mixtera3249322011-03-03 08:47:38 -0800461 LOG(INFO) << "Leaving core file at " << core_path.value()
462 << " due to conversion error";
Ben Chan6e709a12012-02-29 12:10:44 -0800463 return error_type;
Ken Mixter207694d2010-10-28 15:42:37 -0700464 }
465
466 // Here we commit to sending this file. We must not return false
467 // after this point or we will generate a log report as well as a
468 // crash report.
469 WriteCrashMetaData(meta_path,
470 exec,
471 minidump_path.value());
472
Michael Krebs538ecbf2011-07-27 14:13:22 -0700473 if (!IsDeveloperImage()) {
Mike Frysingera557c112014-02-05 22:55:39 -0500474 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700475 } else {
Ken Mixtera3249322011-03-03 08:47:38 -0800476 LOG(INFO) << "Leaving core file at " << core_path.value()
477 << " due to developer image";
Ken Mixter777484c2010-07-23 16:22:44 -0700478 }
479
Mike Frysingera557c112014-02-05 22:55:39 -0500480 base::DeleteFile(container_dir, true);
Ben Chan6e709a12012-02-29 12:10:44 -0800481 return kErrorNone;
Ken Mixter777484c2010-07-23 16:22:44 -0700482}
483
Ken Mixter1b8fe012011-01-25 13:33:05 -0800484bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700485 pid_t *pid, int *signal, uid_t *uid,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800486 std::string *kernel_supplied_name) {
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700487 pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(.*)");
488 if (re.FullMatch(crash_attributes, pid, signal, uid, kernel_supplied_name))
489 return true;
490
491 LOG(INFO) << "Falling back to parsing crash attributes '"
492 << crash_attributes << "' without UID";
493 pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)");
494 *uid = kUnknownUid;
495 return re_without_uid.FullMatch(crash_attributes, pid, signal,
496 kernel_supplied_name);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800497}
498
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700499bool UserCollector::ShouldDump(bool has_owner_consent,
500 bool is_developer,
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700501 std::string *reason) {
502 reason->clear();
503
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700504 // For developer builds, we always want to keep the crash reports unless
505 // we're testing the crash facilities themselves. This overrides
506 // feedback. Crash sending still obeys consent.
Michael Krebs538ecbf2011-07-27 14:13:22 -0700507 if (is_developer) {
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700508 *reason = "developer build - not testing - always dumping";
509 return true;
510 }
511
512 if (!has_owner_consent) {
513 *reason = "ignoring - no consent";
514 return false;
515 }
516
517 *reason = "handling";
518 return true;
519}
520
Ken Mixter1b8fe012011-01-25 13:33:05 -0800521bool UserCollector::HandleCrash(const std::string &crash_attributes,
522 const char *force_exec) {
Chris Sosae4a86032010-06-16 17:08:34 -0700523 CHECK(initialized_);
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700524 pid_t pid = 0;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800525 int signal = 0;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700526 uid_t supplied_ruid = kUnknownUid;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800527 std::string kernel_supplied_name;
528
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700529 if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800530 &kernel_supplied_name)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800531 LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800532 return false;
533 }
534
Ken Mixter777484c2010-07-23 16:22:44 -0700535 std::string exec;
536 if (force_exec) {
537 exec.assign(force_exec);
538 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800539 // If we cannot find the exec name, use the kernel supplied name.
540 // We don't always use the kernel's since it truncates the name to
541 // 16 characters.
542 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700543 }
Ken Mixterc6a58e02010-11-01 18:05:30 -0700544
545 // Allow us to test the crash reporting mechanism successfully even if
546 // other parts of the system crash.
Steve Fungd6169a22014-08-11 15:52:23 -0700547 if (!filter_in_.empty() &&
548 (filter_in_ == "none" ||
549 filter_in_ != exec)) {
Ken Mixterc6a58e02010-11-01 18:05:30 -0700550 // We use a different format message to make it more obvious in tests
551 // which crashes are test generated and which are real.
Ken Mixtera3249322011-03-03 08:47:38 -0800552 LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while "
Steve Fungd6169a22014-08-11 15:52:23 -0700553 << "filter_in=" << filter_in_ << ".";
Ken Mixterc6a58e02010-11-01 18:05:30 -0700554 return true;
555 }
556
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700557 std::string reason;
558 bool dump = ShouldDump(is_feedback_allowed_function_(),
Michael Krebs538ecbf2011-07-27 14:13:22 -0700559 IsDeveloperImage(),
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700560 &reason);
Ken Mixter2105b492010-11-09 16:14:38 -0800561
Ken Mixtera3249322011-03-03 08:47:38 -0800562 LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700563 << "] sig " << signal << ", user " << supplied_ruid
564 << " (" << reason << ")";
Chris Sosae4a86032010-06-16 17:08:34 -0700565
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700566 if (dump) {
Chris Sosae4a86032010-06-16 17:08:34 -0700567 count_crash_function_();
Ken Mixter777484c2010-07-23 16:22:44 -0700568
Ken Mixter03403162010-08-18 15:23:16 -0700569 if (generate_diagnostics_) {
Ken Mixter207694d2010-10-28 15:42:37 -0700570 bool out_of_capacity = false;
Ben Chan6e709a12012-02-29 12:10:44 -0800571 ErrorType error_type =
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700572 ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity);
Ben Chan6e709a12012-02-29 12:10:44 -0800573 if (error_type != kErrorNone) {
Ken Mixter207694d2010-10-28 15:42:37 -0700574 if (!out_of_capacity)
Ben Chan6e709a12012-02-29 12:10:44 -0800575 EnqueueCollectionErrorLog(pid, error_type, exec);
Ken Mixter207694d2010-10-28 15:42:37 -0700576 return false;
577 }
Ken Mixter03403162010-08-18 15:23:16 -0700578 }
Ken Mixter777484c2010-07-23 16:22:44 -0700579 }
Ken Mixter207694d2010-10-28 15:42:37 -0700580
Ken Mixter777484c2010-07-23 16:22:44 -0700581 return true;
Chris Sosae4a86032010-06-16 17:08:34 -0700582}