Skip to content
This repository was archived by the owner on Feb 5, 2025. It is now read-only.

Commit b735855

Browse files
committed
Add ancestry annotator
1 parent 737525b commit b735855

File tree

17 files changed

+310
-12
lines changed

17 files changed

+310
-12
lines changed

Diff for: Source/common/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
12
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
23
load("//:helper.bzl", "santa_unit_test")
34

Diff for: Source/common/santa.proto

+5-5
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,13 @@ message FileDescriptor {
129129
// Process information
130130
message ProcessInfo {
131131
// Process ID of the process
132-
optional ProcessID id = 1;
132+
optional santa.pb.v1.ProcessID id = 1;
133133

134134
// Process ID of the parent process
135-
optional ProcessID parent_id = 2;
135+
optional santa.pb.v1.ProcessID parent_id = 2;
136136

137137
// Process ID of the process responsible for this one
138-
optional ProcessID responsible_id = 3;
138+
optional santa.pb.v1.ProcessID responsible_id = 3;
139139

140140
// Original parent ID, remains stable in the event a process is reparented
141141
optional int32 original_parent_pid = 4;
@@ -181,10 +181,10 @@ message ProcessInfo {
181181
// Light variant of ProcessInfo message to help minimize on-disk/on-wire sizes
182182
message ProcessInfoLight {
183183
// Process ID of the process
184-
optional ProcessID id = 1;
184+
optional santa.pb.v1.ProcessID id = 1;
185185

186186
// Process ID of the parent process
187-
optional ProcessID parent_id = 2;
187+
optional santa.pb.v1.ProcessID parent_id = 2;
188188

189189
// Original parent ID, remains stable in the event a process is reparented
190190
optional int32 original_parent_pid = 3;

Diff for: Source/santad/BUILD

+1-1
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,7 @@ objc_library(
802802
"//Source/common:Unit",
803803
"//Source/santad/ProcessTree:process_tree",
804804
"//Source/santad/ProcessTree/annotations:originator",
805+
"//Source/santad/ProcessTree/annotations:ancestry",
805806
"@MOLXPCConnection",
806807
],
807808
)
@@ -840,7 +841,6 @@ macos_bundle(
840841
],
841842
entitlements = select({
842843
"//:adhoc_build": "com.google.santa.daemon.systemextension-adhoc.entitlements",
843-
# Non-adhoc builds get their entitlements from the provisioning profile.
844844
"//conditions:default": None,
845845
}),
846846
infoplists = ["Info.plist"],

Diff for: Source/santad/Logs/EndpointSecurity/Writers/FSSpool/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
12
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
23
load("//:helper.bzl", "santa_unit_test")
34

Diff for: Source/santad/ProcessTree/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
12
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
23
load("//:helper.bzl", "santa_unit_test")
34

Diff for: Source/santad/ProcessTree/annotations/BUILD

+24
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ cc_library(
2525
],
2626
)
2727

28+
cc_library(
29+
name = "ancestry",
30+
srcs = ["ancestry.cc"],
31+
hdrs = ["ancestry.h"],
32+
deps = [
33+
":annotator",
34+
"//Source/santad/ProcessTree:process",
35+
"//Source/santad/ProcessTree:process_tree",
36+
"//Source/santad/ProcessTree:process_tree_cc_proto",
37+
"@com_google_absl//absl/container:flat_hash_map",
38+
],
39+
)
40+
2841
santa_unit_test(
2942
name = "originator_test",
3043
srcs = ["originator_test.mm"],
@@ -35,3 +48,14 @@ santa_unit_test(
3548
"//Source/santad/ProcessTree:process_tree_test_helpers",
3649
],
3750
)
51+
52+
santa_unit_test(
53+
name = "ancestry_test",
54+
srcs = ["ancestry_test.mm"],
55+
deps = [
56+
":ancestry",
57+
"//Source/santad/ProcessTree:process",
58+
"//Source/santad/ProcessTree:process_tree_cc_proto",
59+
"//Source/santad/ProcessTree:process_tree_test_helpers",
60+
],
61+
)

Diff for: Source/santad/ProcessTree/annotations/ancestry.cc

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/// Copyright 2023 Google LLC
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// https://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
#include "Source/santad/ProcessTree/annotations/ancestry.h"
15+
16+
#include "Source/santad/ProcessTree/process.h"
17+
#include "Source/santad/ProcessTree/process_tree.h"
18+
#include "Source/santad/ProcessTree/process_tree.pb.h"
19+
#include "absl/container/flat_hash_map.h"
20+
21+
namespace ptpb = ::santa::pb::v1::process_tree;
22+
23+
namespace santa::santad::process_tree {
24+
25+
::santa::pb::v1::process_tree::Annotations::Ancestry
26+
AncestryAnnotator::getAncestry() const {
27+
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry;
28+
ancestry.CopyFrom(ancestry_);
29+
return ancestry;
30+
}
31+
32+
void AncestryAnnotator::AddProcessToAncestry(
33+
ptpb::Annotations::Ancestry &ancestry, const Process &process) {
34+
ptpb::AncestryProcessID *ancestor = ancestry.add_ancestor();
35+
ancestor->set_pid(process.pid_.pid);
36+
ancestor->set_secondary_id(process.creation_timestamp);
37+
}
38+
39+
void AncestryAnnotator::AnnotateFork(ProcessTree &tree, const Process &parent,
40+
const Process &child) {
41+
ptpb::Annotations::Ancestry ancestry;
42+
43+
// If parent process has ancestry annotation, copy and add parent.
44+
if (auto parent_annotation = tree.GetAnnotation<AncestryAnnotator>(parent)) {
45+
ancestry.CopyFrom((*parent_annotation)->getAncestry());
46+
AddProcessToAncestry(ancestry, parent);
47+
// Otherwise, get all ancestors of the child and add them.
48+
} else {
49+
std::vector<ptpb::AncestryProcessID> ancestors = tree.GetAncestors(child);
50+
// Add ancestors starting from the root process
51+
for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) {
52+
ptpb::AncestryProcessID *ancestor = ancestry.add_ancestor();
53+
ancestor->set_pid(it->pid());
54+
ancestor->set_secondary_id(it->secondary_id());
55+
}
56+
}
57+
tree.AnnotateProcess(child, std::make_shared<AncestryAnnotator>(ancestry));
58+
}
59+
60+
void AncestryAnnotator::AnnotateExec(ProcessTree &tree,
61+
const Process &orig_process,
62+
const Process &new_process) {
63+
// Do not annotate process on exec
64+
return;
65+
}
66+
67+
std::optional<ptpb::Annotations> AncestryAnnotator::Proto() const {
68+
auto annotation = ptpb::Annotations();
69+
auto *ancestry_ptr = annotation.mutable_ancestry();
70+
ancestry_ptr->CopyFrom(AncestryAnnotator::getAncestry());
71+
return annotation;
72+
}
73+
74+
} // namespace santa::santad::process_tree

Diff for: Source/santad/ProcessTree/annotations/ancestry.h

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// Copyright 2023 Google LLC
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// https://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
#ifndef SANTA__SANTAD_PROCESSTREE_ANNOTATIONS_ANCESTRY_H
15+
#define SANTA__SANTAD_PROCESSTREE_ANNOTATIONS_ANCESTRY_H
16+
17+
#include <optional>
18+
19+
#include "Source/santad/ProcessTree/annotations/annotator.h"
20+
#include "Source/santad/ProcessTree/process.h"
21+
#include "Source/santad/ProcessTree/process_tree.pb.h"
22+
23+
namespace santa::santad::process_tree {
24+
25+
class AncestryAnnotator : public Annotator {
26+
public:
27+
// clang-format off
28+
AncestryAnnotator() {}
29+
explicit AncestryAnnotator(
30+
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry)
31+
: ancestry_(ancestry) {};
32+
// clang-format on
33+
void AnnotateFork(ProcessTree &tree, const Process &parent,
34+
const Process &child) override;
35+
void AnnotateExec(ProcessTree &tree, const Process &orig_process,
36+
const Process &new_process) override;
37+
std::optional<::santa::pb::v1::process_tree::Annotations> Proto()
38+
const override;
39+
::santa::pb::v1::process_tree::Annotations::Ancestry getAncestry() const;
40+
41+
private:
42+
void AddProcessToAncestry(
43+
::santa::pb::v1::process_tree::Annotations::Ancestry &ancestry,
44+
const Process &process);
45+
::santa::pb::v1::process_tree::Annotations::Ancestry ancestry_;
46+
};
47+
48+
} // namespace santa::santad::process_tree
49+
50+
#endif
+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/// Copyright 2023 Google LLC
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// https://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
15+
#import <Foundation/Foundation.h>
16+
#import <XCTest/XCTest.h>
17+
18+
#include "Source/santad/ProcessTree/annotations/ancestry.h"
19+
#include "Source/santad/ProcessTree/process.h"
20+
#include "Source/santad/ProcessTree/process_tree.pb.h"
21+
#include "Source/santad/ProcessTree/process_tree_test_helpers.h"
22+
23+
using namespace santa::santad::process_tree;
24+
namespace ptpb = ::santa::pb::v1::process_tree;
25+
26+
@interface AncestryAnnotatorTest : XCTestCase
27+
@property std::shared_ptr<ProcessTreeTestPeer> tree;
28+
@property std::shared_ptr<const Process> initProc;
29+
@end
30+
31+
@implementation AncestryAnnotatorTest
32+
33+
- (void)setUp {
34+
std::vector<std::unique_ptr<Annotator>> annotators;
35+
annotators.emplace_back(std::make_unique<AncestryAnnotator>());
36+
self.tree = std::make_shared<ProcessTreeTestPeer>(std::move(annotators));
37+
self.initProc = self.tree->InsertInit();
38+
}
39+
40+
- (void)testSingleFork_childHasAncestryAnnotation {
41+
uint64_t event_id = 123;
42+
// PID 1.1: fork() -> PID 2.2
43+
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
44+
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
45+
46+
auto child = *self.tree->Get(child_pid);
47+
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*child);
48+
XCTAssertTrue(annotation_opt.has_value());
49+
auto proto_opt = (*annotation_opt)->Proto();
50+
51+
XCTAssertTrue(proto_opt.has_value());
52+
XCTAssertEqual(proto_opt->ancestry().ancestor_size(), 1);
53+
XCTAssertEqual(proto_opt->ancestry().ancestor().Get(0).pid(), 1);
54+
XCTAssertEqual(proto_opt->ancestry().ancestor().Get(0).secondary_id(), 0);
55+
}
56+
57+
- (void)testDoubleFork_grandchildHasAncestryAnnotation {
58+
uint64_t event_id = 123;
59+
// PID 1.1: fork() -> PID 2.2 fork() -> PID 3.3
60+
const struct Pid child_pid = {.pid = 2, .pidversion = 2};
61+
const struct Pid grandchild_pid = {.pid = 3, .pidversion = 3};
62+
63+
self.tree->HandleFork(event_id++, *self.initProc, child_pid);
64+
auto child = *self.tree->Get(child_pid);
65+
self.tree->HandleFork(event_id++, *child, grandchild_pid);
66+
67+
auto grandchild = *self.tree->Get(grandchild_pid);
68+
auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*grandchild);
69+
XCTAssertTrue(annotation_opt.has_value());
70+
auto grandchild_proto_opt = (*annotation_opt)->Proto();
71+
XCTAssertTrue(grandchild_proto_opt.has_value());
72+
auto grandchild_proto = *grandchild_proto_opt;
73+
XCTAssertEqual(grandchild_proto.ancestry().ancestor_size(), 2);
74+
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(0).pid(), 1);
75+
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(0).secondary_id(), 0);
76+
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(1).pid(), 2);
77+
XCTAssertEqual(grandchild_proto.ancestry().ancestor().Get(1).secondary_id(), 123);
78+
}
79+
80+
// - (void)testExec_noEffectOnAncestryAnnotation() {
81+
// uint64_t event_id = 1;
82+
83+
// // PID 1.1: fork() -> PID 2.2
84+
// const struct Pid child_pid = {.pid = 2, .pidversion = 2};
85+
// self.tree->HandleFork(event_id++, *self.initProc, child_pid);
86+
// auto child = *self.tree->Get(child_pid);
87+
// auto annotation_opt = self.tree->GetAnnotation<AncestryAnnotator>(*child);
88+
// XCTAssertTrue(annotation_opt.has_value());
89+
// auto proto_opt = (*annotation_opt)->Proto();
90+
91+
// // PID 2.2: exec("/usr/bin/login") -> PID 2.3
92+
// const struct Pid login_exec_pid = {.pid = 2, .pidversion = 3};
93+
// const struct Program login_prog = {.executable = "/usr/bin/login", .arguments = {}};
94+
// auto login = *self.tree->Get(login_pid);
95+
// self.tree->HandleExec(event_id++, *login, login_exec_pid, login_prog, cred);
96+
// }
97+
98+
@end

Diff for: Source/santad/ProcessTree/process.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ class Process {
7575
public:
7676
explicit Process(const Pid pid, const Cred cred,
7777
std::shared_ptr<const Program> program,
78-
std::shared_ptr<const Process> parent)
78+
std::shared_ptr<const Process> parent,
79+
const uint64_t creation_timestamp)
7980
: pid_(pid),
8081
effective_cred_(cred),
8182
program_(program),
83+
creation_timestamp(creation_timestamp),
8284
annotations_(),
8385
parent_(parent),
8486
refcnt_(0),
@@ -92,6 +94,7 @@ class Process {
9294
const struct Pid pid_;
9395
const struct Cred effective_cred_;
9496
const std::shared_ptr<const Program> program_;
97+
const uint64_t creation_timestamp;
9598

9699
private:
97100
// This is not API.

0 commit comments

Comments
 (0)