Skip to content

Commit

Permalink
ProcessTree: add core process tree logic (1/4) (#1236)
Browse files Browse the repository at this point in the history
* ProcessTree: add core process tree logic

* make Step implicitly called by Handle* methods

* lint

* naming convention

* widen pidversion to be generic

* move os specific backfill to os specific impl

* simplify ts checking

* retain/release a whole vec of pids

* document processtoken

* lint

* namespace

* add process tree to project-wide unit test target

* case change annotations

* case change annotations

* remove stray comment

* default initialize seen_timestamps

* fix missing initialization of refcnt and tombstoned

* reshuffle pb namespace

* pr review

* move annotation registration to tree construction

* use factory function for tree construction
  • Loading branch information
kallsyms committed Feb 5, 2024
1 parent 70474ab commit e8db89c
Show file tree
Hide file tree
Showing 12 changed files with 1,096 additions and 0 deletions.
1 change: 1 addition & 0 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,7 @@ test_suite(
":SantadTest",
":WatchItemsTest",
"//Source/santad/Logs/EndpointSecurity/Writers/FSSpool:fsspool_test",
"//Source/santad/ProcessTree:process_tree_test",
],
visibility = ["//:santa_package_group"],
)
67 changes: 67 additions & 0 deletions Source/santad/ProcessTree/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("//:helper.bzl", "santa_unit_test")

package(
default_visibility = ["//:santa_package_group"],
)

cc_library(
name = "process",
hdrs = ["process.h"],
deps = [
"//Source/santad/ProcessTree/annotations:annotator",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/synchronization",
],
)

objc_library(
name = "process_tree",
srcs = [
"process_tree.cc",
"process_tree_macos.mm",
],
hdrs = ["process_tree.h"],
sdk_dylibs = [
"bsm",
],
deps = [
":process",
"//Source/santad/ProcessTree/annotations:annotator",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/status",
"@com_google_absl//absl/synchronization",
],
)

proto_library(
name = "process_tree_proto",
srcs = ["process_tree.proto"],
)

cc_proto_library(
name = "process_tree_cc_proto",
deps = [":process_tree_proto"],
)

objc_library(
name = "process_tree_test_helpers",
srcs = ["process_tree_test_helpers.mm"],
hdrs = ["process_tree_test_helpers.h"],
deps = [
":process_tree",
"@com_google_absl//absl/synchronization",
],
)

santa_unit_test(
name = "process_tree_test",
srcs = ["process_tree_test.mm"],
deps = [
":process",
":process_tree_test_helpers",
"//Source/santad/ProcessTree/annotations:annotator",
],
)
11 changes: 11 additions & 0 deletions Source/santad/ProcessTree/annotations/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package(
default_visibility = ["//:santa_package_group"],
)

cc_library(
name = "annotator",
hdrs = ["Annotator.h"],
deps = [
"//Source/santad/ProcessTree:process_tree_cc_proto",
],
)
39 changes: 39 additions & 0 deletions Source/santad/ProcessTree/annotations/annotator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/// 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_BASE_H
#define SANTA__SANTAD_PROCESSTREE_ANNOTATIONS_BASE_H

#include <optional>

#include "Source/santad/ProcessTree/process_tree.pb.h"

namespace santa::santad::process_tree {

class ProcessTree;
class Process;

class Annotator {
public:
virtual ~Annotator() = default;

virtual void AnnotateFork(ProcessTree &tree, const Process &parent,
const Process &child) = 0;
virtual void AnnotateExec(ProcessTree &tree, const Process &orig_process,
const Process &new_process) = 0;
virtual std::optional<::santa::pb::v1::process_tree::Annotations> Proto() const = 0;
};

} // namespace santa::santad::process_tree

#endif
113 changes: 113 additions & 0 deletions Source/santad/ProcessTree/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/// 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_PROCESS_H
#define SANTA__SANTAD_PROCESSTREE_PROCESS_H

#include <unistd.h>

#include <memory>
#include <string>
#include <typeindex>
#include <vector>

#include "Source/santad/ProcessTree/annotations/annotator.h"
#include "absl/container/flat_hash_map.h"

namespace santa::santad::process_tree {

struct Pid {
pid_t pid;
uint64_t pidversion;

friend bool operator==(const struct Pid &lhs, const struct Pid &rhs) {
return lhs.pid == rhs.pid && lhs.pidversion == rhs.pidversion;
}
friend bool operator!=(const struct Pid &lhs, const struct Pid &rhs) {
return !(lhs == rhs);
}
};

template <typename H>
H AbslHashValue(H h, const struct Pid &p) {
return H::combine(std::move(h), p.pid, p.pidversion);
}

struct Cred {
uid_t uid;
gid_t gid;

friend bool operator==(const struct Cred &lhs, const struct Cred &rhs) {
return lhs.uid == rhs.uid && lhs.gid == rhs.gid;
}
friend bool operator!=(const struct Cred &lhs, const struct Cred &rhs) {
return !(lhs == rhs);
}
};

struct Program {
std::string executable;
std::vector<std::string> arguments;

friend bool operator==(const struct Program &lhs, const struct Program &rhs) {
return lhs.executable == rhs.executable && lhs.arguments == rhs.arguments;
}
friend bool operator!=(const struct Program &lhs, const struct Program &rhs) {
return !(lhs == rhs);
}
};

// Fwd decls
class ProcessTree;

class Process {
public:
explicit Process(const Pid pid, const Cred cred,
std::shared_ptr<const Program> program,
std::shared_ptr<const Process> parent)
: pid_(pid),
effective_cred_(cred),
program_(program),
annotations_(),
parent_(parent),
refcnt_(0),
tombstoned_(false) {}
Process(const Process &) = default;
Process& operator=(const Process &) = delete;
Process(Process &&) = default;
Process& operator=(Process &&) = delete;

// Const "attributes" are public
const struct Pid pid_;
const struct Cred effective_cred_;
const std::shared_ptr<const Program> program_;

private:
// This is not API.
// The tree helper methods are the API, and we just happen to implement
// annotation storage and the parent relation in memory on the process right
// now.
friend class ProcessTree;
absl::flat_hash_map<std::type_index, std::shared_ptr<const Annotator>>
annotations_;
std::shared_ptr<const Process> parent_;
// TODO(nickmg): atomic here breaks the build.
int refcnt_;
// If the process is tombstoned, the event removing it from the tree has been
// processed, but refcnt>0 keeps it alive.
bool tombstoned_;
};

} // namespace santa::santad::process_tree

#endif
Loading

0 comments on commit e8db89c

Please sign in to comment.