core/unittest/ebpf/ProcessCacheManagerUnittest.cpp (876 lines of code) (raw):
// Copyright 2025 LoongCollector 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.
#include <cstdint>
#include <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include <unordered_map>
#include "ProcParser.h"
#include "common/memory/SourceBuffer.h"
#include "ebpf/EBPFAdapter.h"
#include "ebpf/plugin/ProcessCacheManager.h"
#include "ebpf/type/ProcessEvent.h"
#include "models/PipelineEventGroup.h"
#include "security/bpf_process_event_type.h"
#include "type/table/BaseElements.h"
#include "unittest/Unittest.h"
#include "unittest/ebpf/ProcFsStub.h"
using namespace logtail;
using namespace logtail::ebpf;
class ProcessCacheManagerUnittest : public ::testing::Test {
protected:
void SetUp() override {
mEBPFAdapter = std::make_shared<EBPFAdapter>();
mTestRoot = std::filesystem::path(GetProcessExecutionDir()) / "ProcessCacheManagerUnittest";
mProcDir = mTestRoot / "proc";
mProcessCacheManager = std::make_shared<ProcessCacheManager>(
mEBPFAdapter, "test_host", mTestRoot.string(), mEventQueue, nullptr, nullptr, nullptr, nullptr);
}
void TearDown() override {
moodycamel::BlockingConcurrentQueue<std::shared_ptr<CommonEvent>> emptyQueue;
mEventQueue.swap(emptyQueue);
std::filesystem::remove_all(mTestRoot);
}
// ProcessCacheManager测试用例
void TestListRunningProcs();
// void TestWriteProcToBPFMap();
void TestProcToProcessCacheValue();
void TestRecordDataEventNormal();
void TestDataGetAndRemoveSizeBad();
void TestRecordDataEventExceedLimit();
void TestMsgExecveEventToProcessCacheValueNoClone();
void TestMsgExecveEventToProcessCacheValueLongFilename();
void TestMsgExecveEventToProcessCacheValueLongArgs();
void TestMsgExecveEventToProcessCacheValueNoArgs();
void TestMsgExecveEventToProcessCacheValueNoArgsNoCwd();
void TestMsgCloneEventToProcessCacheValue();
void TestMsgCloneEventToProcessCacheValueParentNotFound();
void TestRecordEventCloneExecveExit();
void TestRecordEventExecveExit();
void TestFinalizeProcessTags();
private:
void FillKernelThreadProc(Proc& proc);
void FillRootCwdProc(Proc& proc);
void FillExecveEventNoClone(msg_execve_event& event);
void FillExecveEventLongFilename(msg_execve_event& event);
std::shared_ptr<EBPFAdapter> mEBPFAdapter;
std::shared_ptr<ProcessCacheManager> mProcessCacheManager;
moodycamel::BlockingConcurrentQueue<std::shared_ptr<CommonEvent>> mEventQueue;
std::filesystem::path mTestRoot;
std::filesystem::path mProcDir;
};
void ProcessCacheManagerUnittest::FillKernelThreadProc(Proc& proc) {
proc.pid = 10002;
proc.ppid = 0;
proc.tid = proc.pid;
proc.nspid = 0; // no container_id
proc.flags = static_cast<uint32_t>(EVENT_PROCFS | EVENT_NEEDS_CWD | EVENT_NEEDS_AUID | EVENT_ROOT_CWD);
proc.cwd = "/";
proc.comm = "ksoftirqd/18";
proc.cmdline = ""; // \0 separated binary and args
proc.exe = "";
proc.container_id.resize(0);
proc.effective = 0x000001ffffffffff;
proc.inheritable = 0x0000000000000000;
proc.permitted = 0x000001ffffffffff;
}
msg_execve_event CreateStubExecveEvent() {
msg_execve_event event{};
event.process.pid = 1234;
event.process.ktime = 123456789;
event.process.uid = 0;
event.creds.caps.permitted = 0x11;
event.creds.caps.effective = 0x33;
event.creds.caps.inheritable = 0x22;
event.parent.pid = 5678;
event.parent.ktime = 567891234;
return event;
}
void ProcessCacheManagerUnittest::FillExecveEventNoClone(msg_execve_event& event) {
constexpr char args[] = "/usr/bin/ls\0-l\0/root/one more thing\0/root";
constexpr uint32_t argsSize = sizeof(args) - 1;
memcpy(event.buffer + SIZEOF_EVENT, args, argsSize);
event.process.size = argsSize + SIZEOF_EVENT;
event.cleanup_key.pid = 1234;
event.cleanup_key.ktime = 123456780;
}
void ProcessCacheManagerUnittest::FillExecveEventLongFilename(msg_execve_event& event) {
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = event.process.pid;
msgData.id.time = event.process.ktime;
std::fill_n(msgData.arg, 255, 'a');
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = event.process.ktime;
msgData.common.size = offsetof(struct msg_data, arg) + 255;
mProcessCacheManager->RecordDataEvent(&msgData);
// fill data_event_desc
auto* desc = reinterpret_cast<data_event_desc*>(event.buffer + SIZEOF_EVENT);
desc->error = 0;
desc->pad = 0;
desc->size = 256;
desc->leftover = 1;
desc->id.pid = event.process.pid;
desc->id.time = event.process.ktime;
// fill arguments and cwd
constexpr char args[] = "-l\0/root/one more thing\0";
constexpr uint32_t argsSize = sizeof(args) - 1;
memcpy(event.buffer + SIZEOF_EVENT + sizeof(data_event_desc), args, argsSize);
event.process.size = argsSize + sizeof(data_event_desc) + SIZEOF_EVENT;
event.process.flags |= EVENT_DATA_FILENAME | EVENT_ROOT_CWD;
event.cleanup_key.pid = 1234;
event.cleanup_key.ktime = 123456780;
}
void ProcessCacheManagerUnittest::FillRootCwdProc(Proc& proc) {
proc.pid = 20001;
proc.ppid = 99999;
proc.tid = proc.pid;
proc.nspid = 0; // no container_id
proc.flags = static_cast<uint32_t>(EVENT_PROCFS | EVENT_NEEDS_CWD | EVENT_NEEDS_AUID | EVENT_ROOT_CWD);
proc.cwd = "/";
proc.comm = "cat";
constexpr char cmdline[] = "cat\0/etc/host.conf\0/etc/resolv.conf";
proc.cmdline.assign(cmdline, sizeof(cmdline) - 1); // \0 separated binary and args
proc.exe = "/usr/bin/cat";
proc.container_id.resize(0);
}
void ProcessCacheManagerUnittest::TestListRunningProcs() {
ProcFsStub procFsStub(mProcDir);
std::unordered_map<int, Proc> pidMap;
for (uint32_t i = 1; i < 11; ++i) { // max i-1 is 9 so that container_id generated is ok
Proc proc = CreateStubProc();
proc.pid = i;
proc.ppid = i - 1;
proc.ktime = i * 1000000000UL;
proc.pktime = (i - 1) * 1000000000UL;
proc.auid = i + 500;
proc.realUid = i + 500;
proc.effectiveUid = i + 500;
proc.savedUid = i + 500;
proc.fsUid = i + 500;
proc.realGid = i + 500;
proc.effectiveGid = i + 500;
proc.savedGid = i + 500;
proc.fsGid = i + 500;
proc.tid = proc.pid;
proc.nspid = proc.pid;
proc.flags = static_cast<uint32_t>(EVENT_PROCFS | EVENT_NEEDS_CWD | EVENT_NEEDS_AUID);
proc.cwd = "/home/user";
proc.comm = "test program";
proc.cmdline = proc.comm + '\0' + std::to_string(i) + '\0' + "arg2"; // \0 separated binary and args
proc.container_id.clear();
proc.container_id.resize(64, '0' + i - 1);
proc.exe = "/usr/local/bin/test program";
proc.effective = i;
proc.inheritable = i + 1;
proc.permitted = i + 2;
proc.uts_ns = i + 400000000;
proc.ipc_ns = i + 400000001;
proc.mnt_ns = i + 400000002;
proc.pid_ns = i + 400000003;
proc.pid_for_children_ns = i + 400000004;
proc.net_ns = i + 400000005;
proc.time_ns = i + 400000006;
proc.time_for_children_ns = i + 400000007;
proc.cgroup_ns = i + 400000008;
proc.user_ns = i + 400000009;
pidMap[i] = proc;
}
{ // kernal thread
Proc proc = CreateStubProc();
FillKernelThreadProc(proc);
pidMap[proc.pid] = proc;
}
{ // cwd is root and invalid ppid
Proc proc = CreateStubProc();
FillRootCwdProc(proc);
pidMap[proc.pid] = proc;
}
for (auto& proc : pidMap) {
procFsStub.CreatePidDir(proc.second);
}
auto procs = mProcessCacheManager->listRunningProcs();
for (const auto& proc : procs) {
const auto it = pidMap.find(proc->pid);
APSARA_TEST_TRUE_FATAL(it != pidMap.end());
const auto& expected = it->second;
APSARA_TEST_EQUAL(proc->pid, expected.pid);
APSARA_TEST_EQUAL(proc->ppid, expected.ppid);
APSARA_TEST_EQUAL(proc->ktime, expected.ktime);
APSARA_TEST_EQUAL(proc->auid, expected.auid);
APSARA_TEST_EQUAL(proc->realUid, expected.realUid);
APSARA_TEST_EQUAL(proc->effectiveUid, expected.effectiveUid);
APSARA_TEST_EQUAL(proc->savedUid, expected.savedUid);
APSARA_TEST_EQUAL(proc->fsUid, expected.fsUid);
APSARA_TEST_EQUAL(proc->realGid, expected.realGid);
APSARA_TEST_EQUAL(proc->effectiveGid, expected.effectiveGid);
APSARA_TEST_EQUAL(proc->savedGid, expected.savedGid);
APSARA_TEST_EQUAL(proc->fsGid, expected.fsGid);
APSARA_TEST_EQUAL(proc->tid, expected.tid);
APSARA_TEST_EQUAL(proc->nspid, expected.nspid);
APSARA_TEST_EQUAL(proc->flags, expected.flags);
APSARA_TEST_EQUAL(proc->cwd, expected.cwd);
APSARA_TEST_EQUAL(proc->comm, expected.comm);
APSARA_TEST_EQUAL(proc->cmdline, expected.cmdline);
APSARA_TEST_EQUAL(proc->container_id, expected.container_id);
APSARA_TEST_EQUAL(proc->exe, expected.exe);
APSARA_TEST_EQUAL(proc->effective, expected.effective);
APSARA_TEST_EQUAL(proc->inheritable, expected.inheritable);
APSARA_TEST_EQUAL(proc->permitted, expected.permitted);
APSARA_TEST_EQUAL(proc->uts_ns, expected.uts_ns);
APSARA_TEST_EQUAL(proc->ipc_ns, expected.ipc_ns);
APSARA_TEST_EQUAL(proc->mnt_ns, expected.mnt_ns);
APSARA_TEST_EQUAL(proc->pid_ns, expected.pid_ns);
APSARA_TEST_EQUAL(proc->pid_for_children_ns, expected.pid_for_children_ns);
APSARA_TEST_EQUAL(proc->net_ns, expected.net_ns);
APSARA_TEST_EQUAL(proc->time_ns, expected.time_ns);
APSARA_TEST_EQUAL(proc->time_for_children_ns, expected.time_for_children_ns);
APSARA_TEST_EQUAL(proc->cgroup_ns, expected.cgroup_ns);
APSARA_TEST_EQUAL(proc->user_ns, expected.user_ns);
const auto pit = pidMap.find(proc->ppid);
if (pit != pidMap.end()) {
const auto& pexpected = pit->second;
APSARA_TEST_EQUAL(proc->ppid, pexpected.pid);
APSARA_TEST_EQUAL(proc->pktime, pexpected.ktime);
// APSARA_TEST_EQUAL(proc->pcmdline, pexpected.cmdline);
// APSARA_TEST_EQUAL(proc->pexe, pexpected.exe);
// APSARA_TEST_EQUAL(proc->pnspid, pexpected.nspid);
// APSARA_TEST_EQUAL(proc->pflags, static_cast<uint32_t>(EVENT_PROCFS | EVENT_NEEDS_CWD | EVENT_NEEDS_AUID);
}
}
}
void ProcessCacheManagerUnittest::TestProcToProcessCacheValue() {
{ // kernel thread
Proc proc = CreateStubProc();
FillKernelThreadProc(proc);
auto cacheValuePtr = mProcessCacheManager->procToProcessCacheValue(proc);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, proc.ppid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, proc.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(proc.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(0U));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(proc.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), proc.cwd);
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), proc.comm);
}
{ // cwd is root and invalid ppid
Proc proc = CreateStubProc();
FillRootCwdProc(proc);
auto cacheValuePtr = mProcessCacheManager->procToProcessCacheValue(proc);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, proc.ppid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, proc.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(proc.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(0U));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(proc.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), proc.cwd);
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), proc.exe);
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), "/etc/host.conf /etc/resolv.conf");
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string());
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(), std::string());
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string());
}
}
void ProcessCacheManagerUnittest::TestRecordDataEventNormal() {
{
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = 1234;
msgData.id.time = 123546789;
std::string filename(255, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
APSARA_TEST_EQUAL(1UL, mProcessCacheManager->mDataMap.size());
// fill data_event_desc
data_event_desc desc{};
desc.error = 0;
desc.pad = 0;
desc.size = filename.size();
desc.leftover = 0;
desc.id.pid = msgData.id.pid;
desc.id.time = msgData.id.time;
auto dataStr = mProcessCacheManager->dataGetAndRemove(&desc);
APSARA_TEST_EQUAL(dataStr, filename);
APSARA_TEST_EQUAL(0UL, mProcessCacheManager->mDataMap.size());
}
{
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = 1234;
msgData.id.time = 123546789;
std::string filename(255, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
mProcessCacheManager->RecordDataEvent(&msgData);
mProcessCacheManager->RecordDataEvent(&msgData);
mProcessCacheManager->RecordDataEvent(&msgData);
mProcessCacheManager->RecordDataEvent(&msgData);
APSARA_TEST_EQUAL(1UL, mProcessCacheManager->mDataMap.size());
std::string fullFilename = filename + filename + filename + filename + filename;
// fill data_event_desc
data_event_desc desc{};
desc.error = 0;
desc.pad = 0;
desc.size = fullFilename.size();
desc.leftover = 0;
desc.id.pid = msgData.id.pid;
desc.id.time = msgData.id.time;
auto dataStr = mProcessCacheManager->dataGetAndRemove(&desc);
APSARA_TEST_EQUAL(dataStr, fullFilename);
APSARA_TEST_EQUAL(0UL, mProcessCacheManager->mDataMap.size());
}
}
void ProcessCacheManagerUnittest::TestDataGetAndRemoveSizeBad() {
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = 1234;
msgData.id.time = 123546789;
std::string filename(255, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
APSARA_TEST_EQUAL(1UL, mProcessCacheManager->mDataMap.size());
// fill data_event_desc
data_event_desc desc{};
desc.error = 0;
desc.pad = 0;
desc.size = filename.size();
desc.leftover = 1; // let size - leftover != filename.size()
desc.id.pid = msgData.id.pid;
desc.id.time = msgData.id.time;
auto dataStr = mProcessCacheManager->dataGetAndRemove(&desc);
APSARA_TEST_EQUAL(dataStr, "");
APSARA_TEST_EQUAL(0UL, mProcessCacheManager->mDataMap.size());
}
void ProcessCacheManagerUnittest::TestRecordDataEventExceedLimit() {
for (size_t i = 1; i <= ProcessCacheManager::kMaxDataMapSize; i++) {
struct msg_data msgData {};
msgData.id.pid = i;
msgData.id.time = 123546789;
std::string filename(1, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
}
APSARA_TEST_EQUAL(ProcessCacheManager::kMaxDataMapSize, mProcessCacheManager->mDataMap.size());
{
struct msg_data msgData {};
msgData.id.pid = 0;
msgData.id.time = 123546789 + kMaxCacheExpiredTimeout + 1;
std::string filename(1, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
}
APSARA_TEST_EQUAL(1UL, mProcessCacheManager->mDataMap.size()); // keep one item not expired
for (size_t i = 1; i <= ProcessCacheManager::kMaxDataMapSize; i++) {
struct msg_data msgData {};
msgData.id.pid = i;
msgData.id.time = 123546789 + kMaxCacheExpiredTimeout + 2;
std::string filename(1, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = msgData.id.time;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
}
APSARA_TEST_EQUAL(1UL, mProcessCacheManager->mDataMap.size()); // forced clear all, only keep the last one
}
void ProcessCacheManagerUnittest::TestMsgExecveEventToProcessCacheValueNoClone() {
msg_execve_event event = CreateStubExecveEvent();
constexpr char args[] = "/usr/bin/ls\0-l\0/root/one more thing\0/root";
constexpr uint32_t argsSize = sizeof(args) - 1;
memcpy(event.buffer + SIZEOF_EVENT, args, argsSize);
event.process.size = argsSize + SIZEOF_EVENT;
event.cleanup_key.pid = 1234;
event.cleanup_key.ktime = 123456780;
auto cacheValuePtr = mProcessCacheManager->msgExecveEventToProcessCacheValue(event);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, event.cleanup_key.pid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, event.cleanup_key.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(event.process.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(event.process.uid));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(event.process.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), "/root");
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), "/usr/bin/ls");
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), "-l \"/root/one more thing\"");
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string("CAP_CHOWN CAP_FSETID"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(),
std::string("CAP_CHOWN DAC_OVERRIDE CAP_FSETID CAP_KILL"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string("DAC_OVERRIDE CAP_KILL"));
}
void ProcessCacheManagerUnittest::TestMsgExecveEventToProcessCacheValueLongFilename() {
msg_execve_event event = CreateStubExecveEvent();
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = event.process.pid;
msgData.id.time = event.process.ktime;
std::string filename(255, 'a');
std::copy(filename.begin(), filename.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = event.process.ktime;
msgData.common.size = offsetof(struct msg_data, arg) + filename.size();
mProcessCacheManager->RecordDataEvent(&msgData);
// fill data_event_desc
auto* desc = reinterpret_cast<data_event_desc*>(event.buffer + SIZEOF_EVENT);
desc->error = 0;
desc->pad = 0;
desc->size = 256;
desc->leftover = desc->size - filename.size();
desc->id.pid = event.process.pid;
desc->id.time = event.process.ktime;
// fill arguments and cwd
constexpr char args[] = "-l\0/root/one more thing";
constexpr uint32_t argsSize = sizeof(args) - 1;
memcpy(event.buffer + SIZEOF_EVENT + sizeof(data_event_desc), args, argsSize);
event.process.size = argsSize + sizeof(data_event_desc) + SIZEOF_EVENT;
event.process.flags |= EVENT_DATA_FILENAME | EVENT_ROOT_CWD | EVENT_CLONE;
auto cacheValuePtr = mProcessCacheManager->msgExecveEventToProcessCacheValue(event);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, event.parent.pid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, event.parent.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(event.process.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(event.process.uid));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(event.process.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), "/");
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), "/" + filename);
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), "-l \"/root/one more thing\"");
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string("CAP_CHOWN CAP_FSETID"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(),
std::string("CAP_CHOWN DAC_OVERRIDE CAP_FSETID CAP_KILL"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string("DAC_OVERRIDE CAP_KILL"));
}
void ProcessCacheManagerUnittest::TestMsgExecveEventToProcessCacheValueLongArgs() {
msg_execve_event event = CreateStubExecveEvent();
// fill msg_data
struct msg_data msgData {};
msgData.id.pid = event.process.pid;
msgData.id.time = event.process.ktime;
std::string arg1(1023, 'a');
arg1.append(1, '\0');
std::copy(arg1.begin(), arg1.end(), msgData.arg);
msgData.common.op = MSG_OP_DATA;
msgData.common.ktime = event.process.ktime;
msgData.common.size = offsetof(struct msg_data, arg) + arg1.size();
mProcessCacheManager->RecordDataEvent(&msgData);
std::string arg2(1023, 'b');
std::copy(arg2.begin(), arg2.end(), msgData.arg);
msgData.common.size = offsetof(struct msg_data, arg) + arg2.size();
mProcessCacheManager->RecordDataEvent(&msgData);
std::string arguments(arg1 + arg2);
arguments[1023] = ' ';
// fill arguments
constexpr char binary[] = "/usr/bin/ls";
memcpy(event.buffer + SIZEOF_EVENT, binary, sizeof(binary));
uint32_t currentOffset = sizeof(binary);
// fill data_event_desc
auto* desc = reinterpret_cast<data_event_desc*>(event.buffer + SIZEOF_EVENT + currentOffset);
desc->error = 0;
desc->pad = 0;
desc->size = arg1.size() + arg2.size();
desc->leftover = 0;
desc->id.pid = event.process.pid;
desc->id.time = event.process.ktime;
currentOffset += sizeof(data_event_desc);
// fill cwd
constexpr char cwd[] = "/root";
memcpy(event.buffer + SIZEOF_EVENT + currentOffset, cwd, sizeof(cwd) - 1);
currentOffset += sizeof(cwd) - 1;
event.process.size = currentOffset + SIZEOF_EVENT;
event.process.flags |= EVENT_DATA_ARGS | EVENT_PROCFS;
auto cacheValuePtr = mProcessCacheManager->msgExecveEventToProcessCacheValue(event);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, event.parent.pid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, event.parent.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(event.process.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(event.process.uid));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(event.process.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), cwd);
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), binary);
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), arguments);
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string("CAP_CHOWN CAP_FSETID"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(),
std::string("CAP_CHOWN DAC_OVERRIDE CAP_FSETID CAP_KILL"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string("DAC_OVERRIDE CAP_KILL"));
}
void ProcessCacheManagerUnittest::TestMsgExecveEventToProcessCacheValueNoArgs() {
msg_execve_event event = CreateStubExecveEvent();
// fill binary
constexpr char binary[] = "/usr/bin/ls";
memcpy(event.buffer + SIZEOF_EVENT, binary, sizeof(binary));
uint32_t currentOffset = sizeof(binary);
// fill cwd
constexpr char cwd[] = "/root";
memcpy(event.buffer + SIZEOF_EVENT + currentOffset, cwd, sizeof(cwd) - 1);
currentOffset += sizeof(cwd) - 1;
event.process.size = currentOffset + SIZEOF_EVENT;
event.process.flags |= EVENT_ERROR_PATH_COMPONENTS;
auto cacheValuePtr = mProcessCacheManager->msgExecveEventToProcessCacheValue(event);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, event.parent.pid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, event.parent.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(event.process.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(event.process.uid));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(event.process.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), cwd);
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), binary);
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), "");
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string("CAP_CHOWN CAP_FSETID"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(),
std::string("CAP_CHOWN DAC_OVERRIDE CAP_FSETID CAP_KILL"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string("DAC_OVERRIDE CAP_KILL"));
}
void ProcessCacheManagerUnittest::TestMsgExecveEventToProcessCacheValueNoArgsNoCwd() {
msg_execve_event event = CreateStubExecveEvent();
// fill binary
constexpr char binary[] = "/usr/bin/ls";
memcpy(event.buffer + SIZEOF_EVENT, binary, sizeof(binary));
uint32_t currentOffset = sizeof(binary);
event.process.size = currentOffset + SIZEOF_EVENT;
event.process.flags &= ~(EVENT_NO_CWD_SUPPORT | EVENT_ERROR_CWD | EVENT_ROOT_CWD);
auto cacheValuePtr = mProcessCacheManager->msgExecveEventToProcessCacheValue(event);
auto& cacheValue = *cacheValuePtr;
APSARA_TEST_EQUAL(cacheValue.mPPid, event.parent.pid);
APSARA_TEST_EQUAL(cacheValue.mPKtime, event.parent.ktime);
APSARA_TEST_EQUAL(cacheValue.Get<kProcessId>().to_string(), std::to_string(event.process.pid));
APSARA_TEST_EQUAL(cacheValue.Get<kUid>().to_string(), std::to_string(event.process.uid));
APSARA_TEST_EQUAL(cacheValue.Get<kUser>().to_string(), "root");
APSARA_TEST_EQUAL(cacheValue.Get<kKtime>().to_string(), std::to_string(event.process.ktime));
APSARA_TEST_EQUAL(cacheValue.Get<kCWD>().to_string(), "");
APSARA_TEST_EQUAL(cacheValue.Get<kBinary>().to_string(), binary);
APSARA_TEST_EQUAL(cacheValue.Get<kArguments>().to_string(), "");
APSARA_TEST_EQUAL(cacheValue.Get<kCapPermitted>().to_string(), std::string("CAP_CHOWN CAP_FSETID"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapEffective>().to_string(),
std::string("CAP_CHOWN DAC_OVERRIDE CAP_FSETID CAP_KILL"));
APSARA_TEST_EQUAL(cacheValue.Get<kCapInheritable>().to_string(), std::string("DAC_OVERRIDE CAP_KILL"));
}
void ProcessCacheManagerUnittest::TestMsgCloneEventToProcessCacheValue() {
// 测试缓存操作
data_event_id parentkey{12345, 123456789};
auto parentExecId = mProcessCacheManager->GenerateExecId(parentkey.pid, parentkey.time);
auto parentCacheValue = std::make_shared<ProcessCacheValue>();
parentCacheValue->SetContent<kProcessId>(StringView("1234"));
parentCacheValue->SetContent<kKtime>(StringView("123456789"));
parentCacheValue->SetContent<kExecId>(parentExecId);
parentCacheValue->SetContent<kUid>(StringView("1000"));
parentCacheValue->SetContent<kBinary>(StringView("test_binary"));
// 测试缓存更新
mProcessCacheManager->mProcessCache.AddCache(parentkey, std::move(parentCacheValue));
msg_clone_event event{};
event.tgid = 5678;
event.ktime = 123456790;
event.parent.pid = parentkey.pid;
event.parent.ktime = parentkey.time;
auto execId = mProcessCacheManager->GenerateExecId(event.tgid, event.ktime);
std::shared_ptr<ProcessCacheValue> cacheValue = mProcessCacheManager->msgCloneEventToProcessCacheValue(event);
APSARA_TEST_TRUE(cacheValue != nullptr);
APSARA_TEST_EQUAL(cacheValue->mPPid, event.parent.pid);
APSARA_TEST_EQUAL(cacheValue->mPKtime, event.parent.ktime);
APSARA_TEST_EQUAL((*cacheValue).Get<kProcessId>().to_string(), std::to_string(event.tgid));
APSARA_TEST_EQUAL((*cacheValue).Get<kKtime>().to_string(), std::to_string(event.ktime));
APSARA_TEST_EQUAL((*cacheValue).Get<kExecId>().to_string(), execId);
APSARA_TEST_EQUAL((*cacheValue).Get<kUid>().to_string(), "1000");
APSARA_TEST_EQUAL((*cacheValue).Get<kBinary>().to_string(), "test_binary");
}
void ProcessCacheManagerUnittest::TestMsgCloneEventToProcessCacheValueParentNotFound() {
msg_clone_event event{};
event.tgid = 5678;
event.ktime = 123456790;
event.parent.pid = 1234;
event.parent.pid = 123456789;
std::shared_ptr<ProcessCacheValue> cacheValue = mProcessCacheManager->msgCloneEventToProcessCacheValue(event);
APSARA_TEST_TRUE(cacheValue == nullptr);
}
/*
* Before daemon exit
* Lineage: ┌------------------------------┐ ┌-----------------------------┐
* CallChain: (sh) -clone- (daemon) -execve- (daemon) -clone- (app) -execve- (app)
* RefCnt: 2 0 2 0 1
* After daemon exit
* Lineage: ┌------------------------------┐ ┌-----------------------------┐
* CallChain: (sh) -clone- (daemon) -execve- (daemon) -clone- (app) -execve- (app)
* RefCnt: 1 0 1 0 1
*/
void ProcessCacheManagerUnittest::TestRecordEventCloneExecveExit() {
mProcessCacheManager->MarkProcessEventFlushStatus(true);
// sprawn processes
msg_execve_event shExecveEvent = CreateStubExecveEvent();
shExecveEvent.common.ktime = 20;
shExecveEvent.process.pid = 2;
shExecveEvent.process.ktime = 20;
shExecveEvent.parent.pid = 1;
shExecveEvent.parent.ktime = 1;
constexpr char shBinary[] = "/usr/bin/sh";
memcpy(shExecveEvent.buffer + SIZEOF_EVENT, shBinary, sizeof(shBinary));
shExecveEvent.process.size = sizeof(shBinary) + SIZEOF_EVENT;
shExecveEvent.process.flags |= EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&shExecveEvent);
msg_clone_event daemonCloneEvent{};
daemonCloneEvent.common.ktime = 30;
daemonCloneEvent.tgid = 3;
daemonCloneEvent.ktime = 30;
daemonCloneEvent.parent.pid = shExecveEvent.process.pid;
daemonCloneEvent.parent.ktime = shExecveEvent.process.ktime;
mProcessCacheManager->RecordCloneEvent(&daemonCloneEvent);
msg_execve_event daemonExecveEvent = CreateStubExecveEvent();
daemonExecveEvent.common.ktime = 31;
daemonExecveEvent.process.pid = 3;
daemonExecveEvent.process.ktime = 31;
daemonExecveEvent.parent.pid = shExecveEvent.process.pid;
daemonExecveEvent.parent.ktime = shExecveEvent.process.ktime;
daemonExecveEvent.cleanup_key.pid = daemonCloneEvent.tgid;
daemonExecveEvent.cleanup_key.ktime = daemonCloneEvent.ktime;
constexpr char daemonBinary[] = "/usr/local/bin/daemon";
memcpy(daemonExecveEvent.buffer + SIZEOF_EVENT, daemonBinary, sizeof(daemonBinary));
daemonExecveEvent.process.size = sizeof(daemonBinary) + SIZEOF_EVENT;
daemonExecveEvent.process.flags |= EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&daemonExecveEvent);
msg_clone_event appCloneEvent{};
appCloneEvent.common.ktime = 40;
appCloneEvent.tgid = 4;
appCloneEvent.ktime = 40;
appCloneEvent.parent.pid = daemonExecveEvent.process.pid;
appCloneEvent.parent.ktime = daemonExecveEvent.process.ktime;
mProcessCacheManager->RecordCloneEvent(&appCloneEvent);
msg_execve_event appExecveEvent = CreateStubExecveEvent();
appExecveEvent.process.pid = 4;
appExecveEvent.process.ktime = 41;
appExecveEvent.parent.pid = daemonExecveEvent.process.pid;
appExecveEvent.parent.ktime = daemonExecveEvent.process.ktime;
appExecveEvent.cleanup_key.pid = appCloneEvent.tgid;
appExecveEvent.cleanup_key.ktime = appCloneEvent.ktime;
constexpr char appBinary[] = "/usr/local/bin/app";
memcpy(appExecveEvent.buffer + SIZEOF_EVENT, appBinary, sizeof(appBinary));
appExecveEvent.process.size = sizeof(appBinary) + SIZEOF_EVENT;
appExecveEvent.process.flags |= EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&appExecveEvent);
// check cache
auto shProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{shExecveEvent.process.pid, shExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(shProc != nullptr);
APSARA_TEST_EQUAL((*shProc).Get<kBinary>().to_string(), shBinary);
APSARA_TEST_EQUAL(shProc->mRefCount, 2);
auto daemonClone
= mProcessCacheManager->mProcessCache.Lookup(data_event_id{daemonCloneEvent.tgid, daemonCloneEvent.ktime});
APSARA_TEST_TRUE_FATAL(daemonClone != nullptr);
APSARA_TEST_EQUAL((*daemonClone).Get<kBinary>().to_string(), shBinary);
APSARA_TEST_EQUAL(daemonClone->mRefCount, 0);
auto daemonProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{daemonExecveEvent.process.pid, daemonExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(daemonProc != nullptr);
APSARA_TEST_EQUAL((*daemonProc).Get<kBinary>().to_string(), daemonBinary);
APSARA_TEST_EQUAL(daemonProc->mRefCount, 2);
auto appClone = mProcessCacheManager->mProcessCache.Lookup(data_event_id{appCloneEvent.tgid, appCloneEvent.ktime});
APSARA_TEST_TRUE_FATAL(appClone != nullptr);
APSARA_TEST_EQUAL((*appClone).Get<kBinary>().to_string(), daemonBinary);
APSARA_TEST_EQUAL(appClone->mRefCount, 0);
auto appProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{appExecveEvent.process.pid, appExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(appProc != nullptr);
APSARA_TEST_EQUAL((*appProc).Get<kBinary>().to_string(), appBinary);
APSARA_TEST_EQUAL(appProc->mRefCount, 1);
// check output events
std::array<std::shared_ptr<CommonEvent>, 10> items{};
size_t eventCount = mEventQueue.try_dequeue_bulk(items.data(), items.size());
APSARA_TEST_EQUAL_FATAL(5UL, eventCount);
auto& event0 = (ProcessEvent&)(*items[0]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event0.mEventType);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.process.pid, event0.mPid);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.process.ktime, event0.mKtime);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.common.ktime, event0.mTimestamp);
auto& event1 = (ProcessEvent&)(*items[1]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_CLONE_EVENT, event1.mEventType);
APSARA_TEST_EQUAL_FATAL(daemonCloneEvent.tgid, event1.mPid);
APSARA_TEST_EQUAL_FATAL(daemonCloneEvent.ktime, event1.mKtime);
APSARA_TEST_EQUAL_FATAL(daemonCloneEvent.common.ktime, event1.mTimestamp);
auto& event2 = (ProcessEvent&)(*items[2]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event2.mEventType);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.process.pid, event2.mPid);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.process.ktime, event2.mKtime);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.common.ktime, event2.mTimestamp);
auto& event3 = (ProcessEvent&)(*items[3]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_CLONE_EVENT, event3.mEventType);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.tgid, event3.mPid);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.ktime, event3.mKtime);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.common.ktime, event3.mTimestamp);
auto& event4 = (ProcessEvent&)(*items[4]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event4.mEventType);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.process.pid, event4.mPid);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.process.ktime, event4.mKtime);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.common.ktime, event4.mTimestamp);
// daemon exit
msg_exit daemonExitEvent{};
daemonExitEvent.common.ktime = 60;
daemonExitEvent.current.pid = daemonExecveEvent.process.pid;
daemonExitEvent.current.ktime = daemonExecveEvent.process.ktime;
daemonExitEvent.info.code = -1;
daemonExitEvent.info.tid = 3;
mProcessCacheManager->RecordExitEvent(&daemonExitEvent);
// check cache
APSARA_TEST_EQUAL(shProc->mRefCount, 1);
APSARA_TEST_EQUAL(daemonClone->mRefCount, 0);
APSARA_TEST_EQUAL(daemonProc->mRefCount, 1);
APSARA_TEST_EQUAL(appClone->mRefCount, 0);
APSARA_TEST_EQUAL(appProc->mRefCount, 1);
// check output events
eventCount = mEventQueue.try_dequeue_bulk(items.data(), items.size());
APSARA_TEST_EQUAL_FATAL(1UL, eventCount);
auto& event6 = (ProcessExitEvent&)(*items[0]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXIT_EVENT, event6.mEventType);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.current.pid, event6.mPid);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.current.ktime, event6.mKtime);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.common.ktime, event6.mTimestamp);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.info.code, event6.mExitCode);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.info.tid, event6.mExitTid);
}
/*
* Before daemon exit
* Lineage: ┌------------┐ ┌--------------┐ ┌-----------------------------┐
* CallChain: (sh) -execve- (bash) -execve- (daemon) -clone- (app) -execve- (app)
* RefCnt: 0 1 2 0 1
* After daemon exit
* Lineage: ┌------------┐ ┌--------------┐ ┌-----------------------------┐
* CallChain: (sh) -execve- (bash) -execve- (daemon) -clone- (app) -execve- (app)
* RefCnt: 0 0 1 0 1
*/
void ProcessCacheManagerUnittest::TestRecordEventExecveExit() {
mProcessCacheManager->MarkProcessEventFlushStatus(true);
// sprawn processes
msg_execve_event shExecveEvent = CreateStubExecveEvent();
shExecveEvent.common.ktime = 20;
shExecveEvent.process.pid = 2;
shExecveEvent.process.ktime = 20;
shExecveEvent.parent.pid = 1;
shExecveEvent.parent.ktime = 1;
constexpr char shBinary[] = "/usr/bin/sh";
memcpy(shExecveEvent.buffer + SIZEOF_EVENT, shBinary, sizeof(shBinary));
shExecveEvent.process.size = sizeof(shBinary) + SIZEOF_EVENT;
shExecveEvent.process.flags |= EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&shExecveEvent);
msg_execve_event bashExecveEvent = CreateStubExecveEvent();
bashExecveEvent.common.ktime = 21;
bashExecveEvent.process.pid = 2;
bashExecveEvent.process.ktime = 21;
bashExecveEvent.parent.pid = 1;
bashExecveEvent.parent.ktime = 1;
bashExecveEvent.cleanup_key.pid = shExecveEvent.process.pid;
bashExecveEvent.cleanup_key.ktime = shExecveEvent.process.ktime;
constexpr char bashBinary[] = "/usr/bin/bash";
memcpy(bashExecveEvent.buffer + SIZEOF_EVENT, bashBinary, sizeof(bashBinary));
bashExecveEvent.process.size = sizeof(bashBinary) + SIZEOF_EVENT;
bashExecveEvent.process.flags &= ~EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&bashExecveEvent);
msg_execve_event daemonExecveEvent = CreateStubExecveEvent();
daemonExecveEvent.common.ktime = 22;
daemonExecveEvent.process.pid = 2;
daemonExecveEvent.process.ktime = 22;
daemonExecveEvent.parent.pid = 1;
daemonExecveEvent.parent.ktime = 1;
daemonExecveEvent.cleanup_key.pid = bashExecveEvent.process.pid;
daemonExecveEvent.cleanup_key.ktime = bashExecveEvent.process.ktime;
constexpr char daemonBinary[] = "/usr/local/bin/daemon";
memcpy(daemonExecveEvent.buffer + SIZEOF_EVENT, daemonBinary, sizeof(daemonBinary));
daemonExecveEvent.process.size = sizeof(daemonBinary) + SIZEOF_EVENT;
daemonExecveEvent.process.flags &= ~EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&daemonExecveEvent);
msg_clone_event appCloneEvent{};
appCloneEvent.common.ktime = 40;
appCloneEvent.tgid = 4;
appCloneEvent.ktime = 40;
appCloneEvent.parent.pid = daemonExecveEvent.process.pid;
appCloneEvent.parent.ktime = daemonExecveEvent.process.ktime;
mProcessCacheManager->RecordCloneEvent(&appCloneEvent);
msg_execve_event appExecveEvent = CreateStubExecveEvent();
appExecveEvent.process.pid = 4;
appExecveEvent.process.ktime = 41;
appExecveEvent.parent.pid = daemonExecveEvent.process.pid;
appExecveEvent.parent.ktime = daemonExecveEvent.process.ktime;
appExecveEvent.cleanup_key.pid = appCloneEvent.tgid;
appExecveEvent.cleanup_key.ktime = appCloneEvent.ktime;
constexpr char appBinary[] = "/usr/local/bin/app";
memcpy(appExecveEvent.buffer + SIZEOF_EVENT, appBinary, sizeof(appBinary));
appExecveEvent.process.size = sizeof(appBinary) + SIZEOF_EVENT;
appExecveEvent.process.flags |= EVENT_CLONE;
mProcessCacheManager->RecordExecveEvent(&appExecveEvent);
// check cache
auto shProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{shExecveEvent.process.pid, shExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(shProc != nullptr);
APSARA_TEST_EQUAL((*shProc).Get<kBinary>().to_string(), shBinary);
APSARA_TEST_EQUAL(shProc->mRefCount, 0);
auto bashProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{bashExecveEvent.process.pid, bashExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(bashProc != nullptr);
APSARA_TEST_EQUAL((*bashProc).Get<kBinary>().to_string(), bashBinary);
APSARA_TEST_EQUAL(bashProc->mRefCount, 1);
auto daemonProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{daemonExecveEvent.process.pid, daemonExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(daemonProc != nullptr);
APSARA_TEST_EQUAL((*daemonProc).Get<kBinary>().to_string(), daemonBinary);
APSARA_TEST_EQUAL(daemonProc->mRefCount, 2);
auto appClone = mProcessCacheManager->mProcessCache.Lookup(data_event_id{appCloneEvent.tgid, appCloneEvent.ktime});
APSARA_TEST_TRUE_FATAL(appClone != nullptr);
APSARA_TEST_EQUAL((*appClone).Get<kBinary>().to_string(), daemonBinary);
APSARA_TEST_EQUAL(appClone->mRefCount, 0);
auto appProc = mProcessCacheManager->mProcessCache.Lookup(
data_event_id{appExecveEvent.process.pid, appExecveEvent.process.ktime});
APSARA_TEST_TRUE_FATAL(appProc != nullptr);
APSARA_TEST_EQUAL((*appProc).Get<kBinary>().to_string(), appBinary);
APSARA_TEST_EQUAL(appProc->mRefCount, 1);
// check output events
std::array<std::shared_ptr<CommonEvent>, 10> items{};
size_t eventCount = mEventQueue.try_dequeue_bulk(items.data(), items.size());
APSARA_TEST_EQUAL_FATAL(5UL, eventCount);
auto& event0 = (ProcessEvent&)(*items[0]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event0.mEventType);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.process.pid, event0.mPid);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.process.ktime, event0.mKtime);
APSARA_TEST_EQUAL_FATAL(shExecveEvent.common.ktime, event0.mTimestamp);
auto& event1 = (ProcessEvent&)(*items[1]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event1.mEventType);
APSARA_TEST_EQUAL_FATAL(bashExecveEvent.process.pid, event1.mPid);
APSARA_TEST_EQUAL_FATAL(bashExecveEvent.process.ktime, event1.mKtime);
APSARA_TEST_EQUAL_FATAL(bashExecveEvent.common.ktime, event1.mTimestamp);
auto& event2 = (ProcessEvent&)(*items[2]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event2.mEventType);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.process.pid, event2.mPid);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.process.ktime, event2.mKtime);
APSARA_TEST_EQUAL_FATAL(daemonExecveEvent.common.ktime, event2.mTimestamp);
auto& event3 = (ProcessEvent&)(*items[3]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_CLONE_EVENT, event3.mEventType);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.tgid, event3.mPid);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.ktime, event3.mKtime);
APSARA_TEST_EQUAL_FATAL(appCloneEvent.common.ktime, event3.mTimestamp);
auto& event4 = (ProcessEvent&)(*items[4]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXECVE_EVENT, event4.mEventType);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.process.pid, event4.mPid);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.process.ktime, event4.mKtime);
APSARA_TEST_EQUAL_FATAL(appExecveEvent.common.ktime, event4.mTimestamp);
// daemon exit
msg_exit daemonExitEvent{};
daemonExitEvent.common.ktime = 60;
daemonExitEvent.current.pid = daemonExecveEvent.process.pid;
daemonExitEvent.current.ktime = daemonExecveEvent.process.ktime;
daemonExitEvent.info.code = -1;
daemonExitEvent.info.tid = 3;
mProcessCacheManager->RecordExitEvent(&daemonExitEvent);
// check cache
APSARA_TEST_EQUAL(shProc->mRefCount, 0);
APSARA_TEST_EQUAL(bashProc->mRefCount, 0);
APSARA_TEST_EQUAL(daemonProc->mRefCount, 1);
APSARA_TEST_EQUAL(appClone->mRefCount, 0);
APSARA_TEST_EQUAL(appProc->mRefCount, 1);
// check output events
eventCount = mEventQueue.try_dequeue_bulk(items.data(), items.size());
APSARA_TEST_EQUAL_FATAL(1UL, eventCount);
auto& event6 = (ProcessExitEvent&)(*items[0]);
APSARA_TEST_EQUAL_FATAL(KernelEventType::PROCESS_EXIT_EVENT, event6.mEventType);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.current.pid, event6.mPid);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.current.ktime, event6.mKtime);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.common.ktime, event6.mTimestamp);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.info.code, event6.mExitCode);
APSARA_TEST_EQUAL_FATAL(daemonExitEvent.info.tid, event6.mExitTid);
}
void ProcessCacheManagerUnittest::TestFinalizeProcessTags() {
// 创建进程事件
data_event_id key{1234, 5678};
auto execveEvent = std::make_shared<ProcessCacheValue>();
execveEvent->SetContent<kProcessId>(StringView("1234"));
execveEvent->SetContent<kKtime>(StringView("5678"));
execveEvent->SetContent<kUid>(StringView("1000"));
execveEvent->SetContent<kBinary>(StringView("test_binary"));
execveEvent->mPPid = 2345;
execveEvent->mPKtime = 6789;
// parent
data_event_id pKey{2345, 6789};
auto pExecveEvent = std::make_shared<ProcessCacheValue>();
pExecveEvent->SetContent<kProcessId>(StringView("2345"));
pExecveEvent->SetContent<kKtime>(StringView("6789"));
pExecveEvent->SetContent<kUid>(StringView("1000"));
pExecveEvent->SetContent<kBinary>(StringView("test_binary_parent"));
// 更新缓存
mProcessCacheManager->mProcessCache.AddCache(key, std::move(execveEvent));
mProcessCacheManager->mProcessCache.AddCache(pKey, std::move(pExecveEvent));
// 测试进程标签生成
PipelineEventGroup sharedEventGroup(std::make_shared<SourceBuffer>());
auto sharedEvent = sharedEventGroup.CreateLogEvent();
APSARA_TEST_TRUE(mProcessCacheManager->FinalizeProcessTags(key.pid, key.time, *sharedEvent));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kProcessId.LogKey()), StringView("1234"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kKtime.LogKey()), StringView("5678"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kUid.LogKey()), StringView("1000"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kBinary.LogKey()), StringView("test_binary"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kParentProcessId.LogKey()), StringView("2345"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kParentKtime.LogKey()), StringView("6789"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kParentUid.LogKey()), StringView("1000"));
APSARA_TEST_EQUAL(sharedEvent->GetContent(kParentBinary.LogKey()), StringView("test_binary_parent"));
}
// void ProcessCacheManagerUnittest::TestPollPerfBuffers() {
// // 初始化ProcessCacheManager
// APSARA_TEST_TRUE(mProcessCacheManager->Init());
// // 测试PerfBuffer轮询
// mProcessCacheManager->pollPerfBuffers();
// // 测试停止操作
// mProcessCacheManager->Stop();
// }
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestListRunningProcs);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestProcToProcessCacheValue);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestRecordDataEventNormal);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestDataGetAndRemoveSizeBad);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestRecordDataEventExceedLimit);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgExecveEventToProcessCacheValueNoClone);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgExecveEventToProcessCacheValueLongFilename);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgExecveEventToProcessCacheValueLongArgs);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgExecveEventToProcessCacheValueNoArgs);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgExecveEventToProcessCacheValueNoArgsNoCwd);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgCloneEventToProcessCacheValue);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestMsgCloneEventToProcessCacheValueParentNotFound);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestRecordEventCloneExecveExit);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestRecordEventExecveExit);
UNIT_TEST_CASE(ProcessCacheManagerUnittest, TestFinalizeProcessTags);
UNIT_TEST_MAIN