Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Unified Diff: user_collector.cc

Issue 6297004: crash-reporter: Add diagnostics to help diagnose failures in the wild (Closed) Base URL: http://git.chromium.org/git/crash-reporter.git@master
Patch Set: respond to review Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « user_collector.h ('k') | user_collector_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: user_collector.cc
diff --git a/user_collector.cc b/user_collector.cc
index 59b460bdca6ae261cfa8bfe2890170a5fc91c2f5..a6dd091e770349587bc052a924fe790ed372cf8f 100644
--- a/user_collector.cc
+++ b/user_collector.cc
@@ -5,6 +5,8 @@
#include "crash-reporter/user_collector.h"
#include <grp.h> // For struct group.
+#include <pcrecpp.h>
+#include <pcrecpp.h>
#include <pwd.h> // For struct passwd.
#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
@@ -18,8 +20,8 @@
#include "gflags/gflags.h"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-DEFINE_bool(core2md_failure_test, false, "Core2md failure test");
-DEFINE_bool(directory_failure_test, false, "Spool directory failure test");
+DEFINE_bool(core2md_failure, false, "Core2md failure test");
+DEFINE_bool(directory_failure, false, "Spool directory failure test");
DEFINE_string(filter_in, "",
"Ignore all crashes but this for testing");
#pragma GCC diagnostic error "-Wstrict-aliasing"
@@ -68,7 +70,11 @@ UserCollector::~UserCollector() {
std::string UserCollector::GetPattern(bool enabled) const {
if (enabled) {
- return StringPrintf("|%s --signal=%%s --pid=%%p", our_path_.c_str());
+ // Combine the three crash attributes into one parameter to try to reduce
+ // the size of the invocation line for crash_reporter since the kernel
+ // has a fixed-sized (128B) buffer that it will truncate into. Note that
+ // the kernel does not support quoted arguments in core_pattern.
+ return StringPrintf("|%s --user=%%p:%%s:%%e", our_path_.c_str());
} else {
return "core";
}
@@ -169,12 +175,6 @@ bool UserCollector::GetIdFromStatus(const char *prefix,
return true;
}
-void UserCollector::LogCollectionError(const std::string &error_message) {
- error_log_.append(error_message.c_str());
- error_log_.append("\n");
- logger_->LogError(error_message.c_str());
-}
-
void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
const std::string &exec) {
FilePath crash_path;
@@ -184,12 +184,24 @@ void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
return;
}
std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
+ std::string error_log = logger_->get_accumulator();
+ FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
+ if (GetLogContents(FilePath(kDefaultLogConfig), kCollectionErrorSignature,
+ diag_log_path)) {
+ // We load the contents of diag_log into memory and append it to
+ // the error log. We cannot just append to files because we need
+ // to always create new files to prevent attack.
+ std::string diag_log_contents;
+ file_util::ReadFileToString(diag_log_path, &diag_log_contents);
+ error_log.append(diag_log_contents);
+ file_util::Delete(diag_log_path, false);
+ }
FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
// We must use WriteNewFile instead of file_util::WriteFile as we do
// not want to write with root access to a symlink that an attacker
// might have created.
- WriteNewFile(log_path, error_log_.data(), error_log_.length());
+ WriteNewFile(log_path, error_log.data(), error_log.length());
AddCrashMetaData("sig", kCollectionErrorSignature);
WriteCrashMetaData(meta_path, exec, log_path.value());
}
@@ -197,14 +209,13 @@ void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
bool UserCollector::CopyOffProcFiles(pid_t pid,
const FilePath &container_dir) {
if (!file_util::CreateDirectory(container_dir)) {
- LogCollectionError(StringPrintf("Could not create %s",
- container_dir.value().c_str()));
+ logger_->LogError("Could not create %s",
+ container_dir.value().c_str());
return false;
}
FilePath process_path = GetProcessPath(pid);
if (!file_util::PathExists(process_path)) {
- LogCollectionError(StringPrintf("Path %s does not exist",
- process_path.value().c_str()));
+ logger_->LogError("Path %s does not exist", process_path.value().c_str());
return false;
}
static const char *proc_files[] = {
@@ -217,8 +228,7 @@ bool UserCollector::CopyOffProcFiles(pid_t pid,
for (unsigned i = 0; i < arraysize(proc_files); ++i) {
if (!file_util::CopyFile(process_path.Append(proc_files[i]),
container_dir.Append(proc_files[i]))) {
- LogCollectionError(StringPrintf("Could not copy %s file",
- proc_files[i]));
+ logger_->LogError("Could not copy %s file", proc_files[i]);
return false;
}
}
@@ -230,24 +240,27 @@ bool UserCollector::GetCreatedCrashDirectory(pid_t pid,
bool *out_of_capacity) {
FilePath process_path = GetProcessPath(pid);
std::string status;
- if (FLAGS_directory_failure_test) {
- LogCollectionError("Purposefully failing to create spool directory");
+ if (FLAGS_directory_failure) {
+ logger_->LogError("Purposefully failing to create spool directory");
return false;
}
if (!file_util::ReadFileToString(process_path.Append("status"),
&status)) {
- LogCollectionError("Could not read status file");
+ logger_->LogError("Could not read status file");
+ logger_->LogInfo("Path %s FileExists: %d",
+ process_path.value().c_str(),
+ file_util::DirectoryExists(process_path));
return false;
}
int process_euid;
if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) {
- LogCollectionError("Could not find euid in status file");
+ logger_->LogError("Could not find euid in status file");
return false;
}
if (!GetCreatedCrashDirectoryByEuid(process_euid,
crash_file_path,
out_of_capacity)) {
- LogCollectionError("Could not create crash directory");
+ logger_->LogError("Could not create crash directory");
return false;
}
return true;
@@ -260,7 +273,7 @@ bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
return true;
}
- LogCollectionError("Could not write core file");
+ logger_->LogError("Could not write core file");
// If the file system was full, make sure we remove any remnants.
file_util::Delete(core_path, false);
return false;
@@ -277,7 +290,7 @@ bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
core2md_arguments.push_back(procfs_directory.value().c_str());
core2md_arguments.push_back(minidump_path.value().c_str());
- if (FLAGS_core2md_failure_test) {
+ if (FLAGS_core2md_failure) {
// To test how core2md errors are propagaged, cause an error
// by forgetting a required argument.
core2md_arguments.pop_back();
@@ -289,16 +302,16 @@ bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
std::string output;
file_util::ReadFileToString(output_path, &output);
if (errorlevel != 0) {
- LogCollectionError(StringPrintf("Problem during %s [result=%d]: %s",
- kCoreToMinidumpConverterPath,
- errorlevel,
- output.c_str()));
+ logger_->LogError("Problem during %s [result=%d]: %s",
+ kCoreToMinidumpConverterPath,
+ errorlevel,
+ output.c_str());
return false;
}
if (!file_util::PathExists(minidump_path)) {
- LogCollectionError(StringPrintf("Minidump file %s was not created",
- minidump_path.value().c_str()));
+ logger_->LogError("Minidump file %s was not created",
+ minidump_path.value().c_str());
return false;
}
return true;
@@ -334,7 +347,7 @@ bool UserCollector::ConvertAndEnqueueCrash(int pid,
bool *out_of_capacity) {
FilePath crash_path;
if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) {
- LogCollectionError("Unable to find/create process-specific crash path");
+ logger_->LogError("Unable to find/create process-specific crash path");
return false;
}
@@ -342,6 +355,10 @@ bool UserCollector::ConvertAndEnqueueCrash(int pid,
// procfs entries and other temporary files used during conversion.
FilePath container_dir = FilePath("/tmp").Append(
StringPrintf("crash_reporter.%d", pid));
+ // Delete a pre-existing directory from crash reporter that may have
+ // been left around for diagnostics from a failed conversion attempt.
+ // If we don't, existing files can cause forking to fail.
+ file_util::Delete(container_dir, true);
std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
@@ -376,15 +393,34 @@ bool UserCollector::ConvertAndEnqueueCrash(int pid,
return true;
}
-bool UserCollector::HandleCrash(int signal, int pid, const char *force_exec) {
+bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
+ pid_t *pid, int *signal,
+ std::string *kernel_supplied_name) {
+ pcrecpp::RE re("(\\d+):(\\d+):(.*)");
+ return re.FullMatch(crash_attributes, pid, signal, kernel_supplied_name);
+}
+
+bool UserCollector::HandleCrash(const std::string &crash_attributes,
+ const char *force_exec) {
CHECK(initialized_);
+ int pid = 0;
+ int signal = 0;
+ std::string kernel_supplied_name;
+
+ if (!ParseCrashAttributes(crash_attributes, &pid, &signal,
+ &kernel_supplied_name)) {
+ logger_->LogError("Invalid parameter: --user=%s", crash_attributes.c_str());
+ return false;
+ }
+
std::string exec;
if (force_exec) {
exec.assign(force_exec);
} else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
- // If for some reason we don't have the base name, avoid completely
- // failing by indicating an unknown name.
- exec = "unknown";
+ // If we cannot find the exec name, use the kernel supplied name.
+ // We don't always use the kernel's since it truncates the name to
+ // 16 characters.
+ exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
}
// Allow us to test the crash reporting mechanism successfully even if
@@ -394,7 +430,7 @@ bool UserCollector::HandleCrash(int signal, int pid, const char *force_exec) {
FLAGS_filter_in != exec)) {
// We use a different format message to make it more obvious in tests
// which crashes are test generated and which are real.
- logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s",
+ logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s.",
exec.c_str(), pid, FLAGS_filter_in.c_str());
return true;
}
@@ -421,7 +457,11 @@ bool UserCollector::HandleCrash(int signal, int pid, const char *force_exec) {
if (generate_diagnostics_) {
bool out_of_capacity = false;
- if (!ConvertAndEnqueueCrash(pid, exec, &out_of_capacity)) {
+ logger_->set_accumulating(true);
+ bool convert_and_enqueue_result =
+ ConvertAndEnqueueCrash(pid, exec, &out_of_capacity);
+ logger_->set_accumulating(false);
+ if (!convert_and_enqueue_result) {
if (!out_of_capacity)
EnqueueCollectionErrorLog(pid, exec);
return false;
« no previous file with comments | « user_collector.h ('k') | user_collector_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698