Skip to content

Commit

Permalink
modify security eBPF probe parameter for process & file (#1693)
Browse files Browse the repository at this point in the history
* modify security eBPF probe parameter for process & file and add callname check

* fix

* fix

* 1. CallName -> CallNameFilter
2. Adjust boundary behavior

* fix

* fix: modify exception behaviour and add logic of callname merge

* fix

* fix

* fix

* fix
  • Loading branch information
alph00 authored Aug 26, 2024
1 parent f8cec6e commit 6afb77b
Show file tree
Hide file tree
Showing 16 changed files with 689 additions and 663 deletions.
52 changes: 52 additions & 0 deletions core/common/ParamExtractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,58 @@ bool GetOptionalListParam(const Json::Value& config,
return true;
}

template <class T>
bool GetOptionalListFilterParam(const Json::Value& config,
const std::string& key,
std::vector<T>& param,
std::string& errorMsg) {
errorMsg.clear();
std::string currentKey = ExtractCurrentKey(key);
const Json::Value* itr = config.find(currentKey.c_str(), currentKey.c_str() + currentKey.length());
if (itr) {
if (!itr->isArray()) {
errorMsg = "param " + key + " is not of type list";
return false;
}
for (auto it = itr->begin(); it != itr->end(); ++it) {
if constexpr (std::is_same_v<T, bool>) {
if (!it->isBool()) {
errorMsg = "element in list param " + key + " is not of type bool";
param.clear();
return false;
}
param.emplace_back(it->asBool());
} else if constexpr (std::is_same_v<T, uint32_t>) {
if (!it->isUInt()) {
errorMsg = "element in list param " + key + " is not of type uint";
param.clear();
return false;
}
param.emplace_back(it->asUInt());
} else if constexpr (std::is_same_v<T, int32_t>) {
if (!it->isInt()) {
errorMsg = "element in list param " + key + " is not of type int";
param.clear();
return false;
}
param.emplace_back(it->asInt());
} else if constexpr (std::is_same_v<T, std::string>) {
if (!it->isString()) {
errorMsg = "element in list param " + key + " is not of type string";
param.clear();
return false;
}
param.emplace_back(it->asString());
} else {
errorMsg = "element in list param " + key + " is not supported";
param.clear();
return false;
}
}
}
return true;
}

template <class T>
bool GetOptionalMapParam(const Json::Value& config,
const std::string& key,
Expand Down
519 changes: 237 additions & 282 deletions core/ebpf/config.cpp

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions core/ebpf/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ bool InitObserverNetworkOption(const Json::Value& config,

///////////////////// /////////////////////

enum class SecurityFilterType { PROCESS, FILE, NETWORK };
enum class SecurityProbeType { PROCESS, FILE, NETWORK, MAX };

class SecurityOptions {
public:
bool Init(SecurityFilterType filterType,
bool Init(SecurityProbeType filterType,
const Json::Value& config,
const PipelineContext* mContext,
const std::string& sName);

std::vector<nami::SecurityOption> mOptionList;
SecurityFilterType mFilterType;
SecurityProbeType mProbeType;
};

///////////////////// Process Level Config /////////////////////
Expand Down
34 changes: 3 additions & 31 deletions core/ebpf/include/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,37 +153,9 @@ struct ObserverNetworkOption {
};

// file
struct SecurityFileFilterItem {
std::string mFilePath = "";
std::string mFileName = "";
bool operator==(const SecurityFileFilterItem& other) const {
return mFilePath == other.mFilePath && mFileName == other.mFileName;
}
};
struct SecurityFileFilter {
std::vector<SecurityFileFilterItem> mFileFilterItem;
bool operator==(const SecurityFileFilter& other) const {
return mFileFilterItem == other.mFileFilterItem;
}
};

// process
struct SecurityProcessNamespaceFilter {
// type of securityNamespaceFilter
std::string mNamespaceType = "";
std::vector<std::string> mValueList;
bool operator==(const SecurityProcessNamespaceFilter& other) const {
return mNamespaceType == other.mNamespaceType &&
mValueList == other.mValueList;
}
};
struct SecurityProcessFilter {
std::vector<SecurityProcessNamespaceFilter> mNamespaceFilter;
std::vector<SecurityProcessNamespaceFilter> mNamespaceBlackFilter;
bool operator==(const SecurityProcessFilter& other) const {
return mNamespaceFilter == other.mNamespaceFilter &&
mNamespaceBlackFilter == other.mNamespaceBlackFilter;
}
std::vector<std::string> mFilePathList;
bool operator==(const SecurityFileFilter& other) const { return mFilePathList == other.mFilePathList; }
};

// network
Expand All @@ -210,7 +182,7 @@ struct SecurityNetworkFilter {

struct SecurityOption {
std::vector<std::string> call_names_;
std::variant<SecurityFileFilter, SecurityNetworkFilter, SecurityProcessFilter> filter_;
std::variant<std::monostate, SecurityFileFilter, SecurityNetworkFilter> filter_;
bool operator==(const SecurityOption& other) const {
return call_names_ == other.call_names_ &&
filter_ == other.filter_;
Expand Down
2 changes: 1 addition & 1 deletion core/input/InputEBPFFileSecurity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ bool InputEBPFFileSecurity::Init(const Json::Value& config, Json::Value& optiona
LOG_WARNING(sLogger, ("pipeline already loaded", "FILE_SECURITY")("prev pipeline", prev_pipeline_name)("curr pipeline", pipeline_name));
return false;
}
return mSecurityOptions.Init(ebpf::SecurityFilterType::FILE, config, mContext, sName);
return mSecurityOptions.Init(ebpf::SecurityProbeType::FILE, config, mContext, sName);
}

bool InputEBPFFileSecurity::Start() {
Expand Down
2 changes: 1 addition & 1 deletion core/input/InputEBPFNetworkSecurity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ bool InputEBPFNetworkSecurity::Init(const Json::Value& config, Json::Value& opti
return false;
}

return mSecurityOptions.Init(ebpf::SecurityFilterType::NETWORK, config, mContext, sName);
return mSecurityOptions.Init(ebpf::SecurityProbeType::NETWORK, config, mContext, sName);
}

bool InputEBPFNetworkSecurity::Start() {
Expand Down
2 changes: 1 addition & 1 deletion core/input/InputEBPFProcessSecurity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ bool InputEBPFProcessSecurity::Init(const Json::Value& config, Json::Value& opti
LOG_WARNING(sLogger, ("pipeline already loaded", "PROCESS_SECURITY")("prev pipeline", prev_pipeline_name)("curr pipeline", pipeline_name));
return false;
}
return mSecurityOptions.Init(ebpf::SecurityFilterType::PROCESS, config, mContext, sName);
return mSecurityOptions.Init(ebpf::SecurityProbeType::PROCESS, config, mContext, sName);
}

bool InputEBPFProcessSecurity::Start() {
Expand Down
62 changes: 21 additions & 41 deletions core/unittest/ebpf/eBPFServerUnittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,31 +574,23 @@ void eBPFServerUnittest::TestEnableProcessPlugin() {
"Type": "input_ebpf_processprobe_security",
"ProbeConfig": [
{
"NamespaceFilter": [
{
"NamespaceType": "Pid",
"ValueList": [
"4026531833"
]
},
{
"NamespaceType": "Mnt",
"ValueList": [
"4026531834"
]
}
"CallNameFilter": [
"sys_enter_execve",
"disassociate_ctty",
"acct_process",
"wake_up_new_task"
]
}
]
}
)";

std::string errorMsg;
Json::Value configJson;
APSARA_TEST_TRUE(ParseJsonTable(configStr, configJson, errorMsg));
std::cout << "1" << std::endl;
SecurityOptions security_options;
security_options.Init(SecurityFilterType::PROCESS, configJson, &ctx, "input_ebpf_processprobe_security");
security_options.Init(SecurityProbeType::PROCESS, configJson, &ctx, "input_ebpf_processprobe_security");
bool res = ebpf::eBPFServer::GetInstance()->EnablePlugin(
"test", 0,
nami::PluginType::PROCESS_SECURITY,
Expand All @@ -612,11 +604,7 @@ void eBPFServerUnittest::TestEnableProcessPlugin() {
EXPECT_TRUE(process_conf.process_security_cb_ != nullptr);
LOG_WARNING(sLogger, ("process_conf.options_ size", process_conf.options_.size()));
EXPECT_EQ(process_conf.options_.size(), 1);
EXPECT_EQ(process_conf.options_[0].call_names_.size(), 0);
auto filter = std::get<nami::SecurityProcessFilter>(process_conf.options_[0].filter_);
LOG_WARNING(sLogger, ("get filter", filter.mNamespaceFilter.size()));
EXPECT_EQ(filter.mNamespaceFilter.size(), 2);
EXPECT_EQ(filter.mNamespaceBlackFilter.size(), 0);
EXPECT_EQ(process_conf.options_[0].call_names_.size(), 4);

// do suspend
ebpf::eBPFServer::GetInstance()->SuspendPlugin("test", nami::PluginType::PROCESS_SECURITY);
Expand Down Expand Up @@ -646,7 +634,7 @@ void eBPFServerUnittest::TestEnableNetworkSecurePlugin() {
"Type": "input_ebpf_sockettraceprobe_security",
"ProbeConfig": [
{
"CallName": ["tcp_connect", "tcp_close"],
"CallNameFilter": ["tcp_connect", "tcp_close"],
"AddrFilter": {
"DestAddrList": ["10.0.0.0/8","92.168.0.0/16"],
"DestPortList": [80],
Expand All @@ -655,7 +643,7 @@ void eBPFServerUnittest::TestEnableNetworkSecurePlugin() {
}
},
{
"CallName": ["tcp_sendmsg"],
"CallNameFilter": ["tcp_sendmsg"],
"AddrFilter": {
"DestAddrList": ["10.0.0.0/8","92.168.0.0/16"],
"DestPortList": [80]
Expand All @@ -669,7 +657,7 @@ void eBPFServerUnittest::TestEnableNetworkSecurePlugin() {
Json::Value configJson;
APSARA_TEST_TRUE(ParseJsonTable(configStr, configJson, errorMsg));
SecurityOptions security_options;
security_options.Init(SecurityFilterType::NETWORK, configJson, &ctx, "input_ebpf_sockettraceprobe_security");
security_options.Init(SecurityProbeType::NETWORK, configJson, &ctx, "input_ebpf_sockettraceprobe_security");
bool res = ebpf::eBPFServer::GetInstance()->EnablePlugin(
"input_ebpf_sockettraceprobe_security", 5,
nami::PluginType::NETWORK_SECURITY,
Expand Down Expand Up @@ -718,37 +706,29 @@ void eBPFServerUnittest::TestEnableFileSecurePlugin() {
"Type": "input_ebpf_fileprobe_security",
"ProbeConfig": [
{
"CallName": ["security_file_permission"],
"CallNameFilter": ["security_file_permission"],
"FilePathFilter": [
{
"FilePath": "/etc",
"FileName": "passwd"
},
{
"FilePath": "/etc",
"FileName": "shadow"
},
{
"FilePath": "/bin"
}
"/etc/passwd",
"/etc/shadow",
"/bin"
]
}
]
}
)";

std::string errorMsg;
Json::Value configJson;
APSARA_TEST_TRUE(ParseJsonTable(configStr, configJson, errorMsg));
std::cout << "1" << std::endl;
SecurityOptions security_options;
security_options.Init(SecurityFilterType::FILE, configJson, &ctx, "input_ebpf_fileprobe_security");
security_options.Init(SecurityProbeType::FILE, configJson, &ctx, "input_ebpf_fileprobe_security");
bool res = ebpf::eBPFServer::GetInstance()->EnablePlugin(
"input_ebpf_fileprobe_security", 0,
nami::PluginType::FILE_SECURITY,
&ctx,
&security_options);
EXPECT_EQ(std::get<nami::SecurityFileFilter>(security_options.mOptionList[0].filter_).mFileFilterItem.size(), 3);
EXPECT_EQ(std::get<nami::SecurityFileFilter>(security_options.mOptionList[0].filter_).mFilePathList.size(), 3);
EXPECT_TRUE(res);
auto conf = ebpf::eBPFServer::GetInstance()->mSourceManager->mConfig;
EXPECT_EQ(conf->plugin_type_, nami::PluginType::FILE_SECURITY);
Expand All @@ -758,9 +738,9 @@ void eBPFServerUnittest::TestEnableFileSecurePlugin() {
EXPECT_EQ(inner_conf.options_.size(), 1);
EXPECT_EQ(inner_conf.options_[0].call_names_.size(), 1);
auto filter = std::get<nami::SecurityFileFilter>(inner_conf.options_[0].filter_);
EXPECT_EQ(filter.mFileFilterItem.size(), 3);
EXPECT_EQ(filter.mFileFilterItem[0].mFileName, "passwd");
EXPECT_EQ(filter.mFileFilterItem[0].mFilePath, "/etc");
EXPECT_EQ(filter.mFilePathList.size(), 3);
EXPECT_EQ(filter.mFilePathList[0], "/etc/passwd");
EXPECT_EQ(filter.mFilePathList[1], "/etc/shadow");

// do suspend
ebpf::eBPFServer::GetInstance()->SuspendPlugin("test", nami::PluginType::FILE_SECURITY);
Expand Down
Loading

0 comments on commit 6afb77b

Please sign in to comment.