Steve Fung | 6c34c25 | 2015-08-20 00:27:30 -0700 | [diff] [blame] | 1 | /* |
| 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 Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 16 | |
Steve Fung | 129bea5 | 2015-07-23 13:11:15 -0700 | [diff] [blame] | 17 | #include "user_collector.h" |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 18 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 19 | #include <elf.h> |
| 20 | #include <fcntl.h> |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 21 | #include <grp.h> // For struct group. |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 22 | #include <pcrecpp.h> |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 23 | #include <pwd.h> // For struct passwd. |
Ben Chan | f84ea21 | 2014-08-06 17:27:48 -0700 | [diff] [blame] | 24 | #include <stdint.h> |
Steve Fung | 8bafb3d | 2015-08-07 13:22:46 -0700 | [diff] [blame] | 25 | #include <sys/cdefs.h> // For __WORDSIZE |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 26 | #include <sys/fsuid.h> |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 27 | #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. |
Steve Fung | b440e50 | 2015-08-21 02:12:34 -0700 | [diff] [blame] | 28 | #include <unistd.h> // For setgroups |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 29 | |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 30 | #include <iostream> // For std::oct |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 31 | #include <string> |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 32 | #include <vector> |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 33 | |
Ben Chan | ab6cc90 | 2014-09-05 08:21:06 -0700 | [diff] [blame] | 34 | #include <base/files/file_util.h> |
Ben Chan | 7e77690 | 2014-06-18 13:19:51 -0700 | [diff] [blame] | 35 | #include <base/logging.h> |
| 36 | #include <base/posix/eintr_wrapper.h> |
Ben Chan | 7e77690 | 2014-06-18 13:19:51 -0700 | [diff] [blame] | 37 | #include <base/strings/string_split.h> |
| 38 | #include <base/strings/string_util.h> |
| 39 | #include <base/strings/stringprintf.h> |
Alex Vakulenko | 74dc624 | 2015-10-13 09:23:34 -0700 | [diff] [blame] | 40 | #include <brillo/process.h> |
| 41 | #include <brillo/syslog_logging.h> |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 42 | #include <cutils/properties.h> |
Steve Fung | b440e50 | 2015-08-21 02:12:34 -0700 | [diff] [blame] | 43 | #include <private/android_filesystem_config.h> |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 44 | |
| 45 | static const char kCollectionErrorSignature[] = |
| 46 | "crash_reporter-user-collection"; |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 47 | static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled"; |
| 48 | static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 49 | |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 50 | static const char kStatePrefix[] = "State:\t"; |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 51 | |
Steve Fung | da98133 | 2015-08-23 17:18:23 -0700 | [diff] [blame] | 52 | static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp"; |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 53 | |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 54 | // Define an otherwise invalid value that represents an unknown UID and GID. |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 55 | static const uid_t kUnknownUid = -1; |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 56 | static const gid_t kUnknownGid = -1; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 57 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 58 | const char *UserCollector::kUserId = "Uid:\t"; |
| 59 | const char *UserCollector::kGroupId = "Gid:\t"; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 60 | |
Steve Fung | 4818011 | 2015-09-30 16:27:56 -0700 | [diff] [blame] | 61 | |
Simon Que | 9f90aca | 2013-02-19 17:19:52 -0800 | [diff] [blame] | 62 | using base::FilePath; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 63 | using base::StringPrintf; |
Simon Que | 9f90aca | 2013-02-19 17:19:52 -0800 | [diff] [blame] | 64 | |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 65 | UserCollector::UserCollector() |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 66 | : generate_diagnostics_(false), |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 67 | initialized_(false) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | void UserCollector::Initialize( |
| 71 | UserCollector::CountCrashFunction count_crash_function, |
| 72 | const std::string &our_path, |
| 73 | UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 74 | bool generate_diagnostics, |
| 75 | bool core2md_failure, |
| 76 | bool directory_failure, |
| 77 | const std::string &filter_in) { |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 78 | CrashCollector::Initialize(count_crash_function, |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 79 | is_feedback_allowed_function); |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 80 | our_path_ = our_path; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 81 | initialized_ = true; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 82 | generate_diagnostics_ = generate_diagnostics; |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 83 | core2md_failure_ = core2md_failure; |
| 84 | directory_failure_ = directory_failure; |
| 85 | filter_in_ = filter_in; |
Steve Fung | b440e50 | 2015-08-21 02:12:34 -0700 | [diff] [blame] | 86 | |
Steve Fung | a76ba85 | 2015-11-11 17:50:37 -0800 | [diff] [blame] | 87 | gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS, AID_READPROC }; |
Steve Fung | b440e50 | 2015-08-21 02:12:34 -0700 | [diff] [blame] | 88 | if (setgroups(arraysize(groups), groups) != 0) { |
Steve Fung | a76ba85 | 2015-11-11 17:50:37 -0800 | [diff] [blame] | 89 | PLOG(FATAL) << "Unable to set groups to root, system, dbus, and readproc"; |
Steve Fung | b440e50 | 2015-08-21 02:12:34 -0700 | [diff] [blame] | 90 | } |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | UserCollector::~UserCollector() { |
| 94 | } |
| 95 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 96 | std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const { |
| 97 | switch (error_type) { |
| 98 | case kErrorSystemIssue: |
| 99 | return "system-issue"; |
| 100 | case kErrorReadCoreData: |
| 101 | return "read-core-data"; |
| 102 | case kErrorUnusableProcFiles: |
| 103 | return "unusable-proc-files"; |
| 104 | case kErrorInvalidCoreFile: |
| 105 | return "invalid-core-file"; |
| 106 | case kErrorUnsupported32BitCoreFile: |
| 107 | return "unsupported-32bit-core-file"; |
| 108 | case kErrorCore2MinidumpConversion: |
| 109 | return "core2md-conversion"; |
| 110 | default: |
| 111 | return ""; |
| 112 | } |
| 113 | } |
| 114 | |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 115 | bool UserCollector::SetUpInternal(bool enabled) { |
| 116 | CHECK(initialized_); |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 117 | LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling"; |
| 118 | |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 119 | property_set(kCorePatternProperty, enabled ? "1" : "0"); |
| 120 | |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 121 | return true; |
| 122 | } |
| 123 | |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 124 | bool UserCollector::GetFirstLineWithPrefix( |
| 125 | const std::vector<std::string> &lines, |
| 126 | const char *prefix, std::string *line) { |
| 127 | std::vector<std::string>::const_iterator line_iterator; |
| 128 | for (line_iterator = lines.begin(); line_iterator != lines.end(); |
| 129 | ++line_iterator) { |
| 130 | if (line_iterator->find(prefix) == 0) { |
| 131 | *line = *line_iterator; |
| 132 | return true; |
| 133 | } |
| 134 | } |
| 135 | return false; |
| 136 | } |
| 137 | |
| 138 | bool UserCollector::GetIdFromStatus( |
| 139 | const char *prefix, IdKind kind, |
| 140 | const std::vector<std::string> &status_lines, int *id) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 141 | // From fs/proc/array.c:task_state(), this file contains: |
| 142 | // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 143 | std::string id_line; |
| 144 | if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 145 | return false; |
| 146 | } |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 147 | std::string id_substring = id_line.substr(strlen(prefix), std::string::npos); |
Alex Vakulenko | ea05ff9 | 2016-01-20 07:53:57 -0800 | [diff] [blame] | 148 | std::vector<std::string> ids = base::SplitString( |
| 149 | id_substring, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 150 | if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) { |
| 151 | return false; |
| 152 | } |
| 153 | const char *number = ids[kind].c_str(); |
Ben Chan | 262d798 | 2014-09-18 08:05:20 -0700 | [diff] [blame] | 154 | char *end_number = nullptr; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 155 | *id = strtol(number, &end_number, 10); |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 156 | if (*end_number != '\0') { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 157 | return false; |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 158 | } |
| 159 | return true; |
| 160 | } |
| 161 | |
| 162 | bool UserCollector::GetStateFromStatus( |
| 163 | const std::vector<std::string> &status_lines, std::string *state) { |
| 164 | std::string state_line; |
| 165 | if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) { |
| 166 | return false; |
| 167 | } |
| 168 | *state = state_line.substr(strlen(kStatePrefix), std::string::npos); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 169 | return true; |
| 170 | } |
| 171 | |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 172 | void UserCollector::EnqueueCollectionErrorLog(pid_t pid, |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 173 | ErrorType error_type, |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 174 | const std::string &exec) { |
| 175 | FilePath crash_path; |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 176 | LOG(INFO) << "Writing conversion problems as separate crash report."; |
Ben Chan | 262d798 | 2014-09-18 08:05:20 -0700 | [diff] [blame] | 177 | if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 178 | LOG(ERROR) << "Could not even get log directory; out of space?"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 179 | return; |
| 180 | } |
Thiemo Nagel | 8fce285 | 2014-05-09 14:48:45 +0200 | [diff] [blame] | 181 | AddCrashMetaData("sig", kCollectionErrorSignature); |
| 182 | AddCrashMetaData("error_type", GetErrorTypeSignature(error_type)); |
Ben Chan | 262d798 | 2014-09-18 08:05:20 -0700 | [diff] [blame] | 183 | std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid); |
Alex Vakulenko | 74dc624 | 2015-10-13 09:23:34 -0700 | [diff] [blame] | 184 | std::string error_log = brillo::GetLog(); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 185 | FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog"); |
Simon Que | acc7938 | 2012-05-04 18:10:09 -0700 | [diff] [blame] | 186 | if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature, |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 187 | diag_log_path)) { |
| 188 | // We load the contents of diag_log into memory and append it to |
| 189 | // the error log. We cannot just append to files because we need |
| 190 | // to always create new files to prevent attack. |
| 191 | std::string diag_log_contents; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 192 | base::ReadFileToString(diag_log_path, &diag_log_contents); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 193 | error_log.append(diag_log_contents); |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 194 | base::DeleteFile(diag_log_path, false); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 195 | } |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 196 | FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); |
| 197 | FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
Ben Chan | f30c641 | 2014-05-22 23:09:01 -0700 | [diff] [blame] | 198 | // We must use WriteNewFile instead of base::WriteFile as we do |
Ken Mixter | 9b34647 | 2010-11-07 13:45:45 -0800 | [diff] [blame] | 199 | // not want to write with root access to a symlink that an attacker |
| 200 | // might have created. |
Thiemo Nagel | 8fce285 | 2014-05-09 14:48:45 +0200 | [diff] [blame] | 201 | if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) { |
| 202 | LOG(ERROR) << "Error writing new file " << log_path.value(); |
| 203 | return; |
| 204 | } |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 205 | WriteCrashMetaData(meta_path, exec, log_path.value()); |
| 206 | } |
| 207 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 208 | bool UserCollector::CopyOffProcFiles(pid_t pid, |
| 209 | const FilePath &container_dir) { |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 210 | if (!base::CreateDirectory(container_dir)) { |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 211 | PLOG(ERROR) << "Could not create " << container_dir.value(); |
| 212 | return false; |
| 213 | } |
| 214 | int dir_mask = base::FILE_PERMISSION_READ_BY_USER |
| 215 | | base::FILE_PERMISSION_WRITE_BY_USER |
| 216 | | base::FILE_PERMISSION_EXECUTE_BY_USER |
| 217 | | base::FILE_PERMISSION_READ_BY_GROUP |
| 218 | | base::FILE_PERMISSION_WRITE_BY_GROUP; |
| 219 | if (!base::SetPosixFilePermissions(container_dir, |
| 220 | base::FILE_PERMISSION_MASK & dir_mask)) { |
| 221 | PLOG(ERROR) << "Could not set permissions for " << container_dir.value() |
| 222 | << " to " << std::oct |
| 223 | << (base::FILE_PERMISSION_MASK & dir_mask); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 224 | return false; |
| 225 | } |
| 226 | FilePath process_path = GetProcessPath(pid); |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 227 | if (!base::PathExists(process_path)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 228 | LOG(ERROR) << "Path " << process_path.value() << " does not exist"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 229 | 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 Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 239 | if (!base::CopyFile(process_path.Append(proc_files[i]), |
| 240 | container_dir.Append(proc_files[i]))) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 241 | LOG(ERROR) << "Could not copy " << proc_files[i] << " file"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 242 | return false; |
| 243 | } |
| 244 | } |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 245 | return true; |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 246 | } |
| 247 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 248 | bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const { |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 249 | // 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 Chan | f84ea21 | 2014-08-06 17:27:48 -0700 | [diff] [blame] | 251 | int64_t file_size = 0; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 252 | if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) { |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 253 | 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 Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 260 | return true; |
| 261 | } |
| 262 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 263 | UserCollector::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 Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 267 | PLOG(ERROR) << "Could not open core file " << core_path.value(); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 268 | return kErrorInvalidCoreFile; |
| 269 | } |
| 270 | |
| 271 | char e_ident[EI_NIDENT]; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 272 | bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident)); |
Mike Frysinger | f1a5014 | 2014-05-14 16:05:09 -0400 | [diff] [blame] | 273 | IGNORE_EINTR(close(fd)); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 274 | 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 Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 298 | bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid, |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 299 | FilePath *crash_file_path, |
| 300 | bool *out_of_capacity) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 301 | FilePath process_path = GetProcessPath(pid); |
| 302 | std::string status; |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 303 | if (directory_failure_) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 304 | LOG(ERROR) << "Purposefully failing to create spool directory"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 305 | return false; |
| 306 | } |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 307 | |
| 308 | uid_t uid; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 309 | if (base::ReadFileToString(process_path.Append("status"), &status)) { |
Alex Vakulenko | ea05ff9 | 2016-01-20 07:53:57 -0800 | [diff] [blame] | 310 | std::vector<std::string> status_lines = base::SplitString( |
| 311 | status, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 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 Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 334 | LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: " |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 335 | << base::DirectoryExists(process_path); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 336 | return false; |
| 337 | } |
Ben Chan | f13bb58 | 2012-01-06 08:22:07 -0800 | [diff] [blame] | 338 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 339 | if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 340 | LOG(ERROR) << "Could not create crash directory"; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 341 | return false; |
| 342 | } |
| 343 | return true; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 344 | } |
| 345 | |
| 346 | bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { |
| 347 | // Copy off all stdin to a core file. |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 348 | FilePath stdin_path("/proc/self/fd/0"); |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 349 | if (base::CopyFile(stdin_path, core_path)) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 350 | return true; |
| 351 | } |
| 352 | |
Chris Masone | b3fe6c3 | 2013-05-31 09:37:33 -0700 | [diff] [blame] | 353 | PLOG(ERROR) << "Could not write core file"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 354 | // If the file system was full, make sure we remove any remnants. |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 355 | base::DeleteFile(core_path, false); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 356 | return false; |
| 357 | } |
| 358 | |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 359 | bool UserCollector::RunCoreToMinidump(const FilePath &core_path, |
| 360 | const FilePath &procfs_directory, |
| 361 | const FilePath &minidump_path, |
| 362 | const FilePath &temp_directory) { |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 363 | FilePath output_path = temp_directory.Append("output"); |
Alex Vakulenko | 74dc624 | 2015-10-13 09:23:34 -0700 | [diff] [blame] | 364 | brillo::ProcessImpl core2md; |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 365 | core2md.RedirectOutput(output_path.value()); |
| 366 | core2md.AddArg(kCoreToMinidumpConverterPath); |
| 367 | core2md.AddArg(core_path.value()); |
| 368 | core2md.AddArg(procfs_directory.value()); |
Ken Mixter | 2953c3a | 2010-10-18 14:42:20 -0700 | [diff] [blame] | 369 | |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 370 | if (!core2md_failure_) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 371 | core2md.AddArg(minidump_path.value()); |
| 372 | } else { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 373 | // To test how core2md errors are propagaged, cause an error |
| 374 | // by forgetting a required argument. |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 375 | } |
| 376 | |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 377 | int errorlevel = core2md.Run(); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 378 | |
| 379 | std::string output; |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 380 | base::ReadFileToString(output_path, &output); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 381 | if (errorlevel != 0) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 382 | LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath |
| 383 | << " [result=" << errorlevel << "]: " << output; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 384 | return false; |
| 385 | } |
| 386 | |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 387 | if (!base::PathExists(minidump_path)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 388 | LOG(ERROR) << "Minidump file " << minidump_path.value() |
| 389 | << " was not created"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 390 | return false; |
| 391 | } |
| 392 | return true; |
| 393 | } |
| 394 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 395 | UserCollector::ErrorType UserCollector::ConvertCoreToMinidump( |
| 396 | pid_t pid, |
| 397 | const FilePath &container_dir, |
| 398 | const FilePath &core_path, |
| 399 | const FilePath &minidump_path) { |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 400 | // 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 | |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 406 | // Switch back to the original UID/GID. |
| 407 | gid_t rgid, egid, sgid; |
| 408 | if (getresgid(&rgid, &egid, &sgid) != 0) { |
| 409 | PLOG(FATAL) << "Unable to read saved gid"; |
| 410 | } |
| 411 | if (setresgid(sgid, sgid, -1) != 0) { |
| 412 | PLOG(FATAL) << "Unable to set real group ID back to saved gid"; |
| 413 | } else { |
| 414 | if (getresgid(&rgid, &egid, &sgid) != 0) { |
| 415 | // If the groups cannot be read at this point, the rgid variable will |
| 416 | // contain the previously read group ID from before changing it. This |
| 417 | // will cause the chown call below to set the incorrect group for |
| 418 | // non-root crashes. But do not treat this as a fatal error, so that |
| 419 | // the rest of the collection will continue for potential manual |
| 420 | // collection by a developer. |
| 421 | PLOG(ERROR) << "Unable to read real group ID after setting it"; |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | uid_t ruid, euid, suid; |
| 426 | if (getresuid(&ruid, &euid, &suid) != 0) { |
| 427 | PLOG(FATAL) << "Unable to read saved uid"; |
| 428 | } |
| 429 | if (setresuid(suid, suid, -1) != 0) { |
| 430 | PLOG(FATAL) << "Unable to set real user ID back to saved uid"; |
| 431 | } else { |
| 432 | if (getresuid(&ruid, &euid, &suid) != 0) { |
| 433 | // If the user ID cannot be read at this point, the ruid variable will |
| 434 | // contain the previously read user ID from before changing it. This |
| 435 | // will cause the chown call below to set the incorrect user for |
| 436 | // non-root crashes. But do not treat this as a fatal error, so that |
| 437 | // the rest of the collection will continue for potential manual |
| 438 | // collection by a developer. |
| 439 | PLOG(ERROR) << "Unable to read real user ID after setting it"; |
| 440 | } |
| 441 | } |
| 442 | |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 443 | if (!CopyStdinToCoreFile(core_path)) { |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 444 | return kErrorReadCoreData; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 445 | } |
| 446 | |
Ben Chan | ec7d783 | 2012-01-09 10:29:58 -0800 | [diff] [blame] | 447 | if (!proc_files_usable) { |
| 448 | LOG(INFO) << "Skipped converting core file to minidump due to " |
| 449 | << "unusable proc files"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 450 | return kErrorUnusableProcFiles; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 451 | } |
| 452 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 453 | ErrorType error = ValidateCoreFile(core_path); |
| 454 | if (error != kErrorNone) { |
| 455 | return error; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 456 | } |
| 457 | |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 458 | // Chown the temp container directory back to the original user/group that |
| 459 | // crash_reporter is run as, so that additional files can be written to |
| 460 | // the temp folder. |
| 461 | if (chown(container_dir.value().c_str(), ruid, rgid) < 0) { |
| 462 | PLOG(ERROR) << "Could not set owner for " << container_dir.value(); |
| 463 | } |
| 464 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 465 | if (!RunCoreToMinidump(core_path, |
| 466 | container_dir, // procfs directory |
| 467 | minidump_path, |
| 468 | container_dir)) { // temporary directory |
| 469 | return kErrorCore2MinidumpConversion; |
| 470 | } |
| 471 | |
| 472 | LOG(INFO) << "Stored minidump to " << minidump_path.value(); |
| 473 | return kErrorNone; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 474 | } |
| 475 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 476 | UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash( |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 477 | pid_t pid, const std::string &exec, uid_t supplied_ruid, |
| 478 | bool *out_of_capacity) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 479 | FilePath crash_path; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 480 | if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path, |
| 481 | out_of_capacity)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 482 | LOG(ERROR) << "Unable to find/create process-specific crash path"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 483 | return kErrorSystemIssue; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 484 | } |
| 485 | |
Ben Chan | 294d5d1 | 2012-01-04 20:40:15 -0800 | [diff] [blame] | 486 | // Directory like /tmp/crash_reporter/1234 which contains the |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 487 | // procfs entries and other temporary files used during conversion. |
Steve Fung | ab2ac7d | 2015-08-14 17:58:05 -0700 | [diff] [blame] | 488 | FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid)); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 489 | // Delete a pre-existing directory from crash reporter that may have |
| 490 | // been left around for diagnostics from a failed conversion attempt. |
| 491 | // If we don't, existing files can cause forking to fail. |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 492 | base::DeleteFile(container_dir, true); |
Ben Chan | 262d798 | 2014-09-18 08:05:20 -0700 | [diff] [blame] | 493 | std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 494 | FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); |
| 495 | FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
| 496 | FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp"); |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 497 | FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); |
| 498 | |
Simon Que | acc7938 | 2012-05-04 18:10:09 -0700 | [diff] [blame] | 499 | if (GetLogContents(FilePath(log_config_path_), exec, log_path)) |
Ken Mixter | c49dbd4 | 2010-12-14 17:44:11 -0800 | [diff] [blame] | 500 | AddCrashMetaData("log", log_path.value()); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 501 | |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 502 | ErrorType error_type = |
| 503 | ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path); |
| 504 | if (error_type != kErrorNone) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 505 | LOG(INFO) << "Leaving core file at " << core_path.value() |
| 506 | << " due to conversion error"; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 507 | return error_type; |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 508 | } |
| 509 | |
| 510 | // Here we commit to sending this file. We must not return false |
| 511 | // after this point or we will generate a log report as well as a |
| 512 | // crash report. |
| 513 | WriteCrashMetaData(meta_path, |
| 514 | exec, |
| 515 | minidump_path.value()); |
| 516 | |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 517 | if (!IsDeveloperImage()) { |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 518 | base::DeleteFile(core_path, false); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 519 | } else { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 520 | LOG(INFO) << "Leaving core file at " << core_path.value() |
| 521 | << " due to developer image"; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 522 | } |
| 523 | |
Mike Frysinger | a557c11 | 2014-02-05 22:55:39 -0500 | [diff] [blame] | 524 | base::DeleteFile(container_dir, true); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 525 | return kErrorNone; |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 526 | } |
| 527 | |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 528 | bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes, |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 529 | pid_t *pid, int *signal, uid_t *uid, |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 530 | gid_t *gid, |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 531 | std::string *kernel_supplied_name) { |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 532 | pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(\\d+):(.*)"); |
| 533 | if (re.FullMatch(crash_attributes, pid, signal, uid, gid, |
| 534 | kernel_supplied_name)) |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 535 | return true; |
| 536 | |
| 537 | LOG(INFO) << "Falling back to parsing crash attributes '" |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 538 | << crash_attributes << "' without UID and GID"; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 539 | pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)"); |
| 540 | *uid = kUnknownUid; |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 541 | *gid = kUnknownGid; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 542 | return re_without_uid.FullMatch(crash_attributes, pid, signal, |
| 543 | kernel_supplied_name); |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 544 | } |
| 545 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 546 | bool UserCollector::ShouldDump(bool has_owner_consent, |
| 547 | bool is_developer, |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 548 | std::string *reason) { |
| 549 | reason->clear(); |
| 550 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 551 | // For developer builds, we always want to keep the crash reports unless |
| 552 | // we're testing the crash facilities themselves. This overrides |
| 553 | // feedback. Crash sending still obeys consent. |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 554 | if (is_developer) { |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 555 | *reason = "developer build - not testing - always dumping"; |
| 556 | return true; |
| 557 | } |
| 558 | |
| 559 | if (!has_owner_consent) { |
| 560 | *reason = "ignoring - no consent"; |
| 561 | return false; |
| 562 | } |
| 563 | |
| 564 | *reason = "handling"; |
| 565 | return true; |
| 566 | } |
| 567 | |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 568 | bool UserCollector::HandleCrash(const std::string &crash_attributes, |
| 569 | const char *force_exec) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 570 | CHECK(initialized_); |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 571 | pid_t pid = 0; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 572 | int signal = 0; |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 573 | uid_t supplied_ruid = kUnknownUid; |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 574 | gid_t supplied_rgid = kUnknownGid; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 575 | std::string kernel_supplied_name; |
| 576 | |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 577 | if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid, |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 578 | &supplied_rgid, &kernel_supplied_name)) { |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 579 | LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes; |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 580 | return false; |
| 581 | } |
| 582 | |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 583 | // Switch to the group and user that ran the crashing binary in order to |
| 584 | // access their /proc files. Do not set suid/sgid, so that we can switch |
| 585 | // back after copying the necessary files. |
Steve Fung | 773fd3c | 2015-10-09 17:01:35 -0700 | [diff] [blame] | 586 | if (setresgid(supplied_rgid, supplied_rgid, -1) != 0) { |
Steve Fung | 6db7cd7 | 2015-10-06 16:43:56 -0700 | [diff] [blame] | 587 | PLOG(FATAL) << "Unable to set real group ID to access process files"; |
| 588 | } |
| 589 | if (setresuid(supplied_ruid, supplied_ruid, -1) != 0) { |
| 590 | PLOG(FATAL) << "Unable to set real user ID to access process files"; |
| 591 | } |
| 592 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 593 | std::string exec; |
| 594 | if (force_exec) { |
| 595 | exec.assign(force_exec); |
| 596 | } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { |
Ken Mixter | 1b8fe01 | 2011-01-25 13:33:05 -0800 | [diff] [blame] | 597 | // If we cannot find the exec name, use the kernel supplied name. |
| 598 | // We don't always use the kernel's since it truncates the name to |
| 599 | // 16 characters. |
| 600 | exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str()); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 601 | } |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 602 | |
| 603 | // Allow us to test the crash reporting mechanism successfully even if |
| 604 | // other parts of the system crash. |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 605 | if (!filter_in_.empty() && |
| 606 | (filter_in_ == "none" || |
| 607 | filter_in_ != exec)) { |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 608 | // We use a different format message to make it more obvious in tests |
| 609 | // which crashes are test generated and which are real. |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 610 | LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while " |
Steve Fung | d6169a2 | 2014-08-11 15:52:23 -0700 | [diff] [blame] | 611 | << "filter_in=" << filter_in_ << "."; |
Ken Mixter | c6a58e0 | 2010-11-01 18:05:30 -0700 | [diff] [blame] | 612 | return true; |
| 613 | } |
| 614 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 615 | std::string reason; |
| 616 | bool dump = ShouldDump(is_feedback_allowed_function_(), |
Michael Krebs | 538ecbf | 2011-07-27 14:13:22 -0700 | [diff] [blame] | 617 | IsDeveloperImage(), |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 618 | &reason); |
Ken Mixter | 2105b49 | 2010-11-09 16:14:38 -0800 | [diff] [blame] | 619 | |
Ken Mixter | a324932 | 2011-03-03 08:47:38 -0800 | [diff] [blame] | 620 | LOG(WARNING) << "Received crash notification for " << exec << "[" << pid |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 621 | << "] sig " << signal << ", user " << supplied_ruid |
| 622 | << " (" << reason << ")"; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 623 | |
Ken Mixter | 5d3a1a2 | 2011-03-16 12:47:20 -0700 | [diff] [blame] | 624 | if (dump) { |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 625 | count_crash_function_(); |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 626 | |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 627 | if (generate_diagnostics_) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 628 | bool out_of_capacity = false; |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 629 | ErrorType error_type = |
Michael Krebs | 1c57e9e | 2012-09-25 18:03:13 -0700 | [diff] [blame] | 630 | ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity); |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 631 | if (error_type != kErrorNone) { |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 632 | if (!out_of_capacity) |
Ben Chan | 6e709a1 | 2012-02-29 12:10:44 -0800 | [diff] [blame] | 633 | EnqueueCollectionErrorLog(pid, error_type, exec); |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 634 | return false; |
| 635 | } |
Ken Mixter | 0340316 | 2010-08-18 15:23:16 -0700 | [diff] [blame] | 636 | } |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 637 | } |
Ken Mixter | 207694d | 2010-10-28 15:42:37 -0700 | [diff] [blame] | 638 | |
Ken Mixter | 777484c | 2010-07-23 16:22:44 -0700 | [diff] [blame] | 639 | return true; |
Chris Sosa | e4a8603 | 2010-06-16 17:08:34 -0700 | [diff] [blame] | 640 | } |