blob: a39054e3329e6bc3157ced6af08bef9077d656ca [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/arcvm_kernel_collector.h"
#include <fcntl.h>
#include <unistd.h>
#include <memory>
#include <utility>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <gtest/gtest.h>
#include "crash-reporter/test_util.h"
namespace {
constexpr char kTestCrashDirectory[] = "test-crash-directory";
constexpr char kBasenameWithoutExt[] = "arcvm_kernel.20190101.000000.*.0";
constexpr char kExecName[] = "arcvm-kernel";
constexpr time_t kTimestamp = 1546300800;
constexpr char kDevice[] = "Device";
constexpr char kBoard[] = "Board";
constexpr char kCpuAbi[] = "CPUABI";
constexpr char kFingerprint[] = "Fingerprint";
arc_util::BuildProperty GetBuildProperty() {
return {.device = kDevice,
.board = kBoard,
.cpu_abi = kCpuAbi,
.fingerprint = kFingerprint};
}
constexpr char kRamoopsSampleContent[] =
"Panic#1 Part1\n"
"<6>example@google.com shouled be stripped\n"
"<0>[ 246.088355] Kernel panic - not syncing: sysrq triggered crash\n"
"<4>[ 246.089203] CPU: 1 PID: 2536 Comm: sh Not tainted "
"5.4.73-10450-g5f72588ca054 #1\n"
"<4>[ 246.090349] Hardware name: ChromiumOS crosvm, BIOS 0\n"
"<4>[ 246.091050] Call Trace:\n"
"<4>[ 246.091863] dump_stack+0x88/0xcc\n"
"<4>[ 246.092693] panic+0x100/0x2f1\n"
"<4>[ 246.093710] sysrq_handle_crash+0x13/0x13\n"
"<4>[ 246.094467] __handle_sysrq+0x115/0x12f\n"
"<4>[ 246.095142] write_sysrq_trigger+0x35/0x49\n"
"<4>[ 246.095852] proc_reg_write+0x37/0x68\n"
"<4>[ 246.096549] __vfs_write+0x3d/0x199\n"
"<4>[ 246.097311] ? selinux_file_permission+0x8f/0x124\n"
"<4>[ 246.098111] vfs_write+0xea/0x192\n"
"<4>[ 246.098780] ksys_write+0x68/0xc9\n"
"<4>[ 246.099484] do_syscall_64+0x4b/0x74\n"
"<4>[ 246.100151] entry_SYSCALL_64_after_hwframe+0x44/0xa9\n"
"<4>[ 246.101035] RIP: 0033:0x725b4ecba5b7\n"
"<4>[ 246.101617] Code: 00 00 00 b8 00 00 00 00 0f 05 48 3d 01 f0 ff ff 72 "
"09 f7 d8 89 c7 e8 08 fb ff ff c3 0f 1f 80 00 00 00 00 b8 01 00 00 00 0f "
"05 <48> 3d 01 f0 ff ff 72 09 f7 d8 89 c7 e8 e8 fa ff ff c3 0f 1f 80 00\n"
"<4>[ 246.103266] RSP: 002b:00007fffc5925ed8 EFLAGS: 00000217 ORIG_RAX: "
"0000000000000001\n"
"<4>[ 246.104135] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: "
"0000725b4ecba5b7\n"
"<4>[ 246.105117] RDX: 0000000000000002 RSI: 00007259beb72018 RDI: "
"0000000000000001\n"
"<4>[ 246.105924] RBP: 00007259beb72018 R08: ffffffffffffffff R09: "
"000072597eb70368\n"
"<4>[ 246.106966] R10: 00000000fffffe00 R11: 0000000000000217 R12: "
"0000589b639779c0\n"
"<4>[ 246.107815] R13: 00007fffc5925ef0 R14: 00007259eeb75af0 R15: "
"00007fffc5925f28\n"
"<0>[ 246.109609] Kernel Offset: 0x26a00000 from 0xffffffff81000000 "
"(relocation range: 0xffffffff80000000-0xffffffffbfffffff)\n";
constexpr char kKeywordinRamoops[] =
"Kernel panic - not syncing: sysrq triggered crash";
constexpr char kSensitiveDataInRamoops[] = "example@google.com";
} // namespace
class TestArcvmKernelCollector : public ArcvmKernelCollector {
public:
explicit TestArcvmKernelCollector(const base::FilePath& crash_directory) {
Initialize(false /* early */);
set_crash_directory_for_test(crash_directory);
}
~TestArcvmKernelCollector() override = default;
bool HasMetaData(const std::string& key, const std::string& value) const {
const std::string metadata =
base::StringPrintf("%s=%s\n", key.c_str(), value.c_str());
return extra_metadata_.find(metadata) != std::string::npos;
}
private:
void SetUpDBus() override {}
};
class ArcvmKernelCollectorTest : public ::testing::Test {
public:
~ArcvmKernelCollectorTest() override = default;
void SetUp() override {
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
base::FilePath ramoops_path =
scoped_temp_dir_.GetPath().Append("dmesg-ramoops-0");
ASSERT_TRUE(test_util::CreateFile(ramoops_path, kRamoopsSampleContent));
ramoops_stream_ =
base::ScopedFILE(fopen(ramoops_path.value().c_str(), "r"));
ASSERT_TRUE(ramoops_stream_);
test_crash_directory_ =
scoped_temp_dir_.GetPath().Append(kTestCrashDirectory);
ASSERT_TRUE(base::CreateDirectory(test_crash_directory_));
collector_ =
std::make_unique<TestArcvmKernelCollector>(test_crash_directory_);
}
protected:
base::ScopedTempDir scoped_temp_dir_;
base::ScopedFILE ramoops_stream_;
base::FilePath test_crash_directory_;
std::unique_ptr<TestArcvmKernelCollector> collector_;
};
TEST_F(ArcvmKernelCollectorTest, HandleCrashWithRamoopsStreamAndTimestamp) {
ASSERT_TRUE(collector_->HandleCrashWithRamoopsStreamAndTimestamp(
GetBuildProperty(), ramoops_stream_.get(), kTimestamp));
EXPECT_TRUE(test_util::DirectoryHasFileWithPattern(
test_crash_directory_, std::string(kBasenameWithoutExt) + ".meta",
nullptr));
base::FilePath ramoops_path;
ASSERT_TRUE(test_util::DirectoryHasFileWithPattern(
test_crash_directory_, std::string(kBasenameWithoutExt) + ".log",
&ramoops_path));
std::string ramoops_content;
EXPECT_TRUE(base::ReadFileToString(ramoops_path, &ramoops_content));
EXPECT_THAT(ramoops_content, testing::HasSubstr(kKeywordinRamoops));
EXPECT_THAT(ramoops_content,
testing::Not(testing::HasSubstr(kSensitiveDataInRamoops)));
}
TEST_F(ArcvmKernelCollectorTest, AddArcMetadata) {
collector_->AddArcMetadata(GetBuildProperty());
EXPECT_TRUE(collector_->HasMetaData(arc_util::kProcessField, kExecName));
EXPECT_TRUE(
collector_->HasMetaData(arc_util::kProductField, arc_util::kArcProduct));
EXPECT_TRUE(
collector_->HasMetaData(arc_util::kArcVersionField, kFingerprint));
EXPECT_TRUE(collector_->HasMetaData(arc_util::kDeviceField, kDevice));
EXPECT_TRUE(collector_->HasMetaData(arc_util::kBoardField, kBoard));
EXPECT_TRUE(collector_->HasMetaData(arc_util::kCpuAbiField, kCpuAbi));
}