user_collector.cc revision c49dbd4775986f32b2f09659595f9f28ef7f6b44
13dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 23dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang// Use of this source code is governed by a BSD-style license that can be 33dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang// found in the LICENSE file. 43dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 53dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "crash-reporter/user_collector.h" 63dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 73dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include <grp.h> // For struct group. 83dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include <pwd.h> // For struct passwd. 93dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. 103dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 113dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include <string> 123dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include <vector> 133dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 143dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "base/file_util.h" 153dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "base/logging.h" 163dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "base/string_util.h" 173dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "crash-reporter/system_logging.h" 183dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang#include "gflags/gflags.h" 19b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 20b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang#pragma GCC diagnostic ignored "-Wstrict-aliasing" 21b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik JangDEFINE_bool(core2md_failure_test, false, "Core2md failure test"); 22b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik JangDEFINE_bool(directory_failure_test, false, "Spool directory failure test"); 23b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik JangDEFINE_string(filter_in, "", 24b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang "Ignore all crashes but this for testing"); 25b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang#pragma GCC diagnostic error "-Wstrict-aliasing" 26b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 27b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstatic const char kCollectionErrorSignature[] = 28b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang "crash_reporter-user-collection"; 29a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang// This procfs file is used to cause kernel core file writing to 303dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang// instead pipe the core file into a user space process. See 31a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang// core(5) man page. 32a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jangstatic const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern"; 333dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jangstatic const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit"; 343dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang// Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent 35b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang// crashes, but finite to avoid infinitely recursing on crash handling. 36b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstatic const char kCorePipeLimit[] = "4"; 37b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstatic const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md"; 38b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstatic const char kLeaveCoreFile[] = "/root/.leave_core"; 39b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 40b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstatic const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf"; 41b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 42b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangconst char *UserCollector::kUserId = "Uid:\t"; 43b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangconst char *UserCollector::kGroupId = "Gid:\t"; 44b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 453dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik JangUserCollector::UserCollector() 46b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang : generate_diagnostics_(false), 473dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang core_pattern_file_(kCorePatternFile), 48b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang core_pipe_limit_file_(kCorePipeLimitFile), 493dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang initialized_(false) { 503dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang} 51b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 523dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jangvoid UserCollector::Initialize( 533dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang UserCollector::CountCrashFunction count_crash_function, 543dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang const std::string &our_path, 553dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, 56b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang SystemLogging *logger, 57b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang bool generate_diagnostics) { 583dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang CrashCollector::Initialize(count_crash_function, 593dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang is_feedback_allowed_function, 60b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang logger); 61b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang our_path_ = our_path; 62b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang initialized_ = true; 63b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang generate_diagnostics_ = generate_diagnostics; 64b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 65b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 66b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik JangUserCollector::~UserCollector() { 67b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 68b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 69b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangstd::string UserCollector::GetPattern(bool enabled) const { 70b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (enabled) { 71b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return StringPrintf("|%s --signal=%%s --pid=%%p", our_path_.c_str()); 72b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } else { 73b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return "core"; 74b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 75b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 76b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 77a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jangbool UserCollector::SetUpInternal(bool enabled) { 78a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang CHECK(initialized_); 793dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang logger_->LogInfo("%s user crash handling", 803dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang enabled ? "Enabling" : "Disabling"); 81b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (file_util::WriteFile(FilePath(core_pipe_limit_file_), 82b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang kCorePipeLimit, 83b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang strlen(kCorePipeLimit)) != 84b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang static_cast<int>(strlen(kCorePipeLimit))) { 85b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang logger_->LogError("Unable to write %s", core_pipe_limit_file_.c_str()); 86b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 87b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 88b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang std::string pattern = GetPattern(enabled); 89b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (file_util::WriteFile(FilePath(core_pattern_file_), 903dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang pattern.c_str(), 913dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang pattern.length()) != 923dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang static_cast<int>(pattern.length())) { 93b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang logger_->LogError("Unable to write %s", core_pattern_file_.c_str()); 94b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 95b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 96b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 97b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 98b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 99b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik JangFilePath UserCollector::GetProcessPath(pid_t pid) { 100b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return FilePath(StringPrintf("/proc/%d", pid)); 101b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 102b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 103b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangbool UserCollector::GetSymlinkTarget(const FilePath &symlink, 104b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang FilePath *target) { 105b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang int max_size = 32; 106b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang scoped_array<char> buffer; 107b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang while (true) { 108b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang buffer.reset(new char[max_size + 1]); 109b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size); 110b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (size < 0) { 111b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 112b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 113b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang buffer[size] = 0; 114b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (size == max_size) { 115b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Avoid overflow when doubling. 116b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (max_size * 2 > max_size) { 117b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang max_size *= 2; 118b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang continue; 119b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } else { 120b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 121b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1223dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 1233dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang break; 124b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 125b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 126b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang *target = FilePath(buffer.get()); 127b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 128b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang} 129b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 130b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangbool UserCollector::GetExecutableBaseNameFromPid(uid_t pid, 1313dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang std::string *base_name) { 1323dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang FilePath target; 1333dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang if (!GetSymlinkTarget(GetProcessPath(pid).Append("exe"), &target)) 1343dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang return false; 1353dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang *base_name = target.BaseName().value(); 1363dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang return true; 137} 138 139bool UserCollector::GetIdFromStatus(const char *prefix, 140 IdKind kind, 141 const std::string &status_contents, 142 int *id) { 143 // From fs/proc/array.c:task_state(), this file contains: 144 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n 145 std::vector<std::string> status_lines; 146 SplitString(status_contents, '\n', &status_lines); 147 std::vector<std::string>::iterator line_iterator; 148 for (line_iterator = status_lines.begin(); 149 line_iterator != status_lines.end(); 150 ++line_iterator) { 151 if (line_iterator->find(prefix) == 0) 152 break; 153 } 154 if (line_iterator == status_lines.end()) { 155 return false; 156 } 157 std::string id_substring = line_iterator->substr(strlen(prefix), 158 std::string::npos); 159 std::vector<std::string> ids; 160 SplitString(id_substring, '\t', &ids); 161 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) { 162 return false; 163 } 164 const char *number = ids[kind].c_str(); 165 char *end_number = NULL; 166 *id = strtol(number, &end_number, 10); 167 if (*end_number != '\0') 168 return false; 169 return true; 170} 171 172void UserCollector::LogCollectionError(const std::string &error_message) { 173 error_log_.append(error_message.c_str()); 174 error_log_.append("\n"); 175 logger_->LogError(error_message.c_str()); 176} 177 178void UserCollector::EnqueueCollectionErrorLog(pid_t pid, 179 const std::string &exec) { 180 FilePath crash_path; 181 logger_->LogInfo("Writing conversion problems as separate crash report."); 182 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) { 183 logger_->LogError("Could not even get log directory; out of space?"); 184 return; 185 } 186 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); 187 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 188 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); 189 // We must use WriteNewFile instead of file_util::WriteFile as we do 190 // not want to write with root access to a symlink that an attacker 191 // might have created. 192 WriteNewFile(log_path, error_log_.data(), error_log_.length()); 193 AddCrashMetaData("sig", kCollectionErrorSignature); 194 WriteCrashMetaData(meta_path, exec, log_path.value()); 195} 196 197bool UserCollector::CopyOffProcFiles(pid_t pid, 198 const FilePath &container_dir) { 199 if (!file_util::CreateDirectory(container_dir)) { 200 LogCollectionError(StringPrintf("Could not create %s", 201 container_dir.value().c_str())); 202 return false; 203 } 204 FilePath process_path = GetProcessPath(pid); 205 if (!file_util::PathExists(process_path)) { 206 LogCollectionError(StringPrintf("Path %s does not exist", 207 process_path.value().c_str())); 208 return false; 209 } 210 static const char *proc_files[] = { 211 "auxv", 212 "cmdline", 213 "environ", 214 "maps", 215 "status" 216 }; 217 for (unsigned i = 0; i < arraysize(proc_files); ++i) { 218 if (!file_util::CopyFile(process_path.Append(proc_files[i]), 219 container_dir.Append(proc_files[i]))) { 220 LogCollectionError(StringPrintf("Could not copy %s file", 221 proc_files[i])); 222 return false; 223 } 224 } 225 return true; 226} 227 228bool UserCollector::GetCreatedCrashDirectory(pid_t pid, 229 FilePath *crash_file_path, 230 bool *out_of_capacity) { 231 FilePath process_path = GetProcessPath(pid); 232 std::string status; 233 if (FLAGS_directory_failure_test) { 234 LogCollectionError("Purposefully failing to create spool directory"); 235 return false; 236 } 237 if (!file_util::ReadFileToString(process_path.Append("status"), 238 &status)) { 239 LogCollectionError("Could not read status file"); 240 return false; 241 } 242 int process_euid; 243 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { 244 LogCollectionError("Could not find euid in status file"); 245 return false; 246 } 247 if (!GetCreatedCrashDirectoryByEuid(process_euid, 248 crash_file_path, 249 out_of_capacity)) { 250 LogCollectionError("Could not create crash directory"); 251 return false; 252 } 253 return true; 254} 255 256bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { 257 // Copy off all stdin to a core file. 258 FilePath stdin_path("/dev/fd/0"); 259 if (file_util::CopyFile(stdin_path, core_path)) { 260 return true; 261 } 262 263 LogCollectionError("Could not write core file"); 264 // If the file system was full, make sure we remove any remnants. 265 file_util::Delete(core_path, false); 266 return false; 267} 268 269bool UserCollector::RunCoreToMinidump(const FilePath &core_path, 270 const FilePath &procfs_directory, 271 const FilePath &minidump_path, 272 const FilePath &temp_directory) { 273 FilePath output_path = temp_directory.Append("output"); 274 std::vector<const char *> core2md_arguments; 275 core2md_arguments.push_back(kCoreToMinidumpConverterPath); 276 core2md_arguments.push_back(core_path.value().c_str()); 277 core2md_arguments.push_back(procfs_directory.value().c_str()); 278 core2md_arguments.push_back(minidump_path.value().c_str()); 279 280 if (FLAGS_core2md_failure_test) { 281 // To test how core2md errors are propagaged, cause an error 282 // by forgetting a required argument. 283 core2md_arguments.pop_back(); 284 } 285 286 int errorlevel = ForkExecAndPipe(core2md_arguments, 287 output_path.value().c_str()); 288 289 std::string output; 290 file_util::ReadFileToString(output_path, &output); 291 if (errorlevel != 0) { 292 LogCollectionError(StringPrintf("Problem during %s [result=%d]: %s", 293 kCoreToMinidumpConverterPath, 294 errorlevel, 295 output.c_str())); 296 return false; 297 } 298 299 if (!file_util::PathExists(minidump_path)) { 300 LogCollectionError(StringPrintf("Minidump file %s was not created", 301 minidump_path.value().c_str())); 302 return false; 303 } 304 return true; 305} 306 307bool UserCollector::ConvertCoreToMinidump(pid_t pid, 308 const FilePath &container_dir, 309 const FilePath &core_path, 310 const FilePath &minidump_path) { 311 if (!CopyOffProcFiles(pid, container_dir)) { 312 return false; 313 } 314 315 if (!CopyStdinToCoreFile(core_path)) { 316 return false; 317 } 318 319 bool conversion_result = RunCoreToMinidump( 320 core_path, 321 container_dir, // procfs directory 322 minidump_path, 323 container_dir); // temporary directory 324 325 if (conversion_result) { 326 logger_->LogInfo("Stored minidump to %s", minidump_path.value().c_str()); 327 } 328 329 return conversion_result; 330} 331 332bool UserCollector::ConvertAndEnqueueCrash(int pid, 333 const std::string &exec, 334 bool *out_of_capacity) { 335 FilePath crash_path; 336 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) { 337 LogCollectionError("Unable to find/create process-specific crash path"); 338 return false; 339 } 340 341 // Directory like /tmp/crash_reporter.1234 which contains the 342 // procfs entries and other temporary files used during conversion. 343 FilePath container_dir = FilePath("/tmp").Append( 344 StringPrintf("crash_reporter.%d", pid)); 345 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); 346 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); 347 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); 348 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp"); 349 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 350 351 if (GetLogContents(FilePath(kDefaultLogConfig), exec, log_path)) 352 AddCrashMetaData("log", log_path.value()); 353 354 if (!ConvertCoreToMinidump(pid, container_dir, core_path, 355 minidump_path)) { 356 logger_->LogInfo("Leaving core file at %s due to conversion error", 357 core_path.value().c_str()); 358 return false; 359 } 360 361 // Here we commit to sending this file. We must not return false 362 // after this point or we will generate a log report as well as a 363 // crash report. 364 WriteCrashMetaData(meta_path, 365 exec, 366 minidump_path.value()); 367 368 if (!file_util::PathExists(FilePath(kLeaveCoreFile))) { 369 file_util::Delete(core_path, false); 370 } else { 371 logger_->LogInfo("Leaving core file at %s due to developer image", 372 core_path.value().c_str()); 373 } 374 375 file_util::Delete(container_dir, true); 376 return true; 377} 378 379bool UserCollector::HandleCrash(int signal, int pid, const char *force_exec) { 380 CHECK(initialized_); 381 std::string exec; 382 if (force_exec) { 383 exec.assign(force_exec); 384 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { 385 // If for some reason we don't have the base name, avoid completely 386 // failing by indicating an unknown name. 387 exec = "unknown"; 388 } 389 390 // Allow us to test the crash reporting mechanism successfully even if 391 // other parts of the system crash. 392 if (!FLAGS_filter_in.empty() && 393 (FLAGS_filter_in == "none" || 394 FLAGS_filter_in != exec)) { 395 // We use a different format message to make it more obvious in tests 396 // which crashes are test generated and which are real. 397 logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s", 398 exec.c_str(), pid, FLAGS_filter_in.c_str()); 399 return true; 400 } 401 402 bool feedback = is_feedback_allowed_function_(); 403 const char *handling_string = "handling"; 404 if (!feedback) { 405 handling_string = "ignoring - no consent"; 406 } 407 408 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome 409 // crashes towards user crashes, so user crashes really mean non-Chrome 410 // user-space crashes. 411 if (exec == "chrome") { 412 feedback = false; 413 handling_string = "ignoring - chrome crash"; 414 } 415 416 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", 417 exec.c_str(), pid, signal, handling_string); 418 419 if (feedback) { 420 count_crash_function_(); 421 422 if (generate_diagnostics_) { 423 bool out_of_capacity = false; 424 if (!ConvertAndEnqueueCrash(pid, exec, &out_of_capacity)) { 425 if (!out_of_capacity) 426 EnqueueCollectionErrorLog(pid, exec); 427 return false; 428 } 429 } 430 } 431 432 return true; 433} 434