Files
Alicho/tests/unit/plugin_host/sandbox_security_test.cpp
2025-10-28 10:27:49 +08:00

528 lines
18 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ================================================================================================
// Audio Backend - 沙盒安全测试
// ================================================================================================
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "plugin_host/sandbox/sandbox_interface.h"
#include "tests/common/test_fixtures.h"
#include <thread>
#include <chrono>
#include <atomic>
using namespace audio_backend;
using namespace audio_backend::plugin_host;
using namespace std::chrono_literals;
// 创建安全测试用的沙盒实现
class SecurityTestingSandbox : public SandboxBase {
public:
explicit SecurityTestingSandbox() : SandboxBase(SandboxType::ProcessLevelIsolation) {}
~SecurityTestingSandbox() override = default;
// 基本方法实现
common::ErrorCode do_initialize() override { return common::ErrorCode::Success; }
common::ErrorCode do_shutdown() override { return common::ErrorCode::Success; }
common::ErrorCode do_start_process(
const std::string& executable_path,
const std::vector<std::string>& arguments,
ProcessId& out_process_id) override {
out_process_id = next_pid_++;
register_process(out_process_id, executable_path);
return common::ErrorCode::Success;
}
common::ErrorCode do_stop_process(ProcessId process_id, bool force) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
unregister_process(process_id);
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
// 接口方法实现
common::ErrorCode start_process(
const std::string& executable_path,
const std::vector<std::string>& arguments,
ProcessId& out_process_id) override {
return SandboxBase::start_process(executable_path, arguments, out_process_id);
}
common::ErrorCode suspend_process(ProcessId process_id) override {
return common::ErrorCode::Success;
}
common::ErrorCode resume_process(ProcessId process_id) override {
return common::ErrorCode::Success;
}
common::ErrorCode restart_process(ProcessId process_id) override {
return common::ErrorCode::Success;
}
common::ErrorCode wait_for_process(
ProcessId process_id,
std::chrono::milliseconds timeout,
int& exit_code) override {
exit_code = 0;
return common::ErrorCode::Success;
}
common::ErrorCode set_resource_limits(
ProcessId process_id,
const ResourceLimits& limits) override {
return common::ErrorCode::Success;
}
common::ErrorCode get_resource_usage(
ProcessId process_id,
PerformanceMetrics& metrics) override {
return common::ErrorCode::Success;
}
common::ErrorCode enforce_resource_limits(ProcessId process_id) override {
return common::ErrorCode::Success;
}
// 安全管理重点方法
common::ErrorCode apply_security_settings(
ProcessId process_id,
const SecuritySettings& settings) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
security_settings_[process_id] = settings;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
bool is_path_accessible(
ProcessId process_id,
const std::string& path) const override {
auto* process_info = find_process_info(process_id);
if (!process_info) {
return false;
}
// 获取安全设置
auto it = security_settings_.find(process_id);
if (it == security_settings_.end()) {
// 如果没有特定设置,默认不允许访问
return false;
}
const SecuritySettings& settings = it->second;
// 全局文件访问设置
if (!settings.allow_file_access) {
notify_security_violation(process_id, "FileAccess");
return false;
}
// 检查允许的路径
for (const auto& allowed_path : settings.allowed_paths) {
if (path.find(allowed_path) == 0) {
return true;
}
}
// 检查禁止的路径
for (const auto& denied_path : settings.denied_paths) {
if (path.find(denied_path) == 0) {
notify_security_violation(process_id, "PathAccess:" + denied_path);
return false;
}
}
// 如果允许列表不为空,但路径不在允许列表中,则拒绝访问
if (!settings.allowed_paths.empty()) {
notify_security_violation(process_id, "PathNotAllowed:" + path);
return false;
}
// 默认允许访问
return true;
}
bool is_network_accessible(ProcessId process_id) const override {
auto* process_info = find_process_info(process_id);
if (!process_info) {
return false;
}
// 获取安全设置
auto it = security_settings_.find(process_id);
if (it == security_settings_.end()) {
// 如果没有特定设置,默认不允许访问
return false;
}
const SecuritySettings& settings = it->second;
// 全局网络访问设置
if (!settings.allow_network_access) {
notify_security_violation(process_id, "NetworkAccess");
return false;
}
return true;
}
common::ErrorCode execute_platform_specific_operation(
const std::string& operation_name,
const std::vector<std::string>& parameters,
std::string& result) override {
// 检查是否是安全敏感操作
if (operation_name == "AccessRegistry" ||
operation_name == "ModifySystemFiles" ||
operation_name == "AccessDevices") {
// 获取当前进程ID假设是从调用上下文中获取的
ProcessId current_pid = current_operation_pid_;
auto* process_info = find_process_info(current_pid);
if (process_info) {
auto it = security_settings_.find(current_pid);
if (it != security_settings_.end()) {
const SecuritySettings& settings = it->second;
// 检查是否允许系统操作
if (!settings.allow_system_operations) {
notify_security_violation(current_pid, "SystemOperation:" + operation_name);
return common::ErrorCode::SecurityViolation;
}
}
}
}
// 默认实现
result = "操作执行成功";
return common::ErrorCode::Success;
}
// 添加测试辅助方法
const SecuritySettings& get_security_settings(ProcessId process_id) const {
static SecuritySettings empty_settings;
auto it = security_settings_.find(process_id);
if (it != security_settings_.end()) {
return it->second;
}
return empty_settings;
}
void set_current_operation_pid(ProcessId pid) {
current_operation_pid_ = pid;
}
// 获取安全统计信息
size_t get_security_violations_count() const {
return stats_.total_security_violations.load();
}
private:
std::atomic<ProcessId> next_pid_{1000};
mutable std::map<ProcessId, SecuritySettings> security_settings_;
ProcessId current_operation_pid_ = 0; // 当前操作的进程ID
};
// 沙盒安全测试固定装置
class SandboxSecurityTest : public test::PluginSandboxTest {
protected:
void SetUp() override {
test::PluginSandboxTest::SetUp();
// 创建沙盒
sandbox_ = std::make_unique<SecurityTestingSandbox>();
// 创建事件回调
callback_ = std::make_shared<::testing::NiceMock<MockSandboxEventCallback>>();
// 初始化沙盒
SandboxConfig config;
config.sandbox_type = SandboxType::ProcessLevelIsolation;
config.enable_security_monitoring = true;
ASSERT_EQ(sandbox_->initialize(config), common::ErrorCode::Success);
// 设置事件回调
sandbox_->set_event_callback(callback_);
}
void TearDown() override {
if (sandbox_->is_initialized()) {
sandbox_->shutdown();
}
sandbox_.reset();
callback_.reset();
test::PluginSandboxTest::TearDown();
}
// 创建默认安全设置
SecuritySettings create_default_settings() {
SecuritySettings settings;
settings.allow_file_access = true;
settings.allow_network_access = true;
settings.allow_system_operations = false;
settings.allow_registry_access = false;
settings.allow_process_creation = false;
settings.allow_device_access = false;
settings.allowed_paths = {"/app", "./data"};
settings.denied_paths = {"/system", "./config"};
return settings;
}
protected:
std::unique_ptr<SecurityTestingSandbox> sandbox_;
std::shared_ptr<MockSandboxEventCallback> callback_;
};
// 测试应用安全设置
TEST_F(SandboxSecurityTest, ApplySecuritySettings) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建安全设置
SecuritySettings settings = create_default_settings();
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 验证安全设置
const SecuritySettings& applied_settings = sandbox_->get_security_settings(pid);
EXPECT_EQ(applied_settings.allow_file_access, settings.allow_file_access);
EXPECT_EQ(applied_settings.allow_network_access, settings.allow_network_access);
EXPECT_EQ(applied_settings.allow_system_operations, settings.allow_system_operations);
EXPECT_EQ(applied_settings.allowed_paths, settings.allowed_paths);
EXPECT_EQ(applied_settings.denied_paths, settings.denied_paths);
// 测试无效的进程ID
EXPECT_NE(sandbox_->apply_security_settings(999999, settings), common::ErrorCode::Success);
}
// 测试文件访问控制
TEST_F(SandboxSecurityTest, FileAccessControl) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建安全设置
SecuritySettings settings = create_default_settings();
settings.allow_file_access = true;
settings.allowed_paths = {"/app", "./data"};
settings.denied_paths = {"/system", "./config"};
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 测试允许的路径
EXPECT_TRUE(sandbox_->is_path_accessible(pid, "/app/resources"));
EXPECT_TRUE(sandbox_->is_path_accessible(pid, "./data/user"));
// 设置安全事件调用期望
EXPECT_CALL(*callback_, on_security_violation(pid, ::testing::_))
.Times(2);
// 测试禁止的路径
EXPECT_FALSE(sandbox_->is_path_accessible(pid, "/system/bin"));
EXPECT_FALSE(sandbox_->is_path_accessible(pid, "./config/secrets"));
// 测试未指定的路径
EXPECT_TRUE(sandbox_->is_path_accessible(pid, "/tmp/cache"));
// 测试完全禁止文件访问
SecuritySettings no_file_access = settings;
no_file_access.allow_file_access = false;
ASSERT_EQ(sandbox_->apply_security_settings(pid, no_file_access), common::ErrorCode::Success);
// 设置安全事件调用期望
EXPECT_CALL(*callback_, on_security_violation(pid, "FileAccess"))
.Times(1);
// 即使是允许的路径,现在也应该被拒绝
EXPECT_FALSE(sandbox_->is_path_accessible(pid, "/app/resources"));
}
// 测试网络访问控制
TEST_F(SandboxSecurityTest, NetworkAccessControl) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建安全设置,默认允许网络访问
SecuritySettings settings = create_default_settings();
settings.allow_network_access = true;
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 测试网络访问
EXPECT_TRUE(sandbox_->is_network_accessible(pid));
// 禁用网络访问
settings.allow_network_access = false;
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 设置安全事件调用期望
EXPECT_CALL(*callback_, on_security_violation(pid, "NetworkAccess"))
.Times(1);
// 测试网络访问被拒绝
EXPECT_FALSE(sandbox_->is_network_accessible(pid));
}
// 测试系统操作访问控制
TEST_F(SandboxSecurityTest, SystemOperationsControl) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建安全设置,默认禁止系统操作
SecuritySettings settings = create_default_settings();
settings.allow_system_operations = false;
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 设置当前操作进程ID
sandbox_->set_current_operation_pid(pid);
// 设置安全事件调用期望
EXPECT_CALL(*callback_, on_security_violation(pid, ::testing::StartsWith("SystemOperation:")))
.Times(1);
// 尝试执行系统操作
std::string result;
auto err = sandbox_->execute_platform_specific_operation("AccessRegistry", {}, result);
// 应该被拒绝
EXPECT_EQ(err, common::ErrorCode::SecurityViolation);
// 允许系统操作
settings.allow_system_operations = true;
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 再次尝试执行系统操作
err = sandbox_->execute_platform_specific_operation("AccessRegistry", {}, result);
// 现在应该成功
EXPECT_EQ(err, common::ErrorCode::Success);
EXPECT_FALSE(result.empty());
}
// 测试安全违规计数
TEST_F(SandboxSecurityTest, SecurityViolationCounting) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建安全设置
SecuritySettings settings = create_default_settings();
settings.allow_file_access = true;
settings.allow_network_access = false;
settings.allow_system_operations = false;
settings.allowed_paths = {"/app"};
settings.denied_paths = {"/system"};
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 初始违规计数应为0
EXPECT_EQ(sandbox_->get_security_violations_count(), 0);
// 触发网络访问违规
sandbox_->is_network_accessible(pid);
// 违规计数应增加
EXPECT_EQ(sandbox_->get_security_violations_count(), 1);
// 触发文件访问违规
sandbox_->is_path_accessible(pid, "/system/bin");
// 违规计数应再次增加
EXPECT_EQ(sandbox_->get_security_violations_count(), 2);
// 设置当前操作进程ID
sandbox_->set_current_operation_pid(pid);
// 触发系统操作违规
std::string result;
sandbox_->execute_platform_specific_operation("AccessRegistry", {}, result);
// 违规计数应再次增加
EXPECT_EQ(sandbox_->get_security_violations_count(), 3);
}
// 测试多进程安全设置
TEST_F(SandboxSecurityTest, MultiProcessSecuritySettings) {
// 启动多个进程
ProcessId pid1 = 0, pid2 = 0;
ASSERT_EQ(sandbox_->start_process("process1.exe", {}, pid1), common::ErrorCode::Success);
ASSERT_EQ(sandbox_->start_process("process2.exe", {}, pid2), common::ErrorCode::Success);
// 创建不同的安全设置
SecuritySettings settings1 = create_default_settings();
settings1.allow_file_access = true;
settings1.allow_network_access = false;
SecuritySettings settings2 = create_default_settings();
settings2.allow_file_access = false;
settings2.allow_network_access = true;
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid1, settings1), common::ErrorCode::Success);
ASSERT_EQ(sandbox_->apply_security_settings(pid2, settings2), common::ErrorCode::Success);
// 测试文件访问
EXPECT_TRUE(sandbox_->is_path_accessible(pid1, "/app/resources"));
EXPECT_FALSE(sandbox_->is_path_accessible(pid2, "/app/resources"));
// 测试网络访问
EXPECT_FALSE(sandbox_->is_network_accessible(pid1));
EXPECT_TRUE(sandbox_->is_network_accessible(pid2));
}
// 测试安全设置更新
TEST_F(SandboxSecurityTest, UpdateSecuritySettings) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建初始安全设置
SecuritySettings settings = create_default_settings();
settings.allow_file_access = true;
settings.allow_network_access = true;
// 应用安全设置
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 测试初始设置
EXPECT_TRUE(sandbox_->is_path_accessible(pid, "/app/resources"));
EXPECT_TRUE(sandbox_->is_network_accessible(pid));
// 更新安全设置
settings.allow_file_access = false;
settings.allow_network_access = false;
ASSERT_EQ(sandbox_->apply_security_settings(pid, settings), common::ErrorCode::Success);
// 设置安全事件调用期望
EXPECT_CALL(*callback_, on_security_violation(pid, ::testing::_))
.Times(2);
// 测试更新后的设置
EXPECT_FALSE(sandbox_->is_path_accessible(pid, "/app/resources"));
EXPECT_FALSE(sandbox_->is_network_accessible(pid));
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}