blob: 24ac3de246ee05f8e25a60e5a9f9d57703a41a32 [file] [log] [blame]
// Copyright 2018 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/selinux_violation_collector.h"
#include <unistd.h>
#include <string>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <base/files/file_enumerator.h>
#include "crash-reporter/test_util.h"
using base::FilePath;
namespace {
bool s_metrics = false;
// Source tree log config file name.
constexpr char kLogConfigFileName[] = "crash_reporter_logs.conf";
constexpr char kTestFilename[] = "test-selinux-violation";
constexpr char kTestCrashDirectory[] = "test-crash-directory";
constexpr char TestSELinuxViolationMessage[] =
"sssss-selinux-init\n"
"comm\001init\002scontext\001context1\002\n"
"SELINUX VIOLATION TRIGGERED FOR init AT context1.\n";
constexpr char TestSELinuxViolationMessageContent[] =
"SELINUX VIOLATION TRIGGERED FOR init AT context1.\n";
bool IsMetrics() {
return s_metrics;
}
void CountCrash() {}
// Returns true if at least one file in this directory matches the pattern.
// found_file_path is not assigned if found_file_path is nullptr.
// Only the first found path is stored into found_file_path.
bool DirectoryHasFileWithPattern(const FilePath& directory,
const std::string& pattern,
FilePath* found_file_path) {
base::FileEnumerator enumerator(
directory, false, base::FileEnumerator::FileType::FILES, pattern);
FilePath path = enumerator.Next();
if (!path.empty() && found_file_path)
*found_file_path = path;
return !path.empty();
}
} // namespace
class SELinuxViolationCollectorMock : public SELinuxViolationCollector {
public:
MOCK_METHOD0(SetUpDBus, void());
};
class SELinuxViolationCollectorTest : public ::testing::Test {
void SetUp() {
s_metrics = true;
EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
collector_.Initialize(CountCrash, IsMetrics);
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
test_path_ = scoped_temp_dir_.GetPath().Append(kTestFilename);
collector_.set_violation_report_path_for_testing(test_path_);
test_crash_directory_ =
scoped_temp_dir_.GetPath().Append(kTestCrashDirectory);
CreateDirectory(test_crash_directory_);
collector_.set_crash_directory_for_test(test_crash_directory_);
collector_.set_log_config_path(kLogConfigFileName);
}
protected:
SELinuxViolationCollectorMock collector_;
base::ScopedTempDir scoped_temp_dir_;
FilePath test_path_;
FilePath test_crash_directory_;
};
TEST_F(SELinuxViolationCollectorTest, CollectOK) {
// Collector produces a violation report.
collector_.set_developer_image_for_testing();
ASSERT_TRUE(test_util::CreateFile(test_path_, TestSELinuxViolationMessage));
EXPECT_TRUE(collector_.Collect());
EXPECT_FALSE(IsDirectoryEmpty(test_crash_directory_));
EXPECT_TRUE(DirectoryHasFileWithPattern(test_crash_directory_,
"selinux_violation.*.meta", NULL));
FilePath file_path;
EXPECT_TRUE(DirectoryHasFileWithPattern(
test_crash_directory_, "selinux_violation.*.log", &file_path));
std::string content;
base::ReadFileToString(file_path, &content);
EXPECT_STREQ(content.c_str(), TestSELinuxViolationMessageContent);
}
TEST_F(SELinuxViolationCollectorTest, CollectSample) {
// Collector produces a violation report.
collector_.set_fake_random_for_statistic_sampling(1);
ASSERT_TRUE(test_util::CreateFile(test_path_, TestSELinuxViolationMessage));
EXPECT_TRUE(collector_.Collect());
EXPECT_FALSE(IsDirectoryEmpty(test_crash_directory_));
EXPECT_TRUE(DirectoryHasFileWithPattern(test_crash_directory_,
"selinux_violation.*.meta", NULL));
FilePath file_path;
EXPECT_TRUE(DirectoryHasFileWithPattern(
test_crash_directory_, "selinux_violation.*.log", &file_path));
std::string content;
base::ReadFileToString(file_path, &content);
EXPECT_STREQ(content.c_str(), TestSELinuxViolationMessageContent);
}
TEST_F(SELinuxViolationCollectorTest, FailureReportDoesNotExist) {
// SELinux violation report file doesn't exist.
EXPECT_TRUE(collector_.Collect());
EXPECT_TRUE(IsDirectoryEmpty(test_crash_directory_));
}
TEST_F(SELinuxViolationCollectorTest, EmptyFailureReport) {
// SELinux violation report file exists, but doesn't have the expected
// contents.
ASSERT_TRUE(test_util::CreateFile(test_path_, ""));
EXPECT_TRUE(collector_.Collect());
EXPECT_TRUE(IsDirectoryEmpty(test_crash_directory_));
}
TEST_F(SELinuxViolationCollectorTest, FeedbackNotAllowed) {
// Feedback not allowed.
s_metrics = false;
ASSERT_TRUE(test_util::CreateFile(test_path_, TestSELinuxViolationMessage));
EXPECT_TRUE(collector_.Collect());
EXPECT_TRUE(IsDirectoryEmpty(test_crash_directory_));
}
TEST_F(SELinuxViolationCollectorTest, DroppedSample) {
// Drop sample.
collector_.set_fake_random_for_statistic_sampling(999);
ASSERT_TRUE(test_util::CreateFile(test_path_, TestSELinuxViolationMessage));
EXPECT_TRUE(collector_.Collect());
EXPECT_TRUE(IsDirectoryEmpty(test_crash_directory_));
}