Skip to content

Commit e93d80c

Browse files
cel: Add path, target.is_platform_binary and target.team_id fields (#863)
1 parent 3177cf4 commit e93d80c

15 files changed

Lines changed: 196 additions & 8 deletions

File tree

.github/workflows/check-markdown.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
- name: "Checkout Santa"
1414
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
1515
- name: "Check for deadlinks"
16-
uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # ratchet:lycheeverse/lychee-action@v2
16+
uses: lycheeverse/lychee-action@2b973e86fc7b1f6b36a93795fe2c9c6ae1118621 # ratchet:lycheeverse/lychee-action@v1
1717
with:
1818
fail: true
1919
- name: "Check for trailing whitespace and newlines"

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ bazel_dep(name = "boringssl", version = "0.20260211.0")
1717
bazel_dep(name = "protos", version = "1.0.1", repo_name = "northpolesec_protos")
1818
git_override(
1919
module_name = "protos",
20-
commit = "53b9f4e4db95e927f095754c24c12028bae03abc",
20+
commit = "fa0ad3f19cd1e32ec4946331e94fb1e13e9df4ea",
2121
remote = "https://github.com/northpolesec/protos",
2222
)
2323

Source/common/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ cc_proto_library(
2626
deps = [":santa_proto"],
2727
)
2828

29-
3029
objc_library(
3130
name = "PowerMonitor",
3231
srcs = ["PowerMonitor.mm"],

Source/common/cel/Activation.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ class Activation : public ::google::api::expr::runtime::BaseActivation {
4949

5050
Activation(std::unique_ptr<ExecutableFileT> file, std::vector<std::string> (^args)(),
5151
std::map<std::string, std::string> (^envs)(), uid_t (^euid)(), std::string (^cwd)(),
52-
std::vector<AncestorT> (^ancestors)(), std::vector<FileDescriptorT> (^fds)())
52+
std::string (^path)(), std::vector<AncestorT> (^ancestors)(),
53+
std::vector<FileDescriptorT> (^fds)())
5354
: file_(std::move(file)),
5455
args_(args),
5556
envs_(envs),
5657
euid_(euid),
5758
cwd_(cwd),
59+
path_(path),
5860
ancestors_(ancestors),
5961
fds_(fds) {};
6062
~Activation() = default;
@@ -80,6 +82,7 @@ class Activation : public ::google::api::expr::runtime::BaseActivation {
8082
Memoizer<std::map<std::string, std::string>> envs_;
8183
Memoizer<uid_t> euid_;
8284
Memoizer<std::string> cwd_;
85+
Memoizer<std::string> path_;
8386
Memoizer<std::vector<AncestorT>> ancestors_;
8487
Memoizer<std::vector<FileDescriptorT>> fds_;
8588

Source/common/cel/Activation.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@
158158
return CELValue(euid_(), arena);
159159
} else if (name == "cwd") {
160160
return CELValue(cwd_(), arena);
161+
} else if (name == "path") {
162+
return CELValue(path_(), arena);
161163
}
162164

163165
// Handle the V2 specific fields
@@ -248,7 +250,8 @@
248250

249251
template <bool IsV2>
250252
bool Activation<IsV2>::IsResultCacheable() const {
251-
if (args_.HasValue() || envs_.HasValue() || euid_.HasValue() || cwd_.HasValue()) {
253+
if (args_.HasValue() || envs_.HasValue() || euid_.HasValue() || cwd_.HasValue() ||
254+
path_.HasValue()) {
252255
return false;
253256
}
254257

Source/common/cel/ArenaGrowthTest.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ - (void)testCompileAndEvaluateArenaGrowth {
9393
^std::string() {
9494
return "/usr/local/bin";
9595
},
96+
^std::string() {
97+
return "/usr/bin/test";
98+
},
9699
^std::vector<AncestorT>() {
97100
return {};
98101
},
@@ -133,6 +136,9 @@ - (void)testCompileAndEvaluateArenaGrowth {
133136
^std::string() {
134137
return "/usr/local/bin";
135138
},
139+
^std::string() {
140+
return "/usr/bin/test";
141+
},
136142
^std::vector<AncestorT>() {
137143
return {};
138144
},

Source/common/cel/Test.mm

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ - (void)testBasic {
3939

4040
auto f = std::make_unique<ExecutableFileT>();
4141
f->mutable_signing_time()->set_seconds(1748436989);
42+
f->set_is_platform_binary(false);
43+
f->set_team_id("EQHXZ8M8AV");
4244
santa::cel::Activation<true> activation(
4345
std::move(f),
4446
^std::vector<std::string>() {
@@ -53,6 +55,9 @@ - (void)testBasic {
5355
^std::string() {
5456
return "/";
5557
},
58+
^std::string() {
59+
return "/usr/bin/test";
60+
},
5661
^std::vector<AncestorT>() {
5762
return {};
5863
},
@@ -92,6 +97,37 @@ - (void)testBasic {
9297
XCTAssertEqual(result.value().cacheable, true);
9398
}
9499
}
100+
{
101+
// Static - is_platform_binary on target
102+
auto result = sut.value()->CompileAndEvaluate("target.is_platform_binary == false", activation);
103+
if (!result.ok()) {
104+
XCTFail("Failed to evaluate: %s", result.status().message().data());
105+
} else {
106+
XCTAssertEqual(result.value().value, ReturnValue::ALLOWLIST);
107+
XCTAssertEqual(result.value().cacheable, true);
108+
}
109+
}
110+
{
111+
// Static - team_id on target
112+
auto result = sut.value()->CompileAndEvaluate("target.team_id == 'EQHXZ8M8AV'", activation);
113+
if (!result.ok()) {
114+
XCTFail("Failed to evaluate: %s", result.status().message().data());
115+
} else {
116+
XCTAssertEqual(result.value().value, ReturnValue::ALLOWLIST);
117+
XCTAssertEqual(result.value().cacheable, true);
118+
}
119+
}
120+
{
121+
// Combined - is_platform_binary and team_id
122+
auto result = sut.value()->CompileAndEvaluate(
123+
"!target.is_platform_binary && target.team_id == 'EQHXZ8M8AV'", activation);
124+
if (!result.ok()) {
125+
XCTFail("Failed to evaluate: %s", result.status().message().data());
126+
} else {
127+
XCTAssertEqual(result.value().value, ReturnValue::ALLOWLIST);
128+
XCTAssertEqual(result.value().cacheable, true);
129+
}
130+
}
95131
{
96132
// Re-use of a compiled expression.
97133
google::protobuf::Arena arena;
@@ -125,6 +161,9 @@ - (void)testBasic {
125161
^std::string() {
126162
return "/Users/foo";
127163
},
164+
^std::string() {
165+
return "/usr/bin/test";
166+
},
128167
^std::vector<santa::cel::v2::Ancestor>() {
129168
return {};
130169
},
@@ -179,6 +218,9 @@ - (void)testBasic {
179218
^std::string {
180219
return "/";
181220
},
221+
^std::string() {
222+
return "/usr/bin/test";
223+
},
182224
^std::vector<santa::cel::v2::Ancestor>() {
183225
return {};
184226
},
@@ -206,6 +248,26 @@ - (void)testBasic {
206248
XCTAssertEqual(result.value().cacheable, false);
207249
}
208250
}
251+
{
252+
// Dynamic - filepath via path field
253+
auto result = sut.value()->CompileAndEvaluate("path == '/usr/bin/test'", activation);
254+
if (!result.ok()) {
255+
XCTFail("Failed to evaluate: %s", result.status().message().data());
256+
} else {
257+
XCTAssertEqual(result.value().value, ReturnValue::ALLOWLIST);
258+
XCTAssertEqual(result.value().cacheable, false);
259+
}
260+
}
261+
{
262+
// Dynamic - path with startsWith
263+
auto result = sut.value()->CompileAndEvaluate("path.startsWith('/usr/bin')", activation);
264+
if (!result.ok()) {
265+
XCTFail("Failed to evaluate: %s", result.status().message().data());
266+
} else {
267+
XCTAssertEqual(result.value().value, ReturnValue::ALLOWLIST);
268+
XCTAssertEqual(result.value().cacheable, false);
269+
}
270+
}
209271
}
210272

211273
- (void)testV2Only {
@@ -221,6 +283,9 @@ - (void)testV2Only {
221283
auto cwdFn = ^std::string() {
222284
return "/";
223285
};
286+
auto pathFn = ^std::string() {
287+
return "/usr/bin/test";
288+
};
224289
auto ancestorsV1Fn = ^std::vector<santa::cel::CELProtoTraits<false>::AncestorT>() {
225290
return {};
226291
};
@@ -238,7 +303,7 @@ - (void)testV2Only {
238303
// V1
239304
auto f = std::make_unique<santa::cel::CELProtoTraits<false>::ExecutableFileT>();
240305
f->mutable_signing_time()->set_seconds(1748436989);
241-
santa::cel::Activation<false> activation(std::move(f), argsFn, envsFn, euidFn, cwdFn,
306+
santa::cel::Activation<false> activation(std::move(f), argsFn, envsFn, euidFn, cwdFn, pathFn,
242307
ancestorsV1Fn, fdsV1Fn);
243308
auto sut = santa::cel::Evaluator<false>::Create();
244309
XCTAssertTrue(sut.ok());
@@ -254,7 +319,7 @@ - (void)testV2Only {
254319
using ReturnValue = santa::cel::CELProtoTraits<true>::ReturnValue;
255320
auto f = std::make_unique<santa::cel::CELProtoTraits<true>::ExecutableFileT>();
256321
f->mutable_signing_time()->set_seconds(1748436989);
257-
santa::cel::Activation<true> activation(std::move(f), argsFn, envsFn, euidFn, cwdFn,
322+
santa::cel::Activation<true> activation(std::move(f), argsFn, envsFn, euidFn, cwdFn, pathFn,
258323
ancestorsV2Fn, fdsV2Fn);
259324
auto sut = santa::cel::Evaluator<true>::Create();
260325
XCTAssertTrue(sut.ok());
@@ -292,6 +357,9 @@ - (void)testFds {
292357
^std::string() {
293358
return "/";
294359
},
360+
^std::string() {
361+
return "/usr/bin/test";
362+
},
295363
^std::vector<AncestorT>() {
296364
return {};
297365
},
@@ -387,6 +455,9 @@ - (void)testTouchIDCooldownFunctions {
387455
^std::string() {
388456
return "/";
389457
},
458+
^std::string() {
459+
return "/usr/bin/test";
460+
},
390461
^std::vector<AncestorT>() {
391462
return {};
392463
},
@@ -490,6 +561,9 @@ - (void)testTouchIDCooldownNotAvailableInV1 {
490561
^std::string() {
491562
return "/";
492563
},
564+
^std::string() {
565+
return "/usr/bin/test";
566+
},
493567
^std::vector<AncestorT>() {
494568
return {};
495569
},

Source/santad/CELActivation.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ ActivationCallbackBlock CreateCELActivationBlock(
138138
f->mutable_secure_signing_time()->set_seconds(secureSigningTime.timeIntervalSince1970);
139139
}
140140

141+
f->set_is_platform_binary(isPlatformBinary);
142+
if (teamID) {
143+
f->set_team_id(santa::NSStringToUTF8String(teamID));
144+
}
145+
141146
if constexpr (IsV2) {
142147
if (entitlementsDict) {
143148
auto *entitlements = f->mutable_entitlements();
@@ -179,6 +184,11 @@ ActivationCallbackBlock CreateCELActivationBlock(
179184
if (!f) return std::string();
180185
return std::string(f->path.data, f->path.length);
181186
},
187+
^std::string() {
188+
es_file_t *f = esMsg->event.exec.target->executable;
189+
if (!f) return std::string();
190+
return std::string(f->path.data, f->path.length);
191+
},
182192
^std::vector<AncestorT>() {
183193
return Ancestors<IsV2>(processTree, esMsg);
184194
},

Source/santad/Logs/EndpointSecurity/Writers/FSSpool/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ cc_proto_library(
2323
],
2424
)
2525

26-
2726
cc_library(
2827
name = "fsspool_nowindows",
2928
srcs = ["fsspool_nowindows.cc"],

Source/santad/SNTPolicyProcessorTest.mm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,9 @@ - (void)testCELDecisions {
695695
^std::string() {
696696
return "/";
697697
},
698+
^std::string() {
699+
return "/usr/bin/test";
700+
},
698701
^std::vector<AncestorT>() {
699702
return {};
700703
},
@@ -847,6 +850,9 @@ - (void)testCELAncestors {
847850
^std::string() {
848851
return "/Users/admin";
849852
},
853+
^std::string() {
854+
return "/usr/bin/test";
855+
},
850856
^std::vector<ActivationAncestorT>() {
851857
if constexpr (IsV2) {
852858
AncestorT launchd;
@@ -1027,6 +1033,9 @@ - (ActivationCallbackBlock)fallbackTestActivationCallback {
10271033
^std::string() {
10281034
return "/tmp";
10291035
},
1036+
^std::string() {
1037+
return "/usr/bin/test";
1038+
},
10301039
^std::vector<AncestorT>() {
10311040
return {};
10321041
},
@@ -1052,6 +1061,9 @@ - (ActivationCallbackBlock)fallbackTestActivationCallback {
10521061
^std::string() {
10531062
return "";
10541063
},
1064+
^std::string() {
1065+
return "/usr/bin/test";
1066+
},
10551067
^std::vector<V1AncestorT>() {
10561068
return {};
10571069
},

0 commit comments

Comments
 (0)