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 "kernel_warning_collector.h" 18 19 #include <base/files/file_util.h> 20 #include <base/logging.h> 21 #include <base/strings/string_number_conversions.h> 22 #include <base/strings/string_util.h> 23 #include <base/strings/stringprintf.h> 24 25 namespace { 26 const char kExecName[] = "kernel-warning"; 27 const char kKernelWarningSignatureKey[] = "sig"; 28 const char kKernelWarningPath[] = "/var/run/kwarn/warning"; 29 const pid_t kKernelPid = 0; 30 const uid_t kRootUid = 0; 31 } // namespace 32 33 using base::FilePath; 34 using base::StringPrintf; 35 36 KernelWarningCollector::KernelWarningCollector() { 37 } 38 39 KernelWarningCollector::~KernelWarningCollector() { 40 } 41 42 bool KernelWarningCollector::LoadKernelWarning(std::string *content, 43 std::string *signature) { 44 FilePath kernel_warning_path(kKernelWarningPath); 45 if (!base::ReadFileToString(kernel_warning_path, content)) { 46 LOG(ERROR) << "Could not open " << kKernelWarningPath; 47 return false; 48 } 49 // The signature is in the first line. 50 std::string::size_type end_position = content->find('\n'); 51 if (end_position == std::string::npos) { 52 LOG(ERROR) << "unexpected kernel warning format"; 53 return false; 54 } 55 *signature = content->substr(0, end_position); 56 return true; 57 } 58 59 bool KernelWarningCollector::Collect() { 60 std::string reason = "normal collection"; 61 bool feedback = true; 62 if (IsDeveloperImage()) { 63 reason = "always collect from developer builds"; 64 feedback = true; 65 } else if (!is_feedback_allowed_function_()) { 66 reason = "no user consent"; 67 feedback = false; 68 } 69 70 LOG(INFO) << "Processing kernel warning: " << reason; 71 72 if (!feedback) { 73 return true; 74 } 75 76 std::string kernel_warning; 77 std::string warning_signature; 78 if (!LoadKernelWarning(&kernel_warning, &warning_signature)) { 79 return true; 80 } 81 82 FilePath root_crash_directory; 83 if (!GetCreatedCrashDirectoryByEuid(kRootUid, &root_crash_directory, 84 nullptr)) { 85 return true; 86 } 87 88 std::string dump_basename = 89 FormatDumpBasename(kExecName, time(nullptr), kKernelPid); 90 FilePath kernel_crash_path = root_crash_directory.Append( 91 StringPrintf("%s.kcrash", dump_basename.c_str())); 92 93 // We must use WriteNewFile instead of base::WriteFile as we 94 // do not want to write with root access to a symlink that an attacker 95 // might have created. 96 if (WriteNewFile(kernel_crash_path, 97 kernel_warning.data(), 98 kernel_warning.length()) != 99 static_cast<int>(kernel_warning.length())) { 100 LOG(INFO) << "Failed to write kernel warning to " 101 << kernel_crash_path.value().c_str(); 102 return true; 103 } 104 105 AddCrashMetaData(kKernelWarningSignatureKey, warning_signature); 106 WriteCrashMetaData( 107 root_crash_directory.Append( 108 StringPrintf("%s.meta", dump_basename.c_str())), 109 kExecName, kernel_crash_path.value()); 110 111 LOG(INFO) << "Stored kernel warning into " << kernel_crash_path.value(); 112 return true; 113 } 114