| 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 |