8000 [WIP] file security by xiongyunn · Pull Request #2292 · alibaba/loongcollector · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[WIP] file security #2292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d6b5fc1
[WIP]file security
yyuuttaaoo Apr 18, 2025 8000
5abc5b1
Merge remote-tracking branch 'xunfei/dev/file_security'
xiongyunn Jun 6, 2025
a86f2fd
add eBPF functionality to collect file read and write operations
xiongyunn Jun 27, 2025
1f84a54
feat: add instance labels into host monitor metrics (#2226)
Abingcbc Jun 6, 2025
6f7547a
feat: support send multivalue metrics to sls (#2233)
Abingcbc Jun 9, 2025
5133712
Fix: JsonLogFileReader may cause a crash due to buffer overflow durin…
Takuka0311 Jun 10, 2025
600a48a
add e2e framework code for eBPF process collection (#2250)
xiongyunn Jun 10, 2025
38414b3
feat: provide common cache for system information (#2212)
Abingcbc Jun 10, 2025
3f6aca0
trim meaningless \0 when reading file (#2251)
yyuuttaaoo Jun 11, 2025
9cfb983
Unify the file path formatting in container meta information into one…
linrunqi08 Jun 13, 2025
a49f15c
Disable process security local container meta (#2255)
yyuuttaaoo Jun 13, 2025
d944ead
Feat: upgrade go version from 1.19.10 to 1.23.10 (#2254)
Takuka0311 Jun 16, 2025
ead3545
Revert "Feat: upgrade go version from 1.19.10 to 1.23.10 (#2254)" (#2…
Takuka0311 Jun 19, 2025
80a47ba
feat: add system collector (#2231)
WRPStephanie Jun 19, 2025
5430d93
feat: loongcollector support windows build (#2082)
bilosikia Jun 24, 2025
57051d9
fix docker inspect timeout (#2269)
Takuka0311 Jun 26, 2025
20cd54c
Refactor eBPF Server thread model (#2273)
yyuuttaaoo Jun 26, 2025
f1669bd
Fix: Selfmonitor crash when DoSnapshot (#2262)
Takuka0311 Jun 26, 2025
1af26fa
[WIP]file security
yyuuttaaoo Apr 18, 2025
4785ba0
add eBPF functionality to collect file read and write operations
xiongyunn Jun 27, 2025
7fb02bf
feat: loongcollector support windows build (#2082)
bilosikia Jun 24, 2025
54889e9
Merge branch 'alibaba-main'
xiongyunn Jun 27, 2025
abb8679
fix data loss issues
xiongyunn Jun 30, 2025
a779766
Merge pull request #2 from alibaba/main
xiongyunn Jun 30, 2025
3bc6a2d
fix plugin type update issue
xiongyunn Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions core/collection_pipeline/plugin/PluginRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "plugin/input/InputNetworkObserver.h"
#include "plugin/input/InputNetworkSecurity.h"
#include "plugin/input/InputProcessSecurity.h"
#include "plugin/input/InputFileSecurity.h"
#include "plugin/input/InputPrometheus.h"
#include "plugin/processor/inner/ProcessorPromParseMetricNative.h"
#include "plugin/processor/inner/ProcessorPromRelabelMetricNative.h"
Expand All @@ -72,7 +73,7 @@
DEFINE_FLAG_BOOL(enable_processor_spl, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_network_observer, "", false);
DEFINE_FLAG_BOOL(enable_ebpf_process_secure, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_file_secure, "", false);
DEFINE_FLAG_BOOL(enable_ebpf_file_secure, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_network_secure, "", false);

using namespace std;
Expand Down Expand Up @@ -152,9 +153,9 @@ void PluginRegistry::LoadStaticPlugins() {
if (BOOL_FLAG(enable_ebpf_process_secure)) {
RegisterInputCreator(new StaticInputCreator<InputProcessSecurity>(), true);
}
// if (BOOL_FLAG(enable_ebpf_file_secure)) {
// RegisterInputCreator(new StaticInputCreator<InputFileSecurity>(), true);
// }
if (BOOL_FLAG(enable_ebpf_file_secure)) {
RegisterInputCreator(new StaticInputCreator<InputFileSecurity>(), true);
}
if (BOOL_FLAG(enable_ebpf_network_secure)) {
RegisterInputCreator(new StaticInputCreator<InputNetworkSecurity>(), true);
}
Expand Down
37 changes: 28 additions & 9 deletions core/ebpf/EBPFServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include "ebpf/plugin/AbstractManager.h"
#include "logger/Logger.h"
#include "monitor/metric_models/ReentrantMetricsRecord.h"
// #include "plugin/file_security/FileSecurityManager.h"
#include "plugin/file_security/FileSecurityManager.h"
#include "plugin/network_observer/NetworkObserverManager.h"
#include "plugin/network_security/NetworkSecurityManager.h"
#include "plugin/process_security/ProcessSecurityManager.h"
Expand Down Expand Up @@ -331,14 +331,13 @@ bool EBPFServer::startPluginInternal(const std::string& pipelineName,
break;
}

// case PluginType::FILE_SECURITY: {
// if (!pluginMgr) {
// pluginMgr
// = FileSecurityManager::Create(mProcessCacheManager, mEBPFAdapter, mDataEventQueue,
// metricManager);
// }
// break;
// }
case PluginType::FILE_SECURITY: {
if (!pluginMgr) {
pluginMgr
= FileSecurityManager::Create(mProcessCacheManager, mEBPFAdapter, mCommonEventQueue, metricManager);
}
break;
}
default:
LOG_ERROR(sLogger, ("unknown plugin type", int(type)));
return false;
Expand Down Expand Up @@ -526,6 +525,26 @@ void EBPFServer::updatePluginState(PluginType type,
mPlugins[static_cast<int>(type)].mManager = std::move(mgr);
}

void EBPFServer::SetPluginLifecycleState(PluginType type,
const std::string& pipelineName,
LifecycleState state)
{
if (type >= PluginType::MAX) {
return;
}
mPlugins[static_cast<int>(type)].mStatePipelineName = pipelineName;
mPlugins[static_cast<int>(type)].mLifecycleState = state;

LOG_DEBUG(sLogger, ("update plugin lifestate", "")("type", magic_enum::enum_name(type).data())("pipeline", pipelineName)("lifestate", magic_enum::enum_name(state).data()));
}

bool EBPFServer::IsPluginInited(PluginType type, const std::string& pipelineName) {
if (type >= PluginType::MAX) {
return false;
}
return mPlugins[static_cast<int>(type)].mLifecycleState == LifecycleState::INITIALIZED && mPlugins[static_cast<int>(type)].mStatePipelineName == pipelineName;
}

void EBPFServer::handlerEvents() {
std::array<std::shared_ptr<CommonEvent>, 4096> items;
while (mRunning) {
Expand Down
11 changes: 11 additions & 0 deletions core/ebpf/EBPFServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class EnvManager {
#endif
};

enum class LifecycleState {
STOPPED,
INITIALIZED,
RUNNING,
SUSPENDED
};
struct PluginState {
std::string mPipelineName;
std::string mProject;
Expand All @@ -60,6 +66,8 @@ struct PluginState {
// (PollPerfBuffers/HandlerEvents/GetAllProjects), allowing them to safely interleave.
mutable std::atomic_bool mValid;
mutable std::shared_mutex mMtx;
std::atomic<LifecycleState> mLifecycleState{LifecycleState::STOPPED};
std::string mStatePipelineName;
};

class EBPFServer : public InputRunner {
Expand Down Expand Up @@ -98,6 +106,9 @@ class EBPFServer : public InputRunner {
// TODO(qianlu): remove this function when network observer use unified threads
std::shared_ptr<AbstractManager> GetPluginManager(PluginType type);

void SetPluginLifecycleState(PluginType type, const std::string& pipelineName, LifecycleState state);
bool IsPluginInited(PluginType type, const std::string& pipelineName);

private:
bool startPluginInternal(const std::string& pipelineName,
uint32_t pluginIndex,
Expand Down
171 changes: 171 additions & 0 deletions core/ebpf/driver/FileFilter.cpp
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright 2025 iLogtail Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern "C" {
#include <bpf/libbpf.h>
#include <coolbpf/coolbpf.h>
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include <coolbpf/security.skel.h>
#pragma GCC diagnostic pop
#include <unistd.h>

#include <string>

#include "BPFMapTraits.h"
#include "BPFWrapper.h"
#include "CallName.h"
#include "FileFilter.h"
#include "IdAllocator.h"
#include "Log.h"
#include "ebpf/include/export.h"

namespace logtail {
namespace ebpf {

int CreateFileFilterForCallname(std::shared_ptr<logtail::ebpf::BPFWrapper<security_bpf>> wrapper,
const std::string& callName,
const std::variant<std::monostate, SecurityFileFilter, SecurityNetworkFilter> config) {
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_INFO,
"[CreateFilterForCallname] EnableCallName:%s, idx:%ld, hold:%d \n",
callName.c_str(),
config.index(),
std::holds_alternative<SecurityFileFilter>(config));
int ret = 0;

int callNameIdx = GetCallNameIdx(callName);
if (callNameIdx == ERR_UNKNOWN_CALLNAME) {
return kErrDriverInvalidParam;
}

auto filter = std::get_if<SecurityFileFilter>(&config);
// concatenate path and filename, then write the resulting char* path into path_filter_list
// TODO qianlu.kk use map in map feature to support filters for different call names
if (filter && filter->mFilePathList.size()) {
selector_filters kernelFilters;
::memset(&kernelFilters, 0, sizeof(kernelFilters));

int idx = IdAllocator::GetInstance()->GetNextId<StringPrefixMap>();
if (idx == ERR_LIMIT_EXCEEDED) {
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname][IDAllocator] Failed to get next id, reach max %d\n",
IdAllocator::GetInstance()->GetMaxId<StringPrefixMap>());
return kErrDriverInvalidParam;
}
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname] Get index %d for %s\n",
idx,
callName.c_str());
// step1: add a new entry into string_prefix_maps, and assign a filter id
// step2: add a filter into filter map and record filter type and filter id
selector_filter kFilter{};
::memset(&kFilter, 0, sizeof(kFilter));
kFilter.filter_type = FILTER_TYPE_FILE_PREFIX;
kFilter.map_idx[0] = idx;
// in bytes
// kFilter.vallen = x.length();
kernelFilters.filter_count = 1;
kernelFilters.filters[0] = kFilter;

// LOG(INFO) << "filter not empty!";
for (int i = 0; i < (int)filter->mFilePathList.size() && i < MAX_FILTER_FOR_PER_CALLNAME; i++) {
const auto& origin = filter->mFilePathList[i];
std::string truncatedPath;
if (origin.length() > STRING_PREFIX_MAX_LENGTH - 1) {
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname] filter path is too long, truncating to %d bytes: %s",
STRING_PREFIX_MAX_LENGTH,
origin.c_str());
truncatedPath = origin.substr(0, STRING_PREFIX_MAX_LENGTH - 1);
}
const auto& x = truncatedPath.empty() ? origin : truncatedPath;
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname] begin to update map in map for filter detail, idx: %d, path: %s\n",
idx,
x.c_str());

// update inner map
string_prefix_lpm_trie prefixTrie{};
::memset(&prefixTrie, 0, sizeof(prefixTrie));
::memcpy(prefixTrie.data, x.data(), x.length());
prefixTrie.prefixlen = x.length() * 8; // in bits
uint8_t val = 1;
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname][before update] prefix trie data: %s prefix_len: %u\n",
prefixTrie.data,
prefixTrie.prefixlen);
ret = wrapper->UpdateInnerMapElem<StringPrefixMap>(
std::string("string_prefix_maps"), &idx, &prefixTrie, &val, 0);
if (ret) {
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[CreateFilterForCallname][update failed] prefix trie data: %s prefix_len: %u\n",
prefixTrie.data,
prefixTrie.prefixlen);
continue;
}
}

// udpate filter_map
wrapper->UpdateBPFHashMap("filter_map", &callNameIdx, &kernelFilters, 0);
}

return ret;
}

int DeleteFileFilterForCallname(std::shared_ptr<logtail::ebpf::BPFWrapper<security_bpf>> wrapper,
const std::string& callName) {
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN, "DeleteFilterForCallname %s\n", callName.c_str());
int callNameIdx = GetCallNameIdx(callName);
if (callNameIdx == ERR_UNKNOWN_CALLNAME) {
return kErrDriverInvalidParam;
}
int ret = 0;
// step1: detach callname

// step2: get filters for call name
selector_filters kernelFilters;
::memset(&kernelFilters, 0, sizeof(kernelFilters));
// get filters
ret = wrapper->LookupBPFHashMap("filter_map", &callNameIdx, &kernelFilters);
if (ret) {
// no filters found, return directly
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_INFO,
"[DeleteFilterForCallname] there is no filter for call name: %s\n",
callName.c_str());
return 0;
}

// step3: remove filters
for (int i = 0; i < kernelFilters.filter_count; i++) {
auto filter = kernelFilters.filters[i];
auto outterKey = filter.map_idx[0];
wrapper->DeleteInnerMap<StringPrefixMap>("string_prefix_maps", &outterKey);
IdAllocator::GetInstance()->ReleaseId<StringPrefixMap>(outterKey);
ebpf_log(logtail::ebpf::eBPFLogType::NAMI_LOG_TYPE_WARN,
"[DeleteFilterForCallname] release filter for type: %d mapIdx: %u\n",
static_cast<int>(filter.filter_type),
outterKey);
}

// step4: delete filter map for call name
::memset(&kernelFilters, 0, sizeof(kernelFilters));
ret = wrapper->UpdateBPFHashMap("filter_map", &callNameIdx, &kernelFilters, 0);

return ret;
}

} // namespace ebpf
} // namespace logtail
48 changes: 48 additions & 0 deletions core/ebpf/driver/FileFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2025 iLogtail Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

extern "C" {
#include <bpf/libbpf.h>
#include <coolbpf/coolbpf.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include <coolbpf/security.skel.h>
#pragma GCC diagnostic pop
};

#include <unistd.h>

#include <string>
#include <vector>

#include "BPFMapTraits.h"
#include "BPFWrapper.h"
#include "IdAllocator.h"
#include "Log.h"
#include "ebpf/include/export.h"

namespace logtail {
namespace ebpf {

int CreateFileFilterForCallname(std::shared_ptr<logtail::ebpf::BPFWrapper<security_bpf>> wrapper,
const std::string& call_name,
const std::variant<std::monostate, SecurityFileFilter, SecurityNetworkFilter> config);

int DeleteFileFilterForCallname(std::shared_ptr<logtail::ebpf::BPFWrapper<security_bpf>> wrapper,
const std::string& call_name);

} // namespace ebpf
} // namespace logtail
Loading
Loading
0