blob: f8188c7fbc89714a9abc913f4c2878480e9c4254 [file] [log] [blame]
Luigi Semenzato6fdc0b42013-04-11 17:22:13 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "crash-reporter/kernel_warning_collector.h"
6
7#include "base/file_util.h"
8#include "base/logging.h"
Mike Frysingera557c112014-02-05 22:55:39 -05009#include "base/strings/string_number_conversions.h"
10#include "base/strings/string_util.h"
11#include "base/strings/stringprintf.h"
Luigi Semenzato6fdc0b42013-04-11 17:22:13 -070012
13namespace {
14const char kExecName[] = "kernel-warning";
15const char kKernelWarningSignatureKey[] = "sig";
16const char kKernelWarningPath[] = "/var/run/kwarn/warning";
17const pid_t kKernelPid = 0;
18const uid_t kRootUid = 0;
19} // namespace
20
Mike Frysingera557c112014-02-05 22:55:39 -050021using base::FilePath;
22using base::StringPrintf;
23
Luigi Semenzato6fdc0b42013-04-11 17:22:13 -070024KernelWarningCollector::KernelWarningCollector() {
25}
26
27KernelWarningCollector::~KernelWarningCollector() {
28}
29
30bool KernelWarningCollector::LoadKernelWarning(std::string *content,
31 std::string *hash_string) {
32 FilePath kernel_warning_path(kKernelWarningPath);
Mike Frysingera557c112014-02-05 22:55:39 -050033 if (!base::ReadFileToString(kernel_warning_path, content)) {
Luigi Semenzato6fdc0b42013-04-11 17:22:13 -070034 LOG(ERROR) << "Could not open " << kKernelWarningPath;
35 return false;
36 }
37 /* Verify that the first line contains an 8-digit hex hash. */
38 *hash_string = content->substr(0, 8);
39 std::vector<uint8> output;
40 if (!base::HexStringToBytes(*hash_string, &output)) {
41 LOG(ERROR) << "Bad hash " << *hash_string << " in " << kKernelWarningPath;
42 return false;
43 }
44 return true;
45}
46
47bool KernelWarningCollector::Collect() {
48 std::string reason = "normal collection";
49 bool feedback = true;
50 if (IsDeveloperImage()) {
51 reason = "always collect from developer builds";
52 feedback = true;
53 } else if (!is_feedback_allowed_function_()) {
54 reason = "no user consent";
55 feedback = false;
56 }
57
58 LOG(INFO) << "Processing kernel warning: " << reason;
59
60 if (!feedback) {
61 return true;
62 }
63
64 std::string kernel_warning;
65 std::string warning_hash;
66 if (!LoadKernelWarning(&kernel_warning, &warning_hash)) {
67 return true;
68 }
69
70 FilePath root_crash_directory;
71 if (!GetCreatedCrashDirectoryByEuid(kRootUid, &root_crash_directory, NULL)) {
72 return true;
73 }
74
75 std::string dump_basename =
76 FormatDumpBasename(kExecName, time(NULL), kKernelPid);
77 FilePath kernel_crash_path = root_crash_directory.Append(
78 StringPrintf("%s.kcrash", dump_basename.c_str()));
79
80 // We must use WriteNewFile instead of file_util::WriteFile as we
81 // do not want to write with root access to a symlink that an attacker
82 // might have created.
83 if (WriteNewFile(kernel_crash_path,
84 kernel_warning.data(),
85 kernel_warning.length()) !=
86 static_cast<int>(kernel_warning.length())) {
87 LOG(INFO) << "Failed to write kernel warning to "
88 << kernel_crash_path.value().c_str();
89 return true;
90 }
91
92 AddCrashMetaData(kKernelWarningSignatureKey, warning_hash);
93 WriteCrashMetaData(
94 root_crash_directory.Append(
95 StringPrintf("%s.meta", dump_basename.c_str())),
96 kExecName, kernel_crash_path.value());
97
98 LOG(INFO) << "Stored kernel warning into " << kernel_crash_path.value();
99 return true;
100}