blob: 7712c1c785db1fdae1faa8795caa929403be55a7 [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "dlp/fanotify_watcher.h"
#include <memory>
#include <sys/fanotify.h>
#include <utility>
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback.h"
#include "base/test/task_environment.h"
#include "gtest/gtest.h"
namespace dlp {
namespace {
constexpr int kInode = 1;
constexpr time_t kCrtime = 2;
constexpr int kPid = 3;
} // namespace
class FanotifyWatcherTest : public ::testing::Test,
public FanotifyWatcher::Delegate {
public:
FanotifyWatcherTest() = default;
FanotifyWatcherTest(const FanotifyWatcherTest&) = delete;
FanotifyWatcherTest& operator=(const FanotifyWatcherTest&) = delete;
~FanotifyWatcherTest() override = default;
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(base::CreatePipe(&perm_fd_out_, &perm_fd_in_));
watcher_ = std::make_unique<FanotifyWatcher>(this, perm_fd_in_.release(),
/*fanotify_notif_fd=*/-1);
}
void ProcessFileOpenRequest(
FileId id, int pid, base::OnceCallback<void(bool)> callback) override {
EXPECT_EQ(id.first, kInode);
EXPECT_EQ(id.second, kCrtime);
EXPECT_EQ(pid, kPid);
counter_++;
std::move(callback).Run(file_open_allowed_);
}
void OnFileDeleted(ino64_t inode) override {
// Not expected to be called.
FAIL();
};
void OnFanotifyError(FanotifyError error) override {
// Not expected to be called.
FAIL();
};
bool SimulateFileOpen(int expected_counter) {
base::FilePath temp_file;
base::ScopedFD file_fd = base::CreateAndOpenFdForTemporaryFileInDir(
temp_dir_.GetPath(), &temp_file);
const int fd = file_fd.get();
watcher_->OnFileOpenRequested(
kInode, kCrtime, kPid, std::move(file_fd),
std::make_unique<FanotifyReaderThread::FanotifyReplyWatchdog>());
EXPECT_EQ(counter_, expected_counter);
struct fanotify_response response = {};
HANDLE_EINTR(read(perm_fd_out_.get(), &response, sizeof(response)));
EXPECT_EQ(response.fd, fd);
return response.response == FAN_ALLOW;
}
protected:
base::test::TaskEnvironment task_environment_;
bool file_open_allowed_ = true;
std::unique_ptr<FanotifyWatcher> watcher_;
private:
uint32_t counter_ = 0;
base::ScopedTempDir temp_dir_;
base::ScopedFD perm_fd_in_, perm_fd_out_;
};
TEST_F(FanotifyWatcherTest, FileOpen) {
int requests_counter = 0;
file_open_allowed_ = true;
// Allowed when not active.
EXPECT_TRUE(SimulateFileOpen(requests_counter));
// Allowed when processed.
watcher_->SetActive(true);
requests_counter++;
EXPECT_TRUE(SimulateFileOpen(requests_counter));
// Allowed when disactivated.
watcher_->SetActive(false);
EXPECT_TRUE(SimulateFileOpen(requests_counter));
// Not allowed when processed.
file_open_allowed_ = false;
watcher_->SetActive(true);
requests_counter++;
EXPECT_FALSE(SimulateFileOpen(requests_counter));
// Allowed when disactivated again.
watcher_->SetActive(false);
EXPECT_TRUE(SimulateFileOpen(requests_counter));
}
} // namespace dlp