Skip to content

Commit 7e12a48

Browse files
santad: Populate new signing_id field in CEL context (#793)
Moves activation block creation into a new file to avoid polluting execution controller any further. --------- Signed-off-by: Russell Hancox <russellhancox@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 32d0321 commit 7e12a48

10 files changed

Lines changed: 243 additions & 117 deletions

File tree

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ bazel_dep(name = "boringssl", version = "0.20251110.0")
1818
bazel_dep(name = "protos", version = "1.0.1", repo_name = "northpolesec_protos")
1919
git_override(
2020
module_name = "protos",
21-
commit = "7366338b05136295d7a5be013397130d75cbf1b2",
21+
commit = "836c28d666b0c498d11363a87eac695e8bcb9767",
2222
remote = "https://github.com/northpolesec/protos",
2323
)
2424

Source/santad/BUILD

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,29 @@ santa_unit_test(
375375
],
376376
)
377377

378+
objc_library(
379+
name = "CELActivation",
380+
srcs = ["CELActivation.mm"],
381+
hdrs = ["CELActivation.h"],
382+
deps = [
383+
":EndpointSecurityAPI",
384+
":EndpointSecurityMessage",
385+
":SNTPolicyProcessor",
386+
"//Source/common:MOLCodesignChecker",
387+
"//Source/common:SigningIDHelpers",
388+
"//Source/common:String",
389+
"//Source/common/cel:CEL",
390+
"//Source/santad/ProcessTree:process",
391+
"//Source/santad/ProcessTree:process_tree",
392+
],
393+
)
394+
378395
objc_library(
379396
name = "SNTExecutionController",
380397
srcs = ["SNTExecutionController.mm"],
381398
hdrs = ["SNTExecutionController.h"],
382399
deps = [
400+
":CELActivation",
383401
":EndpointSecurityAPI",
384402
":EndpointSecurityMessage",
385403
":ProcessControl",

Source/santad/CELActivation.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/// Copyright 2026 North Pole Security, Inc.
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+
#ifndef SANTA__SANTAD__CELACTIVATION_H
16+
#define SANTA__SANTAD__CELACTIVATION_H
17+
18+
#import <Foundation/Foundation.h>
19+
20+
#include <memory>
21+
22+
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
23+
#include "Source/santad/ProcessTree/process_tree.h"
24+
#import "Source/santad/SNTPolicyProcessor.h"
25+
26+
@class MOLCodesignChecker;
27+
28+
namespace santa {
29+
30+
// Create a block that returns a santa::cel::Activation object for the given
31+
// Message and MOLCodesignChecker object. The block defines a bool parameter
32+
// that determines whether to create a v1 or v2 activation object.
33+
//
34+
// Note: The returned block captures a reference to the Message object and must
35+
// not use it after the Message object is destroyed. Care must be taken to not
36+
// use this in an asynchronous context outside of the evaluation of that
37+
// execution.
38+
ActivationCallbackBlock _Nonnull CreateCELActivationBlock(
39+
const Message &esMsg, MOLCodesignChecker *_Nullable csInfo,
40+
std::shared_ptr<santad::process_tree::ProcessTree> processTree);
41+
42+
} // namespace santa
43+
44+
#endif // SANTA__SANTAD__CELACTIVATION_H

Source/santad/CELActivation.mm

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/// Copyright 2026 North Pole Security, Inc.
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 "Source/santad/CELActivation.h"
16+
17+
#include <bsm/libbsm.h>
18+
19+
#include <map>
20+
#include <memory>
21+
#include <string>
22+
#include <vector>
23+
24+
#import "Source/common/MOLCodesignChecker.h"
25+
#import "Source/common/SigningIDHelpers.h"
26+
#include "Source/common/String.h"
27+
#include "Source/common/cel/Activation.h"
28+
#include "Source/common/cel/CELProtoTraits.h"
29+
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
30+
#include "Source/santad/ProcessTree/process_tree_macos.h"
31+
32+
namespace {
33+
34+
template <bool IsV2>
35+
std::vector<typename santa::cel::CELProtoTraits<IsV2>::AncestorT> Ancestors(
36+
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
37+
const santa::Message &esMsg);
38+
39+
template <>
40+
std::vector<santa::cel::CELProtoTraits<true>::AncestorT> Ancestors<true>(
41+
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
42+
const santa::Message &esMsg) {
43+
if (!processTree) return {};
44+
45+
using Traits = santa::cel::CELProtoTraits<true>;
46+
using AncestorT = typename Traits::AncestorT;
47+
48+
auto pid = santa::santad::process_tree::PidFromAuditToken(esMsg->process->parent_audit_token);
49+
auto proc = processTree->Get(pid);
50+
if (!proc) {
51+
return {};
52+
}
53+
54+
std::vector<santa::cel::CELProtoTraits<true>::AncestorT> ancestors;
55+
for (const auto &p : processTree->RootSlice(*proc)) {
56+
if (!p->program_) {
57+
continue;
58+
}
59+
60+
AncestorT ancestor;
61+
ancestor.set_path(p->program_->executable);
62+
63+
if (p->program_->code_signing) {
64+
const auto &cs = *p->program_->code_signing;
65+
if (cs.is_platform_binary) {
66+
ancestor.set_signing_id("platform:" + cs.signing_id);
67+
} else {
68+
ancestor.set_signing_id(cs.team_id + ":" + cs.signing_id);
69+
}
70+
ancestor.set_team_id(cs.team_id);
71+
ancestor.set_cdhash(cs.cdhash);
72+
}
73+
74+
ancestors.push_back(std::move(ancestor));
75+
}
76+
return ancestors;
77+
}
78+
79+
template <>
80+
std::vector<santa::cel::CELProtoTraits<false>::AncestorT> Ancestors<false>(
81+
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
82+
const santa::Message &esMsg) {
83+
return {};
84+
}
85+
86+
} // namespace
87+
88+
namespace santa {
89+
90+
ActivationCallbackBlock CreateCELActivationBlock(
91+
const Message &esMsg, MOLCodesignChecker *csInfo,
92+
std::shared_ptr<santad::process_tree::ProcessTree> processTree) {
93+
std::shared_ptr<EndpointSecurityAPI> esApi = esMsg.ESAPI();
94+
95+
return ^std::unique_ptr<::google::api::expr::runtime::BaseActivation>(bool useV2) {
96+
auto makeActivation =
97+
[&]<bool IsV2>() -> std::unique_ptr<::google::api::expr::runtime::BaseActivation> {
98+
using Traits = santa::cel::CELProtoTraits<IsV2>;
99+
using ExecutableFileT = typename Traits::ExecutableFileT;
100+
using AncestorT = typename Traits::AncestorT;
101+
102+
auto f = std::make_unique<ExecutableFileT>();
103+
104+
NSString *signingID = FormatSigningID(csInfo);
105+
if (signingID) {
106+
f->set_signing_id(santa::NSStringToUTF8String(signingID));
107+
}
108+
109+
if (csInfo.signingTime) {
110+
f->mutable_signing_time()->set_seconds(csInfo.signingTime.timeIntervalSince1970);
111+
}
112+
if (csInfo.secureSigningTime) {
113+
f->mutable_secure_signing_time()->set_seconds(
114+
csInfo.secureSigningTime.timeIntervalSince1970);
115+
}
116+
117+
return std::make_unique<santa::cel::Activation<IsV2>>(
118+
std::move(f),
119+
^std::vector<std::string>() {
120+
return esApi->ExecArgs(&esMsg->event.exec);
121+
},
122+
^std::map<std::string, std::string>() {
123+
return esApi->ExecEnvs(&esMsg->event.exec);
124+
},
125+
^uid_t() {
126+
return audit_token_to_euid(esMsg->event.exec.target->audit_token);
127+
},
128+
^std::string() {
129+
es_file_t *f = esMsg->event.exec.cwd;
130+
if (!f) return std::string();
131+
return std::string(f->path.data, f->path.length);
132+
},
133+
^std::vector<AncestorT>() {
134+
return Ancestors<IsV2>(processTree, esMsg);
135+
});
136+
};
137+
138+
if (useV2) {
139+
return makeActivation.operator()<true>();
140+
} else {
141+
return makeActivation.operator()<false>();
142+
}
143+
};
144+
}
145+
146+
} // namespace santa

Source/santad/SNTExecutionController.mm

Lines changed: 3 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@
4747
#include "Source/common/String.h"
4848
#include "Source/common/SystemResources.h"
4949
#include "Source/common/Unit.h"
50+
#include "Source/santad/CELActivation.h"
5051
#import "Source/santad/DataLayer/SNTEventTable.h"
5152
#import "Source/santad/DataLayer/SNTRuleTable.h"
5253
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
53-
#include "Source/santad/ProcessTree/process_tree_macos.h"
5454
#import "Source/santad/SNTDecisionCache.h"
5555
#import "Source/santad/SNTNotificationQueue.h"
5656
#import "Source/santad/SNTSyncdQueue.h"
@@ -263,10 +263,8 @@ - (void)validateExecEvent:(const Message &)esMsg postAction:(bool (^)(SNTAction)
263263
decisionForFileInfo:binInfo
264264
targetProcess:targetProc
265265
configState:configState
266-
activationCallback:[self
267-
createActivationBlockForMessage:esMsg
268-
andCSInfo:[binInfo
269-
codesignCheckerWithError:NULL]]];
266+
activationCallback:santa::CreateCELActivationBlock(
267+
esMsg, [binInfo codesignCheckerWithError:NULL], _processTree)];
270268

271269
cd.codesigningFlags = targetProc->codesigning_flags;
272270
cd.vnodeId = SantaVnode::VnodeForFile(targetProc->executable);
@@ -649,117 +647,8 @@ - (void)createRuleForStandaloneModeEvent:(SNTStoredExecutionEvent *)se {
649647
// TODO: Notify the sync service of the new rule.
650648
}
651649

652-
// Create a block that returns a santa::cel::Activation object for the given Message
653-
// and MOLCodesignChecker object. The block defines a bool parameter that determines
654-
// whether to create a v1 or v2 activation object.
655-
//
656-
// Note: The returned block captures a reference to the Message object and must
657-
// not use it after the Message object is destroyed. Care must be taken to not
658-
// use this in an asynchronous context outside of the evaluation of that execution.
659-
- (ActivationCallbackBlock)createActivationBlockForMessage:(const santa::Message &)esMsg
660-
andCSInfo:(nullable MOLCodesignChecker *)csInfo {
661-
std::shared_ptr<santa::EndpointSecurityAPI> esApi = esMsg.ESAPI();
662-
std::shared_ptr<santa::santad::process_tree::ProcessTree> processTree = _processTree;
663-
664-
return ^std::unique_ptr<::google::api::expr::runtime::BaseActivation>(bool useV2) {
665-
auto makeActivation =
666-
[&]<bool IsV2>() -> std::unique_ptr<::google::api::expr::runtime::BaseActivation> {
667-
using Traits = santa::cel::CELProtoTraits<IsV2>;
668-
using ExecutableFileT = typename Traits::ExecutableFileT;
669-
using AncestorT = typename Traits::AncestorT;
670-
671-
auto f = std::make_unique<ExecutableFileT>();
672-
673-
if (csInfo.signingTime) {
674-
f->mutable_signing_time()->set_seconds(csInfo.signingTime.timeIntervalSince1970);
675-
}
676-
if (csInfo.secureSigningTime) {
677-
f->mutable_secure_signing_time()->set_seconds(
678-
csInfo.secureSigningTime.timeIntervalSince1970);
679-
}
680-
681-
return std::make_unique<santa::cel::Activation<IsV2>>(
682-
std::move(f),
683-
^std::vector<std::string>() {
684-
return esApi->ExecArgs(&esMsg->event.exec);
685-
},
686-
^std::map<std::string, std::string>() {
687-
return esApi->ExecEnvs(&esMsg->event.exec);
688-
},
689-
^uid_t() {
690-
return audit_token_to_euid(esMsg->event.exec.target->audit_token);
691-
},
692-
^std::string() {
693-
es_file_t *f = esMsg->event.exec.cwd;
694-
return std::string(f->path.data, f->path.length);
695-
},
696-
^std::vector<AncestorT>() {
697-
return Ancestors<IsV2>(processTree, esMsg);
698-
});
699-
};
700-
701-
if (useV2) {
702-
return makeActivation.operator()<true>();
703-
} else {
704-
return makeActivation.operator()<false>();
705-
}
706-
};
707-
}
708-
709650
- (void)flushTouchIDApprovalCache {
710651
_touchIDApprovalCache->clear();
711652
}
712653

713-
template <bool IsV2>
714-
std::vector<typename santa::cel::CELProtoTraits<IsV2>::AncestorT> Ancestors(
715-
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
716-
const santa::Message &esMsg);
717-
718-
template <>
719-
std::vector<santa::cel::CELProtoTraits<true>::AncestorT> Ancestors<true>(
720-
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
721-
const santa::Message &esMsg) {
722-
if (!processTree) return {};
723-
724-
using Traits = santa::cel::CELProtoTraits<true>;
725-
using AncestorT = typename Traits::AncestorT;
726-
727-
auto pid = santa::santad::process_tree::PidFromAuditToken(esMsg->process->parent_audit_token);
728-
auto proc = processTree->Get(pid);
729-
if (!proc) {
730-
return {};
731-
}
732-
733-
std::vector<santa::cel::CELProtoTraits<true>::AncestorT> ancestors;
734-
for (const auto &p : processTree->RootSlice(*proc)) {
735-
if (!p->program_) {
736-
continue;
737-
}
738-
739-
AncestorT ancestor;
740-
ancestor.set_path(p->program_->executable);
741-
742-
if (p->program_->code_signing) {
743-
const auto &cs = *p->program_->code_signing;
744-
if (cs.is_platform_binary) {
745-
ancestor.set_signing_id("platform:" + cs.signing_id);
746-
} else {
747-
ancestor.set_signing_id(cs.team_id + ":" + cs.signing_id);
748-
}
749-
ancestor.set_team_id(cs.team_id);
750-
ancestor.set_cdhash(cs.cdhash);
751-
}
752-
753-
ancestors.push_back(std::move(ancestor));
754-
}
755-
return ancestors;
756-
}
757-
758-
template <>
759-
std::vector<santa::cel::CELProtoTraits<false>::AncestorT> Ancestors<false>(
760-
const std::shared_ptr<santa::santad::process_tree::ProcessTree> &processTree,
761-
const santa::Message &esMsg) {
762-
return {};
763-
}
764-
765654
@end

0 commit comments

Comments
 (0)