blob: 98d7448f758e1a63fd2685a3d7a115a281d56334 [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
Steve Fung6db7cd72015-10-06 16:43:56 -070026#include <sys/fsuid.h>
Ken Mixter2953c3a2010-10-18 14:42:20 -070027#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
Steve Fungb440e502015-08-21 02:12:34 -070028#include <unistd.h> // For setgroups
Ken Mixter777484c2010-07-23 16:22:44 -070029
Steve Fung6db7cd72015-10-06 16:43:56 -070030#include <iostream> // For std::oct
Chris Sosae4a86032010-06-16 17:08:34 -070031#include <string>
Ken Mixter2953c3a2010-10-18 14:42:20 -070032#include <vector>
Chris Sosae4a86032010-06-16 17:08:34 -070033
Ben Chanab6cc902014-09-05 08:21:06 -070034#include <base/files/file_util.h>
Ben Chan7e776902014-06-18 13:19:51 -070035#include <base/logging.h>
36#include <base/posix/eintr_wrapper.h>
Ben Chan7e776902014-06-18 13:19:51 -070037#include <base/strings/string_split.h>
38#include <base/strings/string_util.h>
39#include <base/strings/stringprintf.h>
Alex Vakulenko74dc6242015-10-13 09:23:34 -070040#include <brillo/osrelease_reader.h>
41#include <brillo/process.h>
42#include <brillo/syslog_logging.h>
Steve Fungab2ac7d2015-08-14 17:58:05 -070043#include <cutils/properties.h>
Steve Fungb440e502015-08-21 02:12:34 -070044#include <private/android_filesystem_config.h>
Ken Mixter207694d2010-10-28 15:42:37 -070045
46static const char kCollectionErrorSignature[] =
47 "crash_reporter-user-collection";
Steve Fungab2ac7d2015-08-14 17:58:05 -070048static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled";
49static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md";
Ken Mixter777484c2010-07-23 16:22:44 -070050
Ben Chanf13bb582012-01-06 08:22:07 -080051static const char kStatePrefix[] = "State:\t";
Ken Mixterc49dbd42010-12-14 17:44:11 -080052
Steve Fungda981332015-08-23 17:18:23 -070053static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
Steve Fungab2ac7d2015-08-14 17:58:05 -070054
Steve Fung773fd3c2015-10-09 17:01:35 -070055// Define an otherwise invalid value that represents an unknown UID and GID.
Michael Krebs1c57e9e2012-09-25 18:03:13 -070056static const uid_t kUnknownUid = -1;
Steve Fung773fd3c2015-10-09 17:01:35 -070057static const gid_t kUnknownGid = -1;
Michael Krebs1c57e9e2012-09-25 18:03:13 -070058
Ken Mixter777484c2010-07-23 16:22:44 -070059const char *UserCollector::kUserId = "Uid:\t";
60const char *UserCollector::kGroupId = "Gid:\t";
Chris Sosae4a86032010-06-16 17:08:34 -070061
Steve Fung72e3c822015-10-13 14:44:37 -070062// Product information keys in the /etc/os-release.d folder.
Steve Fungaa265b62015-10-11 04:59:14 -070063static const char kBdkVersionKey[] = "bdk_version";
Steve Fung72e3c822015-10-13 14:44:37 -070064static const char kProductIDKey[] = "product_id";
65static const char kProductVersionKey[] = "product_version";
Steve Fungaa265b62015-10-11 04:59:14 -070066
Steve Fung48180112015-09-30 16:27:56 -070067
Simon Que9f90aca2013-02-19 17:19:52 -080068using base::FilePath;
Mike Frysingera557c112014-02-05 22:55:39 -050069using base::StringPrintf;
Simon Que9f90aca2013-02-19 17:19:52 -080070
Chris Sosae4a86032010-06-16 17:08:34 -070071UserCollector::UserCollector()
Ken Mixter777484c2010-07-23 16:22:44 -070072 : generate_diagnostics_(false),
Ken Mixter03403162010-08-18 15:23:16 -070073 initialized_(false) {
Chris Sosae4a86032010-06-16 17:08:34 -070074}
75
76void UserCollector::Initialize(
77 UserCollector::CountCrashFunction count_crash_function,
78 const std::string &our_path,
79 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
Steve Fungd6169a22014-08-11 15:52:23 -070080 bool generate_diagnostics,
81 bool core2md_failure,
82 bool directory_failure,
83 const std::string &filter_in) {
Ken Mixter03403162010-08-18 15:23:16 -070084 CrashCollector::Initialize(count_crash_function,
Ken Mixtera3249322011-03-03 08:47:38 -080085 is_feedback_allowed_function);
Chris Sosae4a86032010-06-16 17:08:34 -070086 our_path_ = our_path;
Chris Sosae4a86032010-06-16 17:08:34 -070087 initialized_ = true;
Ken Mixter777484c2010-07-23 16:22:44 -070088 generate_diagnostics_ = generate_diagnostics;
Steve Fungd6169a22014-08-11 15:52:23 -070089 core2md_failure_ = core2md_failure;
90 directory_failure_ = directory_failure;
91 filter_in_ = filter_in;
Steve Fungb440e502015-08-21 02:12:34 -070092
Steve Funga76ba852015-11-11 17:50:37 -080093 gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS, AID_READPROC };
Steve Fungb440e502015-08-21 02:12:34 -070094 if (setgroups(arraysize(groups), groups) != 0) {
Steve Funga76ba852015-11-11 17:50:37 -080095 PLOG(FATAL) << "Unable to set groups to root, system, dbus, and readproc";
Steve Fungb440e502015-08-21 02:12:34 -070096 }
Chris Sosae4a86032010-06-16 17:08:34 -070097}
98
99UserCollector::~UserCollector() {
100}
101
Ben Chan6e709a12012-02-29 12:10:44 -0800102std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const {
103 switch (error_type) {
104 case kErrorSystemIssue:
105 return "system-issue";
106 case kErrorReadCoreData:
107 return "read-core-data";
108 case kErrorUnusableProcFiles:
109 return "unusable-proc-files";
110 case kErrorInvalidCoreFile:
111 return "invalid-core-file";
112 case kErrorUnsupported32BitCoreFile:
113 return "unsupported-32bit-core-file";
114 case kErrorCore2MinidumpConversion:
115 return "core2md-conversion";
116 default:
117 return "";
118 }
119}
120
Chris Sosae4a86032010-06-16 17:08:34 -0700121bool UserCollector::SetUpInternal(bool enabled) {
122 CHECK(initialized_);
Ken Mixtera3249322011-03-03 08:47:38 -0800123 LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
124
Steve Fungab2ac7d2015-08-14 17:58:05 -0700125 property_set(kCorePatternProperty, enabled ? "1" : "0");
126
Chris Sosae4a86032010-06-16 17:08:34 -0700127 return true;
128}
129
Ben Chanf13bb582012-01-06 08:22:07 -0800130bool UserCollector::GetFirstLineWithPrefix(
131 const std::vector<std::string> &lines,
132 const char *prefix, std::string *line) {
133 std::vector<std::string>::const_iterator line_iterator;
134 for (line_iterator = lines.begin(); line_iterator != lines.end();
135 ++line_iterator) {
136 if (line_iterator->find(prefix) == 0) {
137 *line = *line_iterator;
138 return true;
139 }
140 }
141 return false;
142}
143
144bool UserCollector::GetIdFromStatus(
145 const char *prefix, IdKind kind,
146 const std::vector<std::string> &status_lines, int *id) {
Ken Mixter777484c2010-07-23 16:22:44 -0700147 // From fs/proc/array.c:task_state(), this file contains:
148 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n
Ben Chanf13bb582012-01-06 08:22:07 -0800149 std::string id_line;
150 if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700151 return false;
152 }
Ben Chanf13bb582012-01-06 08:22:07 -0800153 std::string id_substring = id_line.substr(strlen(prefix), std::string::npos);
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800154 std::vector<std::string> ids = base::SplitString(
155 id_substring, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
Ken Mixter777484c2010-07-23 16:22:44 -0700156 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
157 return false;
158 }
159 const char *number = ids[kind].c_str();
Ben Chan262d7982014-09-18 08:05:20 -0700160 char *end_number = nullptr;
Ken Mixter777484c2010-07-23 16:22:44 -0700161 *id = strtol(number, &end_number, 10);
Ben Chanf13bb582012-01-06 08:22:07 -0800162 if (*end_number != '\0') {
Ken Mixter777484c2010-07-23 16:22:44 -0700163 return false;
Ben Chanf13bb582012-01-06 08:22:07 -0800164 }
165 return true;
166}
167
168bool UserCollector::GetStateFromStatus(
169 const std::vector<std::string> &status_lines, std::string *state) {
170 std::string state_line;
171 if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) {
172 return false;
173 }
174 *state = state_line.substr(strlen(kStatePrefix), std::string::npos);
Ken Mixter777484c2010-07-23 16:22:44 -0700175 return true;
176}
177
Ken Mixter207694d2010-10-28 15:42:37 -0700178void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
Ben Chan6e709a12012-02-29 12:10:44 -0800179 ErrorType error_type,
Ken Mixter207694d2010-10-28 15:42:37 -0700180 const std::string &exec) {
181 FilePath crash_path;
Ken Mixtera3249322011-03-03 08:47:38 -0800182 LOG(INFO) << "Writing conversion problems as separate crash report.";
Ben Chan262d7982014-09-18 08:05:20 -0700183 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800184 LOG(ERROR) << "Could not even get log directory; out of space?";
Ken Mixter207694d2010-10-28 15:42:37 -0700185 return;
186 }
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200187 AddCrashMetaData("sig", kCollectionErrorSignature);
188 AddCrashMetaData("error_type", GetErrorTypeSignature(error_type));
Ben Chan262d7982014-09-18 08:05:20 -0700189 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Alex Vakulenko74dc6242015-10-13 09:23:34 -0700190 std::string error_log = brillo::GetLog();
Ken Mixter1b8fe012011-01-25 13:33:05 -0800191 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
Simon Queacc79382012-05-04 18:10:09 -0700192 if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800193 diag_log_path)) {
194 // We load the contents of diag_log into memory and append it to
195 // the error log. We cannot just append to files because we need
196 // to always create new files to prevent attack.
197 std::string diag_log_contents;
Mike Frysingera557c112014-02-05 22:55:39 -0500198 base::ReadFileToString(diag_log_path, &diag_log_contents);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800199 error_log.append(diag_log_contents);
Mike Frysingera557c112014-02-05 22:55:39 -0500200 base::DeleteFile(diag_log_path, false);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800201 }
Ken Mixter207694d2010-10-28 15:42:37 -0700202 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
203 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
Ben Chanf30c6412014-05-22 23:09:01 -0700204 // We must use WriteNewFile instead of base::WriteFile as we do
Ken Mixter9b346472010-11-07 13:45:45 -0800205 // not want to write with root access to a symlink that an attacker
206 // might have created.
Thiemo Nagel8fce2852014-05-09 14:48:45 +0200207 if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) {
208 LOG(ERROR) << "Error writing new file " << log_path.value();
209 return;
210 }
Ken Mixter207694d2010-10-28 15:42:37 -0700211 WriteCrashMetaData(meta_path, exec, log_path.value());
212}
213
Ken Mixter777484c2010-07-23 16:22:44 -0700214bool UserCollector::CopyOffProcFiles(pid_t pid,
215 const FilePath &container_dir) {
Mike Frysingera557c112014-02-05 22:55:39 -0500216 if (!base::CreateDirectory(container_dir)) {
Steve Fung6db7cd72015-10-06 16:43:56 -0700217 PLOG(ERROR) << "Could not create " << container_dir.value();
218 return false;
219 }
220 int dir_mask = base::FILE_PERMISSION_READ_BY_USER
221 | base::FILE_PERMISSION_WRITE_BY_USER
222 | base::FILE_PERMISSION_EXECUTE_BY_USER
223 | base::FILE_PERMISSION_READ_BY_GROUP
224 | base::FILE_PERMISSION_WRITE_BY_GROUP;
225 if (!base::SetPosixFilePermissions(container_dir,
226 base::FILE_PERMISSION_MASK & dir_mask)) {
227 PLOG(ERROR) << "Could not set permissions for " << container_dir.value()
228 << " to " << std::oct
229 << (base::FILE_PERMISSION_MASK & dir_mask);
Ken Mixter777484c2010-07-23 16:22:44 -0700230 return false;
231 }
232 FilePath process_path = GetProcessPath(pid);
Mike Frysingera557c112014-02-05 22:55:39 -0500233 if (!base::PathExists(process_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800234 LOG(ERROR) << "Path " << process_path.value() << " does not exist";
Ken Mixter777484c2010-07-23 16:22:44 -0700235 return false;
236 }
237 static const char *proc_files[] = {
238 "auxv",
239 "cmdline",
240 "environ",
241 "maps",
242 "status"
243 };
244 for (unsigned i = 0; i < arraysize(proc_files); ++i) {
Mike Frysingera557c112014-02-05 22:55:39 -0500245 if (!base::CopyFile(process_path.Append(proc_files[i]),
246 container_dir.Append(proc_files[i]))) {
Ken Mixtera3249322011-03-03 08:47:38 -0800247 LOG(ERROR) << "Could not copy " << proc_files[i] << " file";
Ken Mixter777484c2010-07-23 16:22:44 -0700248 return false;
249 }
250 }
Ben Chanec7d7832012-01-09 10:29:58 -0800251 return true;
Ben Chanf13bb582012-01-06 08:22:07 -0800252}
253
Ben Chan6e709a12012-02-29 12:10:44 -0800254bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const {
Ben Chanf13bb582012-01-06 08:22:07 -0800255 // Check if the maps file is empty, which could be due to the crashed
256 // process being reaped by the kernel before finishing a core dump.
Ben Chanf84ea212014-08-06 17:27:48 -0700257 int64_t file_size = 0;
Mike Frysingera557c112014-02-05 22:55:39 -0500258 if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) {
Ben Chanf13bb582012-01-06 08:22:07 -0800259 LOG(ERROR) << "Could not get the size of maps file";
260 return false;
261 }
262 if (file_size == 0) {
263 LOG(ERROR) << "maps file is empty";
264 return false;
265 }
Ken Mixter777484c2010-07-23 16:22:44 -0700266 return true;
267}
268
Ben Chan6e709a12012-02-29 12:10:44 -0800269UserCollector::ErrorType UserCollector::ValidateCoreFile(
270 const FilePath &core_path) const {
271 int fd = HANDLE_EINTR(open(core_path.value().c_str(), O_RDONLY));
272 if (fd < 0) {
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700273 PLOG(ERROR) << "Could not open core file " << core_path.value();
Ben Chan6e709a12012-02-29 12:10:44 -0800274 return kErrorInvalidCoreFile;
275 }
276
277 char e_ident[EI_NIDENT];
Mike Frysingera557c112014-02-05 22:55:39 -0500278 bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident));
Mike Frysingerf1a50142014-05-14 16:05:09 -0400279 IGNORE_EINTR(close(fd));
Ben Chan6e709a12012-02-29 12:10:44 -0800280 if (!read_ok) {
281 LOG(ERROR) << "Could not read header of core file";
282 return kErrorInvalidCoreFile;
283 }
284
285 if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
286 e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
287 LOG(ERROR) << "Invalid core file";
288 return kErrorInvalidCoreFile;
289 }
290
291#if __WORDSIZE == 64
292 // TODO(benchan, mkrebs): Remove this check once core2md can
293 // handles both 32-bit and 64-bit ELF on a 64-bit platform.
294 if (e_ident[EI_CLASS] == ELFCLASS32) {
295 LOG(ERROR) << "Conversion of 32-bit core file on 64-bit platform is "
296 << "currently not supported";
297 return kErrorUnsupported32BitCoreFile;
298 }
299#endif
300
301 return kErrorNone;
302}
303
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700304bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
Ken Mixter207694d2010-10-28 15:42:37 -0700305 FilePath *crash_file_path,
306 bool *out_of_capacity) {
Ken Mixter777484c2010-07-23 16:22:44 -0700307 FilePath process_path = GetProcessPath(pid);
308 std::string status;
Steve Fungd6169a22014-08-11 15:52:23 -0700309 if (directory_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800310 LOG(ERROR) << "Purposefully failing to create spool directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700311 return false;
312 }
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700313
314 uid_t uid;
Mike Frysingera557c112014-02-05 22:55:39 -0500315 if (base::ReadFileToString(process_path.Append("status"), &status)) {
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800316 std::vector<std::string> status_lines = base::SplitString(
317 status, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700318
319 std::string process_state;
320 if (!GetStateFromStatus(status_lines, &process_state)) {
321 LOG(ERROR) << "Could not find process state in status file";
322 return false;
323 }
324 LOG(INFO) << "State of crashed process [" << pid << "]: " << process_state;
325
326 // Get effective UID of crashing process.
327 int id;
328 if (!GetIdFromStatus(kUserId, kIdEffective, status_lines, &id)) {
329 LOG(ERROR) << "Could not find euid in status file";
330 return false;
331 }
332 uid = id;
333 } else if (supplied_ruid != kUnknownUid) {
334 LOG(INFO) << "Using supplied UID " << supplied_ruid
335 << " for crashed process [" << pid
336 << "] due to error reading status file";
337 uid = supplied_ruid;
338 } else {
339 LOG(ERROR) << "Could not read status file and kernel did not supply UID";
Ken Mixtera3249322011-03-03 08:47:38 -0800340 LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: "
Mike Frysingera557c112014-02-05 22:55:39 -0500341 << base::DirectoryExists(process_path);
Ken Mixter777484c2010-07-23 16:22:44 -0700342 return false;
343 }
Ben Chanf13bb582012-01-06 08:22:07 -0800344
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700345 if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800346 LOG(ERROR) << "Could not create crash directory";
Ken Mixter207694d2010-10-28 15:42:37 -0700347 return false;
348 }
349 return true;
Ken Mixter777484c2010-07-23 16:22:44 -0700350}
351
352bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
353 // Copy off all stdin to a core file.
Steve Fungab2ac7d2015-08-14 17:58:05 -0700354 FilePath stdin_path("/proc/self/fd/0");
Mike Frysingera557c112014-02-05 22:55:39 -0500355 if (base::CopyFile(stdin_path, core_path)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700356 return true;
357 }
358
Chris Masoneb3fe6c32013-05-31 09:37:33 -0700359 PLOG(ERROR) << "Could not write core file";
Ken Mixter777484c2010-07-23 16:22:44 -0700360 // If the file system was full, make sure we remove any remnants.
Mike Frysingera557c112014-02-05 22:55:39 -0500361 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700362 return false;
363}
364
Ken Mixter207694d2010-10-28 15:42:37 -0700365bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
366 const FilePath &procfs_directory,
367 const FilePath &minidump_path,
368 const FilePath &temp_directory) {
Ken Mixter777484c2010-07-23 16:22:44 -0700369 FilePath output_path = temp_directory.Append("output");
Alex Vakulenko74dc6242015-10-13 09:23:34 -0700370 brillo::ProcessImpl core2md;
Ken Mixtera3249322011-03-03 08:47:38 -0800371 core2md.RedirectOutput(output_path.value());
372 core2md.AddArg(kCoreToMinidumpConverterPath);
373 core2md.AddArg(core_path.value());
374 core2md.AddArg(procfs_directory.value());
Ken Mixter2953c3a2010-10-18 14:42:20 -0700375
Steve Fungd6169a22014-08-11 15:52:23 -0700376 if (!core2md_failure_) {
Ken Mixtera3249322011-03-03 08:47:38 -0800377 core2md.AddArg(minidump_path.value());
378 } else {
Ken Mixter207694d2010-10-28 15:42:37 -0700379 // To test how core2md errors are propagaged, cause an error
380 // by forgetting a required argument.
Ken Mixter207694d2010-10-28 15:42:37 -0700381 }
382
Ken Mixtera3249322011-03-03 08:47:38 -0800383 int errorlevel = core2md.Run();
Ken Mixter777484c2010-07-23 16:22:44 -0700384
385 std::string output;
Mike Frysingera557c112014-02-05 22:55:39 -0500386 base::ReadFileToString(output_path, &output);
Ken Mixter777484c2010-07-23 16:22:44 -0700387 if (errorlevel != 0) {
Ken Mixtera3249322011-03-03 08:47:38 -0800388 LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath
389 << " [result=" << errorlevel << "]: " << output;
Ken Mixter777484c2010-07-23 16:22:44 -0700390 return false;
391 }
392
Mike Frysingera557c112014-02-05 22:55:39 -0500393 if (!base::PathExists(minidump_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800394 LOG(ERROR) << "Minidump file " << minidump_path.value()
395 << " was not created";
Ken Mixter777484c2010-07-23 16:22:44 -0700396 return false;
397 }
398 return true;
399}
400
Ben Chan6e709a12012-02-29 12:10:44 -0800401UserCollector::ErrorType UserCollector::ConvertCoreToMinidump(
402 pid_t pid,
403 const FilePath &container_dir,
404 const FilePath &core_path,
405 const FilePath &minidump_path) {
Ben Chanec7d7832012-01-09 10:29:58 -0800406 // If proc files are unuable, we continue to read the core file from stdin,
407 // but only skip the core-to-minidump conversion, so that we may still use
408 // the core file for debugging.
409 bool proc_files_usable =
410 CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir);
411
Steve Fung6db7cd72015-10-06 16:43:56 -0700412 // Switch back to the original UID/GID.
413 gid_t rgid, egid, sgid;
414 if (getresgid(&rgid, &egid, &sgid) != 0) {
415 PLOG(FATAL) << "Unable to read saved gid";
416 }
417 if (setresgid(sgid, sgid, -1) != 0) {
418 PLOG(FATAL) << "Unable to set real group ID back to saved gid";
419 } else {
420 if (getresgid(&rgid, &egid, &sgid) != 0) {
421 // If the groups cannot be read at this point, the rgid variable will
422 // contain the previously read group ID from before changing it. This
423 // will cause the chown call below to set the incorrect group for
424 // non-root crashes. But do not treat this as a fatal error, so that
425 // the rest of the collection will continue for potential manual
426 // collection by a developer.
427 PLOG(ERROR) << "Unable to read real group ID after setting it";
428 }
429 }
430
431 uid_t ruid, euid, suid;
432 if (getresuid(&ruid, &euid, &suid) != 0) {
433 PLOG(FATAL) << "Unable to read saved uid";
434 }
435 if (setresuid(suid, suid, -1) != 0) {
436 PLOG(FATAL) << "Unable to set real user ID back to saved uid";
437 } else {
438 if (getresuid(&ruid, &euid, &suid) != 0) {
439 // If the user ID cannot be read at this point, the ruid variable will
440 // contain the previously read user ID from before changing it. This
441 // will cause the chown call below to set the incorrect user for
442 // non-root crashes. But do not treat this as a fatal error, so that
443 // the rest of the collection will continue for potential manual
444 // collection by a developer.
445 PLOG(ERROR) << "Unable to read real user ID after setting it";
446 }
447 }
448
Ben Chanec7d7832012-01-09 10:29:58 -0800449 if (!CopyStdinToCoreFile(core_path)) {
Ben Chan6e709a12012-02-29 12:10:44 -0800450 return kErrorReadCoreData;
Ken Mixter777484c2010-07-23 16:22:44 -0700451 }
452
Ben Chanec7d7832012-01-09 10:29:58 -0800453 if (!proc_files_usable) {
454 LOG(INFO) << "Skipped converting core file to minidump due to "
455 << "unusable proc files";
Ben Chan6e709a12012-02-29 12:10:44 -0800456 return kErrorUnusableProcFiles;
Ken Mixter777484c2010-07-23 16:22:44 -0700457 }
458
Ben Chan6e709a12012-02-29 12:10:44 -0800459 ErrorType error = ValidateCoreFile(core_path);
460 if (error != kErrorNone) {
461 return error;
Ken Mixter777484c2010-07-23 16:22:44 -0700462 }
463
Steve Fung6db7cd72015-10-06 16:43:56 -0700464 // Chown the temp container directory back to the original user/group that
465 // crash_reporter is run as, so that additional files can be written to
466 // the temp folder.
467 if (chown(container_dir.value().c_str(), ruid, rgid) < 0) {
468 PLOG(ERROR) << "Could not set owner for " << container_dir.value();
469 }
470
Ben Chan6e709a12012-02-29 12:10:44 -0800471 if (!RunCoreToMinidump(core_path,
472 container_dir, // procfs directory
473 minidump_path,
474 container_dir)) { // temporary directory
475 return kErrorCore2MinidumpConversion;
476 }
477
478 LOG(INFO) << "Stored minidump to " << minidump_path.value();
479 return kErrorNone;
Ken Mixter207694d2010-10-28 15:42:37 -0700480}
481
Ben Chan6e709a12012-02-29 12:10:44 -0800482UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash(
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700483 pid_t pid, const std::string &exec, uid_t supplied_ruid,
484 bool *out_of_capacity) {
Ken Mixter207694d2010-10-28 15:42:37 -0700485 FilePath crash_path;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700486 if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path,
487 out_of_capacity)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800488 LOG(ERROR) << "Unable to find/create process-specific crash path";
Ben Chan6e709a12012-02-29 12:10:44 -0800489 return kErrorSystemIssue;
Ken Mixter207694d2010-10-28 15:42:37 -0700490 }
491
Ben Chan294d5d12012-01-04 20:40:15 -0800492 // Directory like /tmp/crash_reporter/1234 which contains the
Ken Mixter207694d2010-10-28 15:42:37 -0700493 // procfs entries and other temporary files used during conversion.
Steve Fungab2ac7d2015-08-14 17:58:05 -0700494 FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800495 // Delete a pre-existing directory from crash reporter that may have
496 // been left around for diagnostics from a failed conversion attempt.
497 // If we don't, existing files can cause forking to fail.
Mike Frysingera557c112014-02-05 22:55:39 -0500498 base::DeleteFile(container_dir, true);
Ben Chan262d7982014-09-18 08:05:20 -0700499 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
Ken Mixter207694d2010-10-28 15:42:37 -0700500 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
501 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
502 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
Ken Mixterc49dbd42010-12-14 17:44:11 -0800503 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
504
Simon Queacc79382012-05-04 18:10:09 -0700505 if (GetLogContents(FilePath(log_config_path_), exec, log_path))
Ken Mixterc49dbd42010-12-14 17:44:11 -0800506 AddCrashMetaData("log", log_path.value());
Ken Mixter207694d2010-10-28 15:42:37 -0700507
Alex Vakulenko74dc6242015-10-13 09:23:34 -0700508 brillo::OsReleaseReader reader;
Steve Fungaa265b62015-10-11 04:59:14 -0700509 reader.Load();
Steve Fung72e3c822015-10-13 14:44:37 -0700510 std::string value = "undefined";
511 if (!reader.GetString(kBdkVersionKey, &value)) {
Steve Fungaa265b62015-10-11 04:59:14 -0700512 LOG(ERROR) << "Could not read " << kBdkVersionKey
513 << " from /etc/os-release.d/";
514 }
Steve Fung72e3c822015-10-13 14:44:37 -0700515 AddCrashMetaData(kBdkVersionKey, value);
516
517 value = "undefined";
518 if (!reader.GetString(kProductIDKey, &value)) {
519 LOG(ERROR) << "Could not read " << kProductIDKey
520 << " from /etc/os-release.d/";
521 }
522 AddCrashMetaData(kProductIDKey, value);
523
524 value = "undefined";
525 if (!reader.GetString(kProductVersionKey, &value)) {
526 LOG(ERROR) << "Could not read " << kProductVersionKey
527 << " from /etc/os-release.d/";
528 }
529 AddCrashMetaData(kProductVersionKey, value);
Steve Fungaa265b62015-10-11 04:59:14 -0700530
Ben Chan6e709a12012-02-29 12:10:44 -0800531 ErrorType error_type =
532 ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
533 if (error_type != kErrorNone) {
Ken Mixtera3249322011-03-03 08:47:38 -0800534 LOG(INFO) << "Leaving core file at " << core_path.value()
535 << " due to conversion error";
Ben Chan6e709a12012-02-29 12:10:44 -0800536 return error_type;
Ken Mixter207694d2010-10-28 15:42:37 -0700537 }
538
539 // Here we commit to sending this file. We must not return false
540 // after this point or we will generate a log report as well as a
541 // crash report.
542 WriteCrashMetaData(meta_path,
543 exec,
544 minidump_path.value());
545
Michael Krebs538ecbf2011-07-27 14:13:22 -0700546 if (!IsDeveloperImage()) {
Mike Frysingera557c112014-02-05 22:55:39 -0500547 base::DeleteFile(core_path, false);
Ken Mixter777484c2010-07-23 16:22:44 -0700548 } else {
Ken Mixtera3249322011-03-03 08:47:38 -0800549 LOG(INFO) << "Leaving core file at " << core_path.value()
550 << " due to developer image";
Ken Mixter777484c2010-07-23 16:22:44 -0700551 }
552
Mike Frysingera557c112014-02-05 22:55:39 -0500553 base::DeleteFile(container_dir, true);
Ben Chan6e709a12012-02-29 12:10:44 -0800554 return kErrorNone;
Ken Mixter777484c2010-07-23 16:22:44 -0700555}
556
Ken Mixter1b8fe012011-01-25 13:33:05 -0800557bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700558 pid_t *pid, int *signal, uid_t *uid,
Steve Fung773fd3c2015-10-09 17:01:35 -0700559 gid_t *gid,
Ken Mixter1b8fe012011-01-25 13:33:05 -0800560 std::string *kernel_supplied_name) {
Steve Fung773fd3c2015-10-09 17:01:35 -0700561 pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(\\d+):(.*)");
562 if (re.FullMatch(crash_attributes, pid, signal, uid, gid,
563 kernel_supplied_name))
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700564 return true;
565
566 LOG(INFO) << "Falling back to parsing crash attributes '"
Steve Fung773fd3c2015-10-09 17:01:35 -0700567 << crash_attributes << "' without UID and GID";
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700568 pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)");
569 *uid = kUnknownUid;
Steve Fung773fd3c2015-10-09 17:01:35 -0700570 *gid = kUnknownGid;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700571 return re_without_uid.FullMatch(crash_attributes, pid, signal,
572 kernel_supplied_name);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800573}
574
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700575bool UserCollector::ShouldDump(bool has_owner_consent,
576 bool is_developer,
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700577 std::string *reason) {
578 reason->clear();
579
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700580 // For developer builds, we always want to keep the crash reports unless
581 // we're testing the crash facilities themselves. This overrides
582 // feedback. Crash sending still obeys consent.
Michael Krebs538ecbf2011-07-27 14:13:22 -0700583 if (is_developer) {
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700584 *reason = "developer build - not testing - always dumping";
585 return true;
586 }
587
588 if (!has_owner_consent) {
589 *reason = "ignoring - no consent";
590 return false;
591 }
592
593 *reason = "handling";
594 return true;
595}
596
Ken Mixter1b8fe012011-01-25 13:33:05 -0800597bool UserCollector::HandleCrash(const std::string &crash_attributes,
598 const char *force_exec) {
Chris Sosae4a86032010-06-16 17:08:34 -0700599 CHECK(initialized_);
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700600 pid_t pid = 0;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800601 int signal = 0;
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700602 uid_t supplied_ruid = kUnknownUid;
Steve Fung773fd3c2015-10-09 17:01:35 -0700603 gid_t supplied_rgid = kUnknownGid;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800604 std::string kernel_supplied_name;
605
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700606 if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid,
Steve Fung773fd3c2015-10-09 17:01:35 -0700607 &supplied_rgid, &kernel_supplied_name)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800608 LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800609 return false;
610 }
611
Steve Fung6db7cd72015-10-06 16:43:56 -0700612 // Switch to the group and user that ran the crashing binary in order to
613 // access their /proc files. Do not set suid/sgid, so that we can switch
614 // back after copying the necessary files.
Steve Fung773fd3c2015-10-09 17:01:35 -0700615 if (setresgid(supplied_rgid, supplied_rgid, -1) != 0) {
Steve Fung6db7cd72015-10-06 16:43:56 -0700616 PLOG(FATAL) << "Unable to set real group ID to access process files";
617 }
618 if (setresuid(supplied_ruid, supplied_ruid, -1) != 0) {
619 PLOG(FATAL) << "Unable to set real user ID to access process files";
620 }
621
Ken Mixter777484c2010-07-23 16:22:44 -0700622 std::string exec;
623 if (force_exec) {
624 exec.assign(force_exec);
625 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800626 // If we cannot find the exec name, use the kernel supplied name.
627 // We don't always use the kernel's since it truncates the name to
628 // 16 characters.
629 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700630 }
Ken Mixterc6a58e02010-11-01 18:05:30 -0700631
632 // Allow us to test the crash reporting mechanism successfully even if
633 // other parts of the system crash.
Steve Fungd6169a22014-08-11 15:52:23 -0700634 if (!filter_in_.empty() &&
635 (filter_in_ == "none" ||
636 filter_in_ != exec)) {
Ken Mixterc6a58e02010-11-01 18:05:30 -0700637 // We use a different format message to make it more obvious in tests
638 // which crashes are test generated and which are real.
Ken Mixtera3249322011-03-03 08:47:38 -0800639 LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while "
Steve Fungd6169a22014-08-11 15:52:23 -0700640 << "filter_in=" << filter_in_ << ".";
Ken Mixterc6a58e02010-11-01 18:05:30 -0700641 return true;
642 }
643
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700644 std::string reason;
645 bool dump = ShouldDump(is_feedback_allowed_function_(),
Michael Krebs538ecbf2011-07-27 14:13:22 -0700646 IsDeveloperImage(),
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700647 &reason);
Ken Mixter2105b492010-11-09 16:14:38 -0800648
Ken Mixtera3249322011-03-03 08:47:38 -0800649 LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700650 << "] sig " << signal << ", user " << supplied_ruid
651 << " (" << reason << ")";
Chris Sosae4a86032010-06-16 17:08:34 -0700652
Ken Mixter5d3a1a22011-03-16 12:47:20 -0700653 if (dump) {
Chris Sosae4a86032010-06-16 17:08:34 -0700654 count_crash_function_();
Ken Mixter777484c2010-07-23 16:22:44 -0700655
Ken Mixter03403162010-08-18 15:23:16 -0700656 if (generate_diagnostics_) {
Ken Mixter207694d2010-10-28 15:42:37 -0700657 bool out_of_capacity = false;
Ben Chan6e709a12012-02-29 12:10:44 -0800658 ErrorType error_type =
Michael Krebs1c57e9e2012-09-25 18:03:13 -0700659 ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity);
Ben Chan6e709a12012-02-29 12:10:44 -0800660 if (error_type != kErrorNone) {
Ken Mixter207694d2010-10-28 15:42:37 -0700661 if (!out_of_capacity)
Ben Chan6e709a12012-02-29 12:10:44 -0800662 EnqueueCollectionErrorLog(pid, error_type, exec);
Ken Mixter207694d2010-10-28 15:42:37 -0700663 return false;
664 }
Ken Mixter03403162010-08-18 15:23:16 -0700665 }
Ken Mixter777484c2010-07-23 16:22:44 -0700666 }
Ken Mixter207694d2010-10-28 15:42:37 -0700667
Ken Mixter777484c2010-07-23 16:22:44 -0700668 return true;
Chris Sosae4a86032010-06-16 17:08:34 -0700669}