Compare commits

...

1 Commits

Author SHA1 Message Date
Kuba Laguna
73ae919d02 Add ancestry annotator 2024-12-10 17:08:29 +01:00
18 changed files with 451 additions and 16 deletions

View File

@@ -1,3 +1,4 @@
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("//:helper.bzl", "santa_unit_test")

View File

@@ -129,13 +129,13 @@ message FileDescriptor {
// Process information
message ProcessInfo {
// Process ID of the process
optional ProcessID id = 1;
optional santa.pb.v1.ProcessID id = 1;
// Process ID of the parent process
optional ProcessID parent_id = 2;
optional santa.pb.v1.ProcessID parent_id = 2;
// Process ID of the process responsible for this one
optional ProcessID responsible_id = 3;
optional santa.pb.v1.ProcessID responsible_id = 3;
// Original parent ID, remains stable in the event a process is reparented
optional int32 original_parent_pid = 4;
@@ -181,10 +181,10 @@ message ProcessInfo {
// Light variant of ProcessInfo message to help minimize on-disk/on-wire sizes
message ProcessInfoLight {
// Process ID of the process
optional ProcessID id = 1;
optional santa.pb.v1.ProcessID id = 1;
// Process ID of the parent process
optional ProcessID parent_id = 2;
optional santa.pb.v1.ProcessID parent_id = 2;
// Original parent ID, remains stable in the event a process is reparented
optional int32 original_parent_pid = 3;

View File

@@ -802,6 +802,7 @@ objc_library(
"//Source/common:Unit",
"//Source/santad/ProcessTree:process_tree",
"//Source/santad/ProcessTree/annotations:originator",
"//Source/santad/ProcessTree/annotations:ancestry",
"@MOLXPCConnection",
],
)
@@ -840,7 +841,6 @@ macos_bundle(
],
entitlements = select({
"//:adhoc_build": "com.google.santa.daemon.systemextension-adhoc.entitlements",
# Non-adhoc builds get their entitlements from the provisioning profile.
"//conditions:default": None,
}),
infoplists = ["Info.plist"],
@@ -1451,6 +1451,7 @@ test_suite(
"//Source/santad/Logs/EndpointSecurity/Writers/FSSpool:fsspool_test",
"//Source/santad/ProcessTree:process_tree_test",
"//Source/santad/ProcessTree/annotations:originator_test",
"//Source/santad/ProcessTree/annotations:ancestry_test",
],
visibility = ["//:santa_package_group"],
)

View File

@@ -1,3 +1,4 @@
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("//:helper.bzl", "santa_unit_test")

View File

@@ -1,3 +1,4 @@
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("//:helper.bzl", "santa_unit_test")

View File

@@ -25,6 +25,19 @@ cc_library(
],
)
cc_library(
name = "ancestry",
srcs = ["ancestry.cc"],
hdrs = ["ancestry.h"],
deps = [
":annotator",
"//Source/santad/ProcessTree:process",
"//Source/santad/ProcessTree:process_tree",
"//Source/santad/ProcessTree:process_tree_cc_proto",
"@com_google_absl//absl/container:flat_hash_map",
],
)
santa_unit_test(
name = "originator_test",
srcs = ["originator_test.mm"],
@@ -35,3 +48,14 @@ santa_unit_test(
"//Source/santad/ProcessTree:process_tree_test_helpers",
],
)
santa_unit_test(
name = "ancestry_test",
srcs = ["ancestry_test.mm"],
deps = [
":ancestry",
"//Source/santad/ProcessTree:process",
"//Source/santad/ProcessTree:process_tree_cc_proto",
"//Source/santad/ProcessTree:process_tree_test_helpers",
],
)

View File

@@ -0,0 +1,89 @@
/// Copyright 2023 Google LLC
///
/// 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
///
/// https://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 "Source/santad/ProcessTree/annotations/ancestry.h"
#include "Source/santad/ProcessTree/process.h"
#include "Source/santad/ProcessTree/process_tree.h"
#include "Source/santad/ProcessTree/process_tree.pb.h"
#include "absl/container/flat_hash_map.h"
namespace ptpb = ::santa::pb::v1::process_tree;
namespace santa::santad::process_tree {
::santa::pb::v1::process_tree::Annotations::Ancestry
AncestryAnnotator::getAncestry() const {
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry;
ancestry.CopyFrom(ancestry_);
return ancestry;
}
void AncestryAnnotator::AddEntryToAncestry(
ptpb::Annotations::Ancestry &ancestry, int pid, uint64_t secondary_id) {
ptpb::AncestryProcessID *ancestor = ancestry.add_ancestor();
ancestor->set_pid(pid);
ancestor->set_secondary_id(secondary_id);
}
void AncestryAnnotator::CopyAncestorsToAncestry(
ptpb::Annotations::Ancestry &ancestry,
std::vector<std::shared_ptr<const Process>> ancestors) {
// Add ancestors starting from the root process
for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) {
AddEntryToAncestry(ancestry, (*it)->pid_.pid, (*it)->creation_timestamp);
}
}
void AncestryAnnotator::AnnotateFork(ProcessTree &tree, const Process &parent,
const Process &child) {
ptpb::Annotations::Ancestry ancestry;
// If parent process has ancestry annotation, copy and add parent.
if (auto parent_annotation = tree.GetAnnotation<AncestryAnnotator>(parent)) {
ancestry.CopyFrom((*parent_annotation)->getAncestry());
AddEntryToAncestry(ancestry, parent.pid_.pid, parent.creation_timestamp);
// Otherwise, get all ancestors of the child and add them.
} else {
std::vector<std::shared_ptr<const Process>> ancestors =
tree.GetAncestors(child);
CopyAncestorsToAncestry(ancestry, ancestors);
}
tree.AnnotateProcess(child, std::make_shared<AncestryAnnotator>(ancestry));
}
void AncestryAnnotator::AnnotateExec(ProcessTree &tree,
const Process &orig_process,
const Process &new_process) {
ptpb::Annotations::Ancestry ancestry;
// If original process has ancestry annotation, copy entries.
if (auto orig_process_annotation =
tree.GetAnnotation<AncestryAnnotator>(orig_process)) {
ancestry.CopyFrom((*orig_process_annotation)->getAncestry());
// Otherwise, compute all ancestors of the new process and add them.
} else {
std::vector<std::shared_ptr<const Process>> ancestors =
tree.GetAncestors(new_process);
CopyAncestorsToAncestry(ancestry, ancestors);
}
tree.AnnotateProcess(new_process,
std::make_shared<AncestryAnnotator>(ancestry));
}
std::optional<ptpb::Annotations> AncestryAnnotator::Proto() const {
auto annotation = ptpb::Annotations();
auto *ancestry_ptr = annotation.mutable_ancestry();
ancestry_ptr->CopyFrom(AncestryAnnotator::getAncestry());
return annotation;
}
} // namespace santa::santad::process_tree

View File

@@ -0,0 +1,53 @@
/// Copyright 2023 Google LLC
///
/// 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
///
/// https://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.
#ifndef SANTA__SANTAD_PROCESSTREE_ANNOTATIONS_ANCESTRY_H
#define SANTA__SANTAD_PROCESSTREE_ANNOTATIONS_ANCESTRY_H
#include <optional>
#include "Source/santad/ProcessTree/annotations/annotator.h"
#include "Source/santad/ProcessTree/process.h"
#include "Source/santad/ProcessTree/process_tree.pb.h"
namespace santa::santad::process_tree {
class AncestryAnnotator : public Annotator {
public:
// clang-format off
AncestryAnnotator() {}
explicit AncestryAnnotator(
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry)
: ancestry_(ancestry) {};
// clang-format on
void AnnotateFork(ProcessTree &tree, const Process &parent,
const Process &child) override;
void AnnotateExec(ProcessTree &tree, const Process &orig_process,
const Process &new_process) override;
std::optional<::santa::pb::v1::process_tree::Annotations> Proto()
const override;
::santa::pb::v1::process_tree::Annotations::Ancestry getAncestry() const;
private:
void AddEntryToAncestry(
::santa::pb::v1::process_tree::Annotations::Ancestry &ancestry, int pid,
uint64_t secondary_id);
void CopyAncestorsToAncestry(
::santa::pb::v1::process_tree::Annotations::Ancestry &ancestry,
std::vector<std::shared_ptr<const Process>> ancestors);
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry_;
};
} // namespace santa::santad::process_tree
#endif

View File

@@ -0,0 +1,193 @@
/// Copyright 2023 Google LLC
///
/// 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
///
/// https://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.
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#include "Source/santad/ProcessTree/annotations/ancestry.h"
#include "Source/santad/ProcessTree/process.h"
#include "Source/santad/ProcessTree/process_tree.pb.h"
#include "Source/santad/ProcessTree/process_tree_test_helpers.h"
using namespace santa::santad::process_tree;
namespace ptpb = ::santa::pb::v1::process_tree;
@interface AncestryAnnotatorTest : XCTestCase
@property std::shared_ptr<ProcessTreeTestPeer> tree;
@property std::shared_ptr<const Process> initProc;
@end
@implementation AncestryAnnotatorTest
- (void)setUp {
std::vector<std::unique_ptr<Annotator>> annotators;
annotators.emplace_back(std::make_unique<AncestryAnnotator>());
self.tree = std::make_shared<ProcessTreeTestPeer>(std::move(annotators));
self.initProc = self.tree->InsertInit();
}
- (void)testSingleFork_childHasAncestryAnnotation {
// PID 1.1: fork() -> PID 1.1
// -> PID 2.2
uint64_t event_id = 123;
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
auto child = *self.tree->Get(child_pid);
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*child);
XCTAssertTrue(annotation_opt.has_value());
auto proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(proto_opt.has_value());
XCTAssertEqual(proto_opt->ancestry().ancestor_size(), 1);
XCTAssertEqual(proto_opt->ancestry().ancestor().Get(0).pid(), 1);
XCTAssertEqual(proto_opt->ancestry().ancestor().Get(0).secondary_id(), 0);
}
- (void)testDoubleFork_grandchildHasAncestryAnnotation {
// PID 1.1: fork() -> PID 1.1
// -> PID 2.2 fork() -> PID 2.2
// -> PID 3.3
uint64_t event_id = 123;
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
const struct Pid grandchild_pid = {.pid = 3, .pidversion = 3};
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
auto child = *self.tree->Get(child_pid);
self.tree->HandleFork(event_id++, *child, grandchild_pid);
auto grandchild = *self.tree->Get(grandchild_pid);
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*grandchild);
XCTAssertTrue(annotation_opt.has_value());
auto grandchild_proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(grandchild_proto_opt.has_value());
auto grandchild_proto = *grandchild_proto_opt;
XCTAssertEqual(grandchild_proto.ancestry().ancestor_size(), 2);
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(0).pid(), 1);
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(0).secondary_id(), 0);
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(1).pid(), 2);
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(1).secondary_id(), 123);
}
- (void)testRootProcessExec_processAfterExecStillHasNoAncestors {
// PID 1.1: exec() -> PID 1.2
uint64_t event_id = 123;
const struct Cred cred = {.uid = 0, .gid = 0};
const struct Pid pid_after_exec = {.pid = 1, .pidversion = 2};
const struct Program program = {.executable = "/any/executable", .arguments = {}};
self.tree->HandleExec(event_id++, *self.initProc, pid_after_exec, program, cred);
auto process_after_exec = *self.tree->Get(pid_after_exec);
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*process_after_exec);
XCTAssertTrue(annotation_opt.has_value());
auto proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(proto_opt.has_value());
auto proto = *proto_opt;
XCTAssertEqual(proto.ancestry().ancestor_size(), 0);
}
- (void)testForkAndExec_processAfterExecHasTheSameAnnotation {
// PID 1.1: fork() -> PID 1.1
// -> PID 2.2 exec() -> PID 2.3
uint64_t event_id = 123;
const struct Cred cred = {.uid = 0, .gid = 0};
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
const struct Pid child_pid_after_exec = {.pid = 2, .pidversion = 3};
const struct Program program = {.executable = "/any/executable", .arguments = {}};
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
auto child = *self.tree->Get(child_pid);
self.tree->HandleExec(event_id++, *child, child_pid_after_exec, program, cred);
auto child_after_exec = *self.tree->Get(child_pid_after_exec);
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*child_after_exec);
XCTAssertTrue(annotation_opt.has_value());
auto proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(proto_opt.has_value());
auto proto = *proto_opt;
XCTAssertEqual(proto.ancestry().ancestor_size(), 1);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).pid(), 1);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).secondary_id(), 0);
}
- (void)testForkAndParentExit_childHasOriginalAncestryAfterParentExit {
// PID 1.1: fork() -> PID 1.1
// -> PID 2.2 fork() -> PID 2.2 exit()
// -> PID 3.3
uint64_t event_id = 123;
const struct Pid parent_pid = {.pid = 2, .pidversion = 2};
const struct Pid child_pid = {.pid = 3, .pidversion = 3};
// Double fork to not call exit on the root process
self.tree->HandleFork(event_id++, *self.initProc, parent_pid);
auto parent = *self.tree->Get(parent_pid);
self.tree->HandleFork(event_id++, *parent, child_pid);
auto child = *self.tree->Get(child_pid);
self.tree->HandleExit(event_id++, *parent);
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*child);
XCTAssertTrue(annotation_opt.has_value());
auto proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(proto_opt.has_value());
auto proto = *proto_opt;
XCTAssertEqual(proto.ancestry().ancestor_size(), 2);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).pid(), 1);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).secondary_id(), 0);
XCTAssertEqual(proto.ancestry().ancestor().Get(1).pid(), 2);
XCTAssertEqual(proto.ancestry().ancestor().Get(1).secondary_id(), 123);
}
- (void)testBackfillInsertChildren_processesHaveAnnotation {
/*
PID 1.1
/ \
PID 2.2 PID 3.3
/
PID 4.4
*/
const struct Cred cred = {.uid = 0, .gid = 0};
const struct Program program = {.executable = "/any/executable", .arguments = {}};
absl::flat_hash_map<pid_t, std::vector<Process>> parent_map;
Process p1 = // root
Process({.pid = 1, .pidversion = 1}, cred, std::make_shared<Program>(program), nullptr, 0);
Process p2 =
Process({.pid = 2, .pidversion = 2}, cred, std::make_shared<Program>(program), nullptr, 0);
Process p3 =
Process({.pid = 3, .pidversion = 3}, cred, std::make_shared<Program>(program), nullptr, 0);
Process p4 =
Process({.pid = 4, .pidversion = 4}, cred, std::make_shared<Program>(program), nullptr, 0);
parent_map[1].push_back(p2);
parent_map[1].push_back(p3);
parent_map[3].push_back(p4);
std::vector<std::unique_ptr<Annotator>> annotators;
annotators.emplace_back(std::make_unique<AncestryAnnotator>());
auto tree = std::make_shared<ProcessTreeTestPeer>(std::move(annotators));
tree->BackfillInsertChildren(parent_map, std::shared_ptr<Process>(), p1);
auto p4_from_tree = *tree->Get(p4.pid_);
auto annotation_opt = tree->GetAnnotation<AncestryAnnotator>(*p4_from_tree);
XCTAssertTrue(annotation_opt.has_value());
auto proto_opt = (*annotation_opt)->Proto();
XCTAssertTrue(proto_opt.has_value());
auto proto = *proto_opt;
XCTAssertEqual(proto.ancestry().ancestor_size(), 2);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).pid(), 1);
XCTAssertEqual(proto.ancestry().ancestor().Get(0).secondary_id(), 0);
XCTAssertEqual(proto.ancestry().ancestor().Get(1).pid(), 3);
XCTAssertEqual(proto.ancestry().ancestor().Get(1).secondary_id(), 0);
}
@end

View File

@@ -75,10 +75,12 @@ class Process {
public:
explicit Process(const Pid pid, const Cred cred,
std::shared_ptr<const Program> program,
std::shared_ptr<const Process> parent)
std::shared_ptr<const Process> parent,
const uint64_t creation_timestamp)
: pid_(pid),
effective_cred_(cred),
program_(program),
creation_timestamp(creation_timestamp),
annotations_(),
parent_(parent),
refcnt_(0),
@@ -92,6 +94,7 @@ class Process {
const struct Pid pid_;
const struct Cred effective_cred_;
const std::shared_ptr<const Program> program_;
const uint64_t creation_timestamp;
private:
// This is not API.

View File

@@ -45,7 +45,7 @@ void ProcessTree::BackfillInsertChildren(
(parent && *(unlinked_proc.program_) == *(parent->program_))
? parent->program_
: unlinked_proc.program_,
parent);
parent, 0);
{
absl::MutexLock lock(&mtx_);
map_.emplace(unlinked_proc.pid_, proc);
@@ -67,6 +67,31 @@ void ProcessTree::BackfillInsertChildren(
}
}
std::vector<std::shared_ptr<const Process>> ProcessTree::GetAncestors(
const Process &process) {
std::vector<std::shared_ptr<const Process>> ancestors;
if (!process.parent_) {
return ancestors;
}
{
absl::MutexLock lock(&mtx_);
std::optional<std::shared_ptr<Process>> ancestor =
GetLocked(process.parent_->pid_);
while (ancestor != std::nullopt) {
// ::santa::pb::v1::process_tree::AncestryProcessID process_id;
// process_id.set_pid((*ancestor)->pid_.pid);
// process_id.set_secondary_id((*ancestor)->creation_timestamp);
ancestors.push_back(*ancestor);
if ((*ancestor)->parent_) {
ancestor = GetLocked((*ancestor)->parent_->pid_);
} else {
ancestor = std::nullopt;
}
}
}
return ancestors;
}
void ProcessTree::HandleFork(uint64_t timestamp, const Process &parent,
const Pid new_pid) {
if (Step(timestamp)) {
@@ -74,7 +99,8 @@ void ProcessTree::HandleFork(uint64_t timestamp, const Process &parent,
{
absl::MutexLock lock(&mtx_);
child = std::make_shared<Process>(new_pid, parent.effective_cred_,
parent.program_, map_[parent.pid_]);
parent.program_, map_[parent.pid_],
timestamp);
map_.emplace(new_pid, child);
}
for (const auto &annotator : annotators_) {
@@ -92,7 +118,8 @@ void ProcessTree::HandleExec(uint64_t timestamp, const Process &p,
assert(new_pid.pid == p.pid_.pid);
auto new_proc = std::make_shared<Process>(
new_pid, c, std::make_shared<const Program>(prog), p.parent_);
new_pid, c, std::make_shared<const Program>(prog), p.parent_,
timestamp);
{
absl::MutexLock lock(&mtx_);
remove_at_.push_back({timestamp, p.pid_});

View File

@@ -43,6 +43,11 @@ class ProcessTree {
// Initialize the tree with the processes currently running on the system.
absl::Status Backfill();
// Returns a vector containing the parent of the process, the parent of the
// parent of the process, etc. up to the root process.
std::vector<std::shared_ptr<const Process>> GetAncestors(
const Process &process);
// Inform the tree of a fork event, in which the parent process spawns a child
// with the only difference between the two being the pid.
void HandleFork(uint64_t timestamp, const Process &parent,
@@ -102,6 +107,10 @@ class ProcessTree {
// Traverse the tree from the given Process to its parent.
std::shared_ptr<const Process> GetParent(const Process &p) const;
void BackfillInsertChildren(
absl::flat_hash_map<pid_t, std::vector<Process>> &parent_map,
std::shared_ptr<Process> parent, const Process &unlinked_proc);
#if SANTA_PROCESS_TREE_DEBUG
// Dump the tree in a human readable form to the given ostream.
void DebugDump(std::ostream &stream) const;
@@ -109,10 +118,6 @@ class ProcessTree {
private:
friend class ProcessTreeTestPeer;
void BackfillInsertChildren(
absl::flat_hash_map<pid_t, std::vector<Process>> &parent_map,
std::shared_ptr<Process> parent, const Process &unlinked_proc);
// Mark that an event with the given timestamp is being processed.
// Returns whether the given timestamp is "novel", and the tree should be
// updated with the results of the event.

View File

@@ -2,6 +2,12 @@ syntax = "proto3";
package santa.pb.v1.process_tree;
message AncestryProcessID {
optional int32 pid = 1;
optional uint64 secondary_id = 2;
}
message Annotations {
enum Originator {
UNSPECIFIED = 0;
@@ -9,5 +15,10 @@ message Annotations {
CRON = 2;
}
message Ancestry {
repeated AncestryProcessID ancestor = 1;
}
Originator originator = 1;
Ancestry ancestry = 2;
}

View File

@@ -134,7 +134,7 @@ absl::StatusOr<Process> LoadPID(pid_t pid) {
.executable = path,
.arguments = args,
}),
nullptr);
nullptr, 0);
}
absl::Status ProcessTree::Backfill() {

View File

@@ -243,4 +243,25 @@ using namespace santa::santad::process_tree;
}
}
- (void)testGetAncestors {
// PID 1.1: fork() -> PID 1.1
// -> PID 2.2 fork() -> PID 2.2
// -> PID 3.3
uint64_t event_id = 1;
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
const struct Pid grandchild_pid = {.pid = 3, .pidversion = 3};
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
auto child = *self.tree->Get(child_pid);
self.tree->HandleFork(event_id++, *child, grandchild_pid);
auto grandchild = *self.tree->Get(grandchild_pid);
auto ancestors = self.tree->GetAncestors(*grandchild);
XCTAssertEqual(ancestors.size(), 2);
XCTAssertEqual(ancestors[0]->pid_.pid, 2);
XCTAssertEqual(ancestors[0]->creation_timestamp, 1);
XCTAssertEqual(ancestors[1]->pid_.pid, 1);
XCTAssertEqual(ancestors[1]->creation_timestamp, 0);
}
@end

View File

@@ -34,7 +34,8 @@ std::shared_ptr<const Process> ProcessTreeTestPeer::InsertInit() {
};
auto proc = std::make_shared<Process>(
initpid, (Cred){.uid = 0, .gid = 0},
std::make_shared<Program>((Program){.executable = "/init", .arguments = {"/init"}}), nullptr);
std::make_shared<Program>((Program){.executable = "/init", .arguments = {"/init"}}), nullptr,
0);
map_.emplace(initpid, proc);
return proc;
}

View File

@@ -24,6 +24,7 @@
#import "Source/santad/DataLayer/SNTRuleTable.h"
#include "Source/santad/DataLayer/WatchItems.h"
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
#include "Source/santad/ProcessTree/annotations/ancestry.h"
#include "Source/santad/ProcessTree/annotations/originator.h"
#include "Source/santad/ProcessTree/process_tree.h"
#import "Source/santad/SNTDatabaseController.h"
@@ -162,6 +163,8 @@ std::unique_ptr<SantadDeps> SantadDeps::Create(SNTConfigurator *configurator,
for (NSString *annotation in [configurator enabledProcessAnnotations]) {
if ([[annotation lowercaseString] isEqualToString:@"originator"]) {
annotators.emplace_back(std::make_unique<santa::santad::process_tree::OriginatorAnnotator>());
} else if ([[annotation lowercaseString] isEqualToString:@"ancestry"]) {
annotators.emplace_back(std::make_unique<santa::santad::process_tree::AncestryAnnotator>());
} else {
LOGW(@"Unrecognized process annotation %@", annotation);
}

View File

@@ -1,3 +1,4 @@
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("//:helper.bzl", "santa_unit_test")