Home | History | Annotate | Download | only in crash_reporter
      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