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 */ 16 17 #include "user_collector.h" 18 19 #include <elf.h> 20 #include <fcntl.h> 21 #include <grp.h> // For struct group. 22 #include <pcrecpp.h> 23 #include <pwd.h> // For struct passwd. 24 #include <stdint.h> 25 #include <sys/cdefs.h> // For __WORDSIZE 26 #include <sys/fsuid.h> 27 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. 28 #include <unistd.h> // For setgroups 29 30 #include <iostream> // For std::oct 31 #include <string> 32 #include <vector> 33 34 #include <base/files/file_util.h> 35 #include <base/logging.h> 36 #include <base/posix/eintr_wrapper.h> 37 #include <base/strings/string_split.h> 38 #include <base/strings/string_util.h> 39 #include <base/strings/stringprintf.h> 40 #include <brillo/osrelease_reader.h> 41 #include <brillo/process.h> 42 #include <brillo/syslog_logging.h> 43 #include <cutils/properties.h> 44 #include <private/android_filesystem_config.h> 45 46 static const char kCollectionErrorSignature[] = 47 "crash_reporter-user-collection"; 48 static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled"; 49 static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md"; 50 51 static const char kStatePrefix[] = "State:\t"; 52 53 static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp"; 54 55 // Define an otherwise invalid value that represents an unknown UID and GID. 56 static const uid_t kUnknownUid = -1; 57 static const gid_t kUnknownGid = -1; 58 59 const char *UserCollector::kUserId = "Uid:\t"; 60 const char *UserCollector::kGroupId = "Gid:\t"; 61 62 // Product information keys in the /etc/os-release.d folder. 63 static const char kBdkVersionKey[] = "bdk_version"; 64 static const char kProductIDKey[] = "product_id"; 65 static const char kProductVersionKey[] = "product_version"; 66 67 68 using base::FilePath; 69 using base::StringPrintf; 70 71 UserCollector::UserCollector() 72 : generate_diagnostics_(false), 73 initialized_(false) { 74 } 75 76 void UserCollector::Initialize( 77 UserCollector::CountCrashFunction count_crash_function, 78 const std::string &our_path, 79 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, 80 bool generate_diagnostics, 81 bool core2md_failure, 82 bool directory_failure, 83 const std::string &filter_in) { 84 CrashCollector::Initialize(count_crash_function, 85 is_feedback_allowed_function); 86 our_path_ = our_path; 87 initialized_ = true; 88 generate_diagnostics_ = generate_diagnostics; 89 core2md_failure_ = core2md_failure; 90 directory_failure_ = directory_failure; 91 filter_in_ = filter_in; 92 93 gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS, AID_READPROC }; 94 if (setgroups(arraysize(groups), groups) != 0) { 95 PLOG(FATAL) << "Unable to set groups to root, system, dbus, and readproc"; 96 } 97 } 98 99 UserCollector::~UserCollector() { 100 } 101 102 std::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 121 bool UserCollector::SetUpInternal(bool enabled) { 122 CHECK(initialized_); 123 LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling"; 124 125 property_set(kCorePatternProperty, enabled ? "1" : "0"); 126 127 return true; 128 } 129 130 bool 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 144 bool UserCollector::GetIdFromStatus( 145 const char *prefix, IdKind kind, 146 const std::vector<std::string> &status_lines, int *id) { 147 // From fs/proc/array.c:task_state(), this file contains: 148 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n 149 std::string id_line; 150 if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) { 151 return false; 152 } 153 std::string id_substring = id_line.substr(strlen(prefix), std::string::npos); 154 std::vector<std::string> ids = base::SplitString( 155 id_substring, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 156 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) { 157 return false; 158 } 159 const char *number = ids[kind].c_str(); 160 char *end_number = nullptr; 161 *id = strtol(number, &end_number, 10); 162 if (*end_number != '\0') { 163 return false; 164 } 165 return true; 166 } 167 168 bool 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); 175 return true; 176 } 177 178 void UserCollector::EnqueueCollectionErrorLog(pid_t pid, 179 ErrorType error_type, 180 const std::string &exec) { 181 FilePath crash_path; 182 LOG(INFO) << "Writing conversion problems as separate crash report."; 183 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) { 184 LOG(ERROR) << "Could not even get log directory; out of space?"; 185 return; 186 } 187 AddCrashMetaData("sig", kCollectionErrorSignature); 188 AddCrashMetaData("error_type", GetErrorTypeSignature(error_type)); 189 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid); 190 std::string error_log = brillo::GetLog(); 191 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog"); 192 if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature, 193 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; 198 base::ReadFileToString(diag_log_path, &diag_log_contents); 199 error_log.append(diag_log_contents); 200 base::DeleteFile(diag_log_path, false); 201 } 202 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 203 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); 204 // We must use WriteNewFile instead of base::WriteFile as we do 205 // not want to write with root access to a symlink that an attacker 206 // might have created. 207 if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) { 208 LOG(ERROR) << "Error writing new file " << log_path.value(); 209 return; 210 } 211 WriteCrashMetaData(meta_path, exec, log_path.value()); 212 } 213 214 bool UserCollector::CopyOffProcFiles(pid_t pid, 215 const FilePath &container_dir) { 216 if (!base::CreateDirectory(container_dir)) { 217 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); 230 return false; 231 } 232 FilePath process_path = GetProcessPath(pid); 233 if (!base::PathExists(process_path)) { 234 LOG(ERROR) << "Path " << process_path.value() << " does not exist"; 235 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) { 245 if (!base::CopyFile(process_path.Append(proc_files[i]), 246 container_dir.Append(proc_files[i]))) { 247 LOG(ERROR) << "Could not copy " << proc_files[i] << " file"; 248 return false; 249 } 250 } 251 return true; 252 } 253 254 bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const { 255 // 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. 257 int64_t file_size = 0; 258 if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) { 259 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 } 266 return true; 267 } 268 269 UserCollector::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) { 273 PLOG(ERROR) << "Could not open core file " << core_path.value(); 274 return kErrorInvalidCoreFile; 275 } 276 277 char e_ident[EI_NIDENT]; 278 bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident)); 279 IGNORE_EINTR(close(fd)); 280 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 304 bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid, 305 FilePath *crash_file_path, 306 bool *out_of_capacity) { 307 FilePath process_path = GetProcessPath(pid); 308 std::string status; 309 if (directory_failure_) { 310 LOG(ERROR) << "Purposefully failing to create spool directory"; 311 return false; 312 } 313 314 uid_t uid; 315 if (base::ReadFileToString(process_path.Append("status"), &status)) { 316 std::vector<std::string> status_lines = base::SplitString( 317 status, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 318 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"; 340 LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: " 341 << base::DirectoryExists(process_path); 342 return false; 343 } 344 345 if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) { 346 LOG(ERROR) << "Could not create crash directory"; 347 return false; 348 } 349 return true; 350 } 351 352 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { 353 // Copy off all stdin to a core file. 354 FilePath stdin_path("/proc/self/fd/0"); 355 if (base::CopyFile(stdin_path, core_path)) { 356 return true; 357 } 358 359 PLOG(ERROR) << "Could not write core file"; 360 // If the file system was full, make sure we remove any remnants. 361 base::DeleteFile(core_path, false); 362 return false; 363 } 364 365 bool UserCollector::RunCoreToMinidump(const FilePath &core_path, 366 const FilePath &procfs_directory, 367 const FilePath &minidump_path, 368 const FilePath &temp_directory) { 369 FilePath output_path = temp_directory.Append("output"); 370 brillo::ProcessImpl core2md; 371 core2md.RedirectOutput(output_path.value()); 372 core2md.AddArg(kCoreToMinidumpConverterPath); 373 core2md.AddArg(core_path.value()); 374 core2md.AddArg(procfs_directory.value()); 375 376 if (!core2md_failure_) { 377 core2md.AddArg(minidump_path.value()); 378 } else { 379 // To test how core2md errors are propagaged, cause an error 380 // by forgetting a required argument. 381 } 382 383 int errorlevel = core2md.Run(); 384 385 std::string output; 386 base::ReadFileToString(output_path, &output); 387 if (errorlevel != 0) { 388 LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath 389 << " [result=" << errorlevel << "]: " << output; 390 return false; 391 } 392 393 if (!base::PathExists(minidump_path)) { 394 LOG(ERROR) << "Minidump file " << minidump_path.value() 395 << " was not created"; 396 return false; 397 } 398 return true; 399 } 400 401 UserCollector::ErrorType UserCollector::ConvertCoreToMinidump( 402 pid_t pid, 403 const FilePath &container_dir, 404 const FilePath &core_path, 405 const FilePath &minidump_path) { 406 // 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 412 // 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 449 if (!CopyStdinToCoreFile(core_path)) { 450 return kErrorReadCoreData; 451 } 452 453 if (!proc_files_usable) { 454 LOG(INFO) << "Skipped converting core file to minidump due to " 455 << "unusable proc files"; 456 return kErrorUnusableProcFiles; 457 } 458 459 ErrorType error = ValidateCoreFile(core_path); 460 if (error != kErrorNone) { 461 return error; 462 } 463 464 // 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 471 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; 480 } 481 482 UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash( 483 pid_t pid, const std::string &exec, uid_t supplied_ruid, 484 bool *out_of_capacity) { 485 FilePath crash_path; 486 if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path, 487 out_of_capacity)) { 488 LOG(ERROR) << "Unable to find/create process-specific crash path"; 489 return kErrorSystemIssue; 490 } 491 492 // Directory like /tmp/crash_reporter/1234 which contains the 493 // procfs entries and other temporary files used during conversion. 494 FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid)); 495 // 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. 498 base::DeleteFile(container_dir, true); 499 std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid); 500 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"); 503 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 504 505 if (GetLogContents(FilePath(log_config_path_), exec, log_path)) 506 AddCrashMetaData("log", log_path.value()); 507 508 brillo::OsReleaseReader reader; 509 reader.Load(); 510 std::string value = "undefined"; 511 if (!reader.GetString(kBdkVersionKey, &value)) { 512 LOG(ERROR) << "Could not read " << kBdkVersionKey 513 << " from /etc/os-release.d/"; 514 } 515 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); 530 531 ErrorType error_type = 532 ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path); 533 if (error_type != kErrorNone) { 534 LOG(INFO) << "Leaving core file at " << core_path.value() 535 << " due to conversion error"; 536 return error_type; 537 } 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 546 if (!IsDeveloperImage()) { 547 base::DeleteFile(core_path, false); 548 } else { 549 LOG(INFO) << "Leaving core file at " << core_path.value() 550 << " due to developer image"; 551 } 552 553 base::DeleteFile(container_dir, true); 554 return kErrorNone; 555 } 556 557 bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes, 558 pid_t *pid, int *signal, uid_t *uid, 559 gid_t *gid, 560 std::string *kernel_supplied_name) { 561 pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(\\d+):(.*)"); 562 if (re.FullMatch(crash_attributes, pid, signal, uid, gid, 563 kernel_supplied_name)) 564 return true; 565 566 LOG(INFO) << "Falling back to parsing crash attributes '" 567 << crash_attributes << "' without UID and GID"; 568 pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)"); 569 *uid = kUnknownUid; 570 *gid = kUnknownGid; 571 return re_without_uid.FullMatch(crash_attributes, pid, signal, 572 kernel_supplied_name); 573 } 574 575 bool UserCollector::ShouldDump(bool has_owner_consent, 576 bool is_developer, 577 std::string *reason) { 578 reason->clear(); 579 580 // 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. 583 if (is_developer) { 584 *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 597 bool UserCollector::HandleCrash(const std::string &crash_attributes, 598 const char *force_exec) { 599 CHECK(initialized_); 600 pid_t pid = 0; 601 int signal = 0; 602 uid_t supplied_ruid = kUnknownUid; 603 gid_t supplied_rgid = kUnknownGid; 604 std::string kernel_supplied_name; 605 606 if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid, 607 &supplied_rgid, &kernel_supplied_name)) { 608 LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes; 609 return false; 610 } 611 612 // 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. 615 if (setresgid(supplied_rgid, supplied_rgid, -1) != 0) { 616 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 622 std::string exec; 623 if (force_exec) { 624 exec.assign(force_exec); 625 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { 626 // 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()); 630 } 631 632 // Allow us to test the crash reporting mechanism successfully even if 633 // other parts of the system crash. 634 if (!filter_in_.empty() && 635 (filter_in_ == "none" || 636 filter_in_ != exec)) { 637 // We use a different format message to make it more obvious in tests 638 // which crashes are test generated and which are real. 639 LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while " 640 << "filter_in=" << filter_in_ << "."; 641 return true; 642 } 643 644 std::string reason; 645 bool dump = ShouldDump(is_feedback_allowed_function_(), 646 IsDeveloperImage(), 647 &reason); 648 649 LOG(WARNING) << "Received crash notification for " << exec << "[" << pid 650 << "] sig " << signal << ", user " << supplied_ruid 651 << " (" << reason << ")"; 652 653 if (dump) { 654 count_crash_function_(); 655 656 if (generate_diagnostics_) { 657 bool out_of_capacity = false; 658 ErrorType error_type = 659 ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity); 660 if (error_type != kErrorNone) { 661 if (!out_of_capacity) 662 EnqueueCollectionErrorLog(pid, error_type, exec); 663 return false; 664 } 665 } 666 } 667 668 return true; 669 } 670