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