Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Source/common/SNTRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
state:(SNTRuleState)state
type:(SNTRuleType)type
customMsg:(NSString *)customMsg
customURL:(NSString *)customURL;
customURL:(NSString *)customURL
celExpr:(NSString *)celExpr;

///
/// Initialize with a default timestamp: current time if rule state is transitive, 0 otherwise.
Expand Down
27 changes: 23 additions & 4 deletions Source/common/SNTRule.m
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,16 @@ - (instancetype)initWithIdentifier:(NSString *)identifier
state:(SNTRuleState)state
type:(SNTRuleType)type
customMsg:(NSString *)customMsg
customURL:(NSString *)customURL {
customURL:(NSString *)customURL
celExpr:(NSString *)celExpr {
self = [self initWithIdentifier:identifier
state:state
type:type
customMsg:customMsg
customURL:customURL
timestamp:0
comment:nil
celExpr:nil
celExpr:celExpr
error:nil];
// Initialize timestamp to current time if rule is transitive.
if (self && state == SNTRuleStateAllowTransitive) {
Expand All @@ -186,7 +187,15 @@ - (instancetype)initWithIdentifier:(NSString *)identifier
- (instancetype)initWithIdentifier:(NSString *)identifier
state:(SNTRuleState)state
type:(SNTRuleType)type {
return [self initWithIdentifier:identifier state:state type:type customMsg:nil customURL:nil];
return [self initWithIdentifier:identifier
state:state
type:type
customMsg:nil
customURL:nil
timestamp:0
comment:nil
celExpr:nil
error:nil];
}

// lowercase policy keys and upper case the policy decision.
Expand Down Expand Up @@ -254,6 +263,8 @@ - (instancetype)initWithDictionary:(NSDictionary *)rawDict error:(NSError **)err
state = SNTRuleStateSilentBlock;
} else if ([policyString isEqual:kRulePolicyRemove]) {
state = SNTRuleStateRemove;
} else if ([policyString isEqual:kRulePolicyCEL]) {
state = SNTRuleStateCEL;
} else {
[SNTError populateError:error
withCode:SNTErrorCodeRuleInvalidPolicy
Expand Down Expand Up @@ -301,14 +312,19 @@ - (instancetype)initWithDictionary:(NSDictionary *)rawDict error:(NSError **)err
comment = nil;
}

NSString *celExpr = dict[kRuleCELExpr];
if (![celExpr isKindOfClass:[NSString class]] || celExpr.length == 0) {
celExpr = nil;
}

return [self initWithIdentifier:identifier
state:state
type:type
customMsg:customMsg
customURL:customURL
timestamp:0
comment:comment
celExpr:nil
celExpr:celExpr
error:error];
}

Expand Down Expand Up @@ -354,6 +370,7 @@ - (NSString *)ruleStateToPolicyString:(SNTRuleState)state {
case SNTRuleStateAllowTransitive: return @"AllowTransitive";
case SNTRuleStateAllowLocalBinary: return kRulePolicyAllowlistLocalBinary;
case SNTRuleStateAllowLocalSigningID: return kRulePolicyAllowlistLocalSigningID;
case SNTRuleStateCEL: return kRulePolicyCEL;
// This should never be hit. But is here for completion.
default: return @"Unknown";
}
Expand Down Expand Up @@ -381,6 +398,7 @@ - (NSDictionary *)dictionaryRepresentation {
kRuleCustomMsg : self.customMsg ?: @"",
kRuleCustomURL : self.customURL ?: @"",
kRuleComment : self.comment ?: @"",
kRuleCELExpr : self.celExpr ?: @"",
};
}

Expand All @@ -399,6 +417,7 @@ - (NSUInteger)hash {
result = prime * result + self.state;
result = prime * result + self.type;
result = prime * result + [self.celExpr hash];
result = prime * result + [self.celExpr hash];
return result;
}

Expand Down
4 changes: 4 additions & 0 deletions Source/common/SNTRuleTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ - (void)testRuleDictionaryRepresentation {
@"custom_msg" : @"A custom block message",
@"custom_url" : @"https://example.com",
@"comment" : @"",
@"cel_expr" : @"",
};

SNTRule *sut = [[SNTRule alloc] initWithDictionary:expectedTeamID error:nil];
Expand All @@ -298,6 +299,7 @@ - (void)testRuleDictionaryRepresentation {
@"custom_msg" : @"",
@"custom_url" : @"",
@"comment" : @"",
@"cel_expr" : @"",
};

sut = [[SNTRule alloc] initWithDictionary:expectedBinary error:nil];
Expand All @@ -313,6 +315,7 @@ - (void)testRuleStateToPolicyString {
@"rule_type" : @"BINARY",
@"custom_msg" : @"A custom block message",
@"custom_url" : @"https://example.com",
@"cel_expr" : @"",
};

SNTRule *sut = [[SNTRule alloc] initWithDictionary:expected error:nil];
Expand All @@ -333,6 +336,7 @@ - (void)testKeyCaseForInitWithDictionary {
for (NSString *key in
@[ kRulePolicy, kRuleIdentifier, kRuleType, kRuleCustomMsg, kRuleCustomURL, kRuleComment ]) {
NSDictionary *expected = @{
@"cel_expr" : @"",
@"identifier" : @"84de9c61777ca36b13228e2446d53e966096e78db7a72c632b5c185b2ffe68a6",
@"policy" : @"ALLOWLIST",
@"rule_type" : @"BINARY",
Expand Down
2 changes: 2 additions & 0 deletions Source/common/SNTSyncConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ extern NSString *const kRulePolicyBlocklistDeprecated;
extern NSString *const kRulePolicySilentBlocklist;
extern NSString *const kRulePolicySilentBlocklistDeprecated;
extern NSString *const kRulePolicyRemove;
extern NSString *const kRulePolicyCEL;
extern NSString *const kRuleType;
extern NSString *const kRuleTypeBinary;
extern NSString *const kRuleTypeCertificate;
Expand All @@ -135,6 +136,7 @@ extern NSString *const kRuleTypeCDHash;
extern NSString *const kRuleCustomMsg;
extern NSString *const kRuleCustomURL;
extern NSString *const kRuleComment;
extern NSString *const kRuleCELExpr;
extern NSString *const kCursor;

extern NSString *const kBackoffInterval;
Expand Down
2 changes: 2 additions & 0 deletions Source/common/SNTSyncConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
NSString *const kRulePolicySilentBlocklist = @"SILENT_BLOCKLIST";
NSString *const kRulePolicySilentBlocklistDeprecated = @"SILENT_BLACKLIST";
NSString *const kRulePolicyRemove = @"REMOVE";
NSString *const kRulePolicyCEL = @"CEL";
NSString *const kRuleType = @"rule_type";
NSString *const kRuleTypeBinary = @"BINARY";
NSString *const kRuleTypeCertificate = @"CERTIFICATE";
Expand All @@ -136,6 +137,7 @@
NSString *const kRuleCustomMsg = @"custom_msg";
NSString *const kRuleCustomURL = @"custom_url";
NSString *const kRuleComment = @"comment";
NSString *const kRuleCELExpr = @"cel_expr";
NSString *const kCursor = @"cursor";

NSString *const kBackoffInterval = @"backoff";
Expand Down
24 changes: 12 additions & 12 deletions Source/common/cel/Activation.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,23 @@
#include "eval/public/activation.h"
#pragma clang diagnostic pop

namespace cel_runtime = ::google::api::expr::runtime;
namespace pbv1 = ::santa::cel::v1;

namespace santa {
namespace cel {

// SantaActivation is a CEL activation that provides lookups of values from the
// santa.pb.cel.v1.Context message, and easy access to variables for return values.
class Activation : public ::cel_runtime::BaseActivation {
class Activation : public ::google::api::expr::runtime::BaseActivation {
public:
Activation(std::unique_ptr<::pbv1::ExecutableFile> file, std::vector<std::string> (^args)(),
std::map<std::string, std::string> (^envs)())
Activation(std::unique_ptr<::santa::cel::v1::ExecutableFile> file,
std::vector<std::string> (^args)(), std::map<std::string, std::string> (^envs)())
: file_(std::move(file)), args_(args), envs_(envs) {};
~Activation() = default;

std::optional<cel_runtime::CelValue> FindValue(absl::string_view name,
google::protobuf::Arena *arena) const override;
std::optional<::google::api::expr::runtime::CelValue> FindValue(
absl::string_view name, google::protobuf::Arena *arena) const override;

// Activation does not support lazy-loaded functions.
std::vector<const cel_runtime::CelFunction *> FindFunctionOverloads(
std::vector<const ::google::api::expr::runtime::CelFunction *> FindFunctionOverloads(
absl::string_view) const override {
return {};
}
Expand All @@ -72,11 +69,14 @@ class Activation : public ::cel_runtime::BaseActivation {
const google::protobuf::Descriptor *messageType);

template <typename T>
static cel_runtime::CelValue CELValue(const T &v, google::protobuf::Arena *arena);
static ::google::api::expr::runtime::CelValue CELValue(const T &v,
google::protobuf::Arena *arena);
template <typename T>
static cel_runtime::CelValue CELValue(const std::vector<T> &v, google::protobuf::Arena *arena);
static ::google::api::expr::runtime::CelValue CELValue(const std::vector<T> &v,
google::protobuf::Arena *arena);
template <typename K, typename V>
static cel_runtime::CelValue CELValue(const std::map<K, V> &v, google::protobuf::Arena *arena);
static ::google::api::expr::runtime::CelValue CELValue(const std::map<K, V> &v,
google::protobuf::Arena *arena);
};

} // namespace cel
Expand Down
6 changes: 3 additions & 3 deletions Source/common/cel/Activation.mm
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
std::optional<cel_runtime::CelValue> Activation::FindValue(absl::string_view name,
google::protobuf::Arena *arena) const {
// Handle the ReturnValue values.
auto retDescriptor = pbv1::ReturnValue_descriptor();
auto retDescriptor = santa::cel::v1::ReturnValue_descriptor();
auto retValue = retDescriptor->FindValueByName(name);
if (retValue != nullptr) {
return CELValue(retValue->number(), arena);
Expand All @@ -109,14 +109,14 @@
// ALLOWLIST or BLOCKLIST in their CEL expressions without having to use the
// proto package name prefix. Start from value number 1 to avoid the
// UNSPECIFIED value.
auto retDescriptor = pbv1::ReturnValue_descriptor();
auto retDescriptor = ::santa::cel::v1::ReturnValue_descriptor();
for (int i = 1; i < retDescriptor->value_count(); i++) {
auto value = retDescriptor->value(i);
v.push_back({value->name(), ::cel::IntType()});
}

// Now add all the fields from the CELContext message.
auto ctxDescriptor = pbv1::ExecutionContext::descriptor();
auto ctxDescriptor = santa::cel::v1::ExecutionContext::descriptor();
for (int i = 0; i < ctxDescriptor->field_count(); i++) {
auto field = ctxDescriptor->field(i);

Expand Down
9 changes: 9 additions & 0 deletions Source/santactl/Commands/SNTCommandRule.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ + (NSString *)longHelpText {
@" --block: add to block\n"
@" --silent-block: add to silent block\n"
@" --compiler: allow and mark as a compiler\n"
@" --cel {cel_expr}: add a CEL rule\n"
Comment thread
russellhancox marked this conversation as resolved.
@" See https://northpole.dev/features/binary-authorization#cel for more "
@"information.\n"
@" --remove: remove existing rule\n"
@" --check: check for an existing rule\n"
@" --import {path}: import rules from a JSON file\n"
Expand Down Expand Up @@ -153,6 +156,12 @@ - (void)runWithArguments:(NSArray *)arguments {
newRule.state = SNTRuleStateSilentBlock;
} else if ([arg caseInsensitiveCompare:@"--compiler"] == NSOrderedSame) {
newRule.state = SNTRuleStateAllowCompiler;
} else if ([arg caseInsensitiveCompare:@"--cel"] == NSOrderedSame) {
if (++i > arguments.count - 1) {
[self printErrorUsageAndExit:@"--cel requires an argument"];
}
newRule.state = SNTRuleStateCEL;
newRule.celExpr = arguments[i];
} else if ([arg caseInsensitiveCompare:@"--remove"] == NSOrderedSame) {
newRule.state = SNTRuleStateRemove;
} else if ([arg caseInsensitiveCompare:@"--check"] == NSOrderedSame) {
Expand Down
2 changes: 1 addition & 1 deletion Source/santad/SNTPolicyProcessor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ - (BOOL)decision:(SNTCachedDecision *)cd
break;
default: break;
}
if (!(*evalResult).second) {
if (!evalResult->second) {
cd.cacheable = NO;
}
}
Expand Down
17 changes: 10 additions & 7 deletions Source/santasyncservice/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ licenses(["notice"])

objc_library(
name = "FCM_lib",
srcs = ["SNTSyncFCM.m"],
srcs = ["SNTSyncFCM.mm"],
hdrs = ["SNTSyncFCM.h"],
sdk_frameworks = ["Network"],
deps = [
Expand All @@ -30,11 +30,12 @@ objc_library(

objc_library(
name = "SNTSyncState",
srcs = ["SNTSyncState.m"],
srcs = ["SNTSyncState.mm"],
hdrs = ["SNTSyncState.h"],
deps = [
"//Source/common:SNTCommonEnums",
"//Source/common:SNTExportConfiguration",
"//Source/common/cel:CEL",
],
)

Expand Down Expand Up @@ -73,17 +74,17 @@ objc_library(
"NSData+Zlib.h",
"NSData+Zlib.m",
"SNTPushClientAPNS.h",
"SNTPushClientAPNS.m",
"SNTPushClientAPNS.mm",
"SNTPushClientFCM.h",
"SNTPushClientFCM.m",
"SNTPushClientFCM.mm",
"SNTPushNotifications.h",
"SNTPushNotificationsTracker.h",
"SNTPushNotificationsTracker.m",
"SNTSyncEventUpload.h",
"SNTSyncEventUpload.mm",
"SNTSyncLogging.h",
"SNTSyncLogging.m",
"SNTSyncManager.m",
"SNTSyncManager.mm",
"SNTSyncPostflight.h",
"SNTSyncPostflight.mm",
"SNTSyncPreflight.h",
Expand Down Expand Up @@ -124,6 +125,7 @@ objc_library(
"//Source/common:SNTXPCControlInterface",
"//Source/common:SNTXPCSyncServiceInterface",
"//Source/common:String",
"//Source/common/cel:CEL",
"@northpolesec_protos//sync:v1_cc_proto",
"@protobuf//src/google/protobuf/json",
],
Expand All @@ -138,9 +140,9 @@ santa_unit_test(
"NSData+Zlib.h",
"NSData+Zlib.m",
"SNTPushClientAPNS.h",
"SNTPushClientAPNS.m",
"SNTPushClientAPNS.mm",
"SNTPushClientFCM.h",
"SNTPushClientFCM.m",
"SNTPushClientFCM.mm",
"SNTPushNotifications.h",
"SNTPushNotificationsTracker.h",
"SNTPushNotificationsTracker.m",
Expand Down Expand Up @@ -185,6 +187,7 @@ santa_unit_test(
"//Source/common:SNTSystemInfo",
"//Source/common:SNTXPCControlInterface",
"//Source/common:String",
"//Source/common/cel:CEL",
"@OCMock",
"@northpolesec_protos//sync:v1_cc_proto",
"@protobuf//src/google/protobuf/json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#import "Source/common/SNTStrengthify.h"
#import "Source/common/SNTSyncConstants.h"
#import "Source/common/SNTXPCControlInterface.h"
#include "Source/common/cel/Evaluator.h"
#import "Source/santasyncservice/SNTPushClientAPNS.h"
#import "Source/santasyncservice/SNTPushClientFCM.h"
#import "Source/santasyncservice/SNTPushNotifications.h"
Expand Down Expand Up @@ -62,7 +63,9 @@ @interface SNTSyncManager () <SNTPushNotificationsSyncDelegate>

@end

@implementation SNTSyncManager
@implementation SNTSyncManager {
std::unique_ptr<santa::cel::Evaluator> _celEvaluator;
}

#pragma mark init

Expand Down Expand Up @@ -93,6 +96,11 @@ - (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn {
_syncLimiter = dispatch_semaphore_create(kMaxEnqueuedSyncs);

_eventBatchSize = kDefaultEventBatchSize;

auto celEvaluator = santa::cel::Evaluator::Create();
if (celEvaluator.ok()) {
_celEvaluator = std::move(celEvaluator.value());
}
}
return self;
}
Expand Down Expand Up @@ -441,6 +449,8 @@ - (SNTSyncState *)createSyncStateWithStatus:(SNTSyncStatusType *)status {
syncState.contentEncoding = config.syncClientContentEncoding;
syncState.pushNotificationsToken = self.pushNotifications.token;

syncState.celEvaluator = _celEvaluator.get();

return syncState;
}

Expand Down
Loading