| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crash-reporter/kernel_collector.h" | 5 #include "crash-reporter/kernel_collector.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "crash-reporter/system_logging.h" | |
| 11 | 10 |
| 12 const char KernelCollector::kClearingSequence[] = " "; | 11 const char KernelCollector::kClearingSequence[] = " "; |
| 13 static const char kDefaultKernelStackSignature[] = | 12 static const char kDefaultKernelStackSignature[] = |
| 14 "kernel-UnspecifiedStackSignature"; | 13 "kernel-UnspecifiedStackSignature"; |
| 15 static const char kKernelExecName[] = "kernel"; | 14 static const char kKernelExecName[] = "kernel"; |
| 16 const pid_t kKernelPid = 0; | 15 const pid_t kKernelPid = 0; |
| 17 static const char kKernelSignatureKey[] = "sig"; | 16 static const char kKernelSignatureKey[] = "sig"; |
| 18 // Byte length of maximum human readable portion of a kernel crash signature. | 17 // Byte length of maximum human readable portion of a kernel crash signature. |
| 19 static const int kMaxHumanStringLength = 40; | 18 static const int kMaxHumanStringLength = 40; |
| 20 static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash"; | 19 static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash"; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 34 } | 33 } |
| 35 | 34 |
| 36 void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) { | 35 void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) { |
| 37 preserved_dump_path_ = file_path; | 36 preserved_dump_path_ = file_path; |
| 38 } | 37 } |
| 39 | 38 |
| 40 bool KernelCollector::LoadPreservedDump(std::string *contents) { | 39 bool KernelCollector::LoadPreservedDump(std::string *contents) { |
| 41 // clear contents since ReadFileToString actually appends to the string. | 40 // clear contents since ReadFileToString actually appends to the string. |
| 42 contents->clear(); | 41 contents->clear(); |
| 43 if (!file_util::ReadFileToString(preserved_dump_path_, contents)) { | 42 if (!file_util::ReadFileToString(preserved_dump_path_, contents)) { |
| 44 logger_->LogError("Unable to read %s", | 43 LOG(ERROR) << "Unable to read " << preserved_dump_path_.value(); |
| 45 preserved_dump_path_.value().c_str()); | |
| 46 return false; | 44 return false; |
| 47 } | 45 } |
| 48 return true; | 46 return true; |
| 49 } | 47 } |
| 50 | 48 |
| 51 bool KernelCollector::Enable() { | 49 bool KernelCollector::Enable() { |
| 52 if (!file_util::PathExists(preserved_dump_path_)) { | 50 if (!file_util::PathExists(preserved_dump_path_)) { |
| 53 logger_->LogWarning("Kernel does not support crash dumping"); | 51 LOG(WARNING) << "Kernel does not support crash dumping"; |
| 54 return false; | 52 return false; |
| 55 } | 53 } |
| 56 | 54 |
| 57 // To enable crashes, we will eventually need to set | 55 // To enable crashes, we will eventually need to set |
| 58 // the chnv bit in BIOS, but it does not yet work. | 56 // the chnv bit in BIOS, but it does not yet work. |
| 59 logger_->LogInfo("Enabling kernel crash handling"); | 57 LOG(INFO) << "Enabling kernel crash handling"; |
| 60 is_enabled_ = true; | 58 is_enabled_ = true; |
| 61 return true; | 59 return true; |
| 62 } | 60 } |
| 63 | 61 |
| 64 bool KernelCollector::ClearPreservedDump() { | 62 bool KernelCollector::ClearPreservedDump() { |
| 65 // It is necessary to write at least one byte to the kcrash file for | 63 // It is necessary to write at least one byte to the kcrash file for |
| 66 // the log to actually be cleared. | 64 // the log to actually be cleared. |
| 67 if (file_util::WriteFile( | 65 if (file_util::WriteFile( |
| 68 preserved_dump_path_, | 66 preserved_dump_path_, |
| 69 kClearingSequence, | 67 kClearingSequence, |
| 70 strlen(kClearingSequence)) != strlen(kClearingSequence)) { | 68 strlen(kClearingSequence)) != strlen(kClearingSequence)) { |
| 71 logger_->LogError("Failed to clear kernel crash dump"); | 69 LOG(ERROR) << "Failed to clear kernel crash dump"; |
| 72 return false; | 70 return false; |
| 73 } | 71 } |
| 74 logger_->LogInfo("Cleared kernel crash diagnostics"); | 72 LOG(INFO) << "Cleared kernel crash diagnostics"; |
| 75 return true; | 73 return true; |
| 76 } | 74 } |
| 77 | 75 |
| 78 // Hash a string to a number. We define our own hash function to not | 76 // Hash a string to a number. We define our own hash function to not |
| 79 // be dependent on a C++ library that might change. This function | 77 // be dependent on a C++ library that might change. This function |
| 80 // uses basically the same approach as tr1/functional_hash.h but with | 78 // uses basically the same approach as tr1/functional_hash.h but with |
| 81 // a larger prime number (16127 vs 131). | 79 // a larger prime number (16127 vs 131). |
| 82 static unsigned HashString(const std::string &input) { | 80 static unsigned HashString(const std::string &input) { |
| 83 unsigned hash = 0; | 81 unsigned hash = 0; |
| 84 for (size_t i = 0; i < input.length(); ++i) | 82 for (size_t i = 0; i < input.length(); ++i) |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 if (kernel_dump.empty()) { | 247 if (kernel_dump.empty()) { |
| 250 return false; | 248 return false; |
| 251 } | 249 } |
| 252 std::string signature; | 250 std::string signature; |
| 253 if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) { | 251 if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) { |
| 254 signature = kDefaultKernelStackSignature; | 252 signature = kDefaultKernelStackSignature; |
| 255 } | 253 } |
| 256 | 254 |
| 257 bool feedback = is_feedback_allowed_function_(); | 255 bool feedback = is_feedback_allowed_function_(); |
| 258 | 256 |
| 259 logger_->LogInfo("Received prior crash notification from " | 257 LOG(INFO) << "Received prior crash notification from " |
| 260 "kernel (signature %s) (%s)", | 258 << "kernel (signature " << signature << ") (" |
| 261 signature.c_str(), | 259 << (feedback ? "handling" : "ignoring - no consent") << ")"; |
| 262 feedback ? "handling" : "ignoring - no consent"); | |
| 263 | 260 |
| 264 if (feedback) { | 261 if (feedback) { |
| 265 count_crash_function_(); | 262 count_crash_function_(); |
| 266 | 263 |
| 267 if (!GetCreatedCrashDirectoryByEuid(kRootUid, | 264 if (!GetCreatedCrashDirectoryByEuid(kRootUid, |
| 268 &root_crash_directory, | 265 &root_crash_directory, |
| 269 NULL)) { | 266 NULL)) { |
| 270 return true; | 267 return true; |
| 271 } | 268 } |
| 272 | 269 |
| 273 std::string dump_basename = | 270 std::string dump_basename = |
| 274 FormatDumpBasename(kKernelExecName, | 271 FormatDumpBasename(kKernelExecName, |
| 275 time(NULL), | 272 time(NULL), |
| 276 kKernelPid); | 273 kKernelPid); |
| 277 FilePath kernel_crash_path = root_crash_directory.Append( | 274 FilePath kernel_crash_path = root_crash_directory.Append( |
| 278 StringPrintf("%s.kcrash", dump_basename.c_str())); | 275 StringPrintf("%s.kcrash", dump_basename.c_str())); |
| 279 | 276 |
| 280 // We must use WriteNewFile instead of file_util::WriteFile as we | 277 // We must use WriteNewFile instead of file_util::WriteFile as we |
| 281 // do not want to write with root access to a symlink that an attacker | 278 // do not want to write with root access to a symlink that an attacker |
| 282 // might have created. | 279 // might have created. |
| 283 if (WriteNewFile(kernel_crash_path, | 280 if (WriteNewFile(kernel_crash_path, |
| 284 kernel_dump.data(), | 281 kernel_dump.data(), |
| 285 kernel_dump.length()) != | 282 kernel_dump.length()) != |
| 286 static_cast<int>(kernel_dump.length())) { | 283 static_cast<int>(kernel_dump.length())) { |
| 287 logger_->LogInfo("Failed to write kernel dump to %s", | 284 LOG(INFO) << "Failed to write kernel dump to " |
| 288 kernel_crash_path.value().c_str()); | 285 << kernel_crash_path.value().c_str(); |
| 289 return true; | 286 return true; |
| 290 } | 287 } |
| 291 | 288 |
| 292 AddCrashMetaData(kKernelSignatureKey, signature); | 289 AddCrashMetaData(kKernelSignatureKey, signature); |
| 293 WriteCrashMetaData( | 290 WriteCrashMetaData( |
| 294 root_crash_directory.Append( | 291 root_crash_directory.Append( |
| 295 StringPrintf("%s.meta", dump_basename.c_str())), | 292 StringPrintf("%s.meta", dump_basename.c_str())), |
| 296 kKernelExecName, | 293 kKernelExecName, |
| 297 kernel_crash_path.value()); | 294 kernel_crash_path.value()); |
| 298 | 295 |
| 299 logger_->LogInfo("Stored kcrash to %s", | 296 LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value(); |
| 300 kernel_crash_path.value().c_str()); | |
| 301 } | 297 } |
| 302 if (!ClearPreservedDump()) { | 298 if (!ClearPreservedDump()) { |
| 303 return false; | 299 return false; |
| 304 } | 300 } |
| 305 | 301 |
| 306 return true; | 302 return true; |
| 307 } | 303 } |
| OLD | NEW |