Skip to content

Commit

Permalink
Abstract TTY writing so multiple writers can be synchronized (#1108)
Browse files Browse the repository at this point in the history
* Abstract TTY writing so multiple writers can be synchronized

* Address PR feedback
  • Loading branch information
mlw committed Jun 14, 2023
1 parent 0715033 commit 6a6aa6d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 17 deletions.
12 changes: 12 additions & 0 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ objc_library(
],
)

objc_library(
name = "TTYWriter",
srcs = ["TTYWriter.mm"],
hdrs = ["TTYWriter.h"],
deps = [
"//Source/common:SNTLogging",
"//Source/common:String",
],
)

objc_library(
name = "SNTExecutionController",
srcs = ["SNTExecutionController.mm"],
Expand All @@ -221,6 +231,7 @@ objc_library(
":SNTPolicyProcessor",
":SNTRuleTable",
":SNTSyncdQueue",
":TTYWriter",
"//Source/common:BranchPrediction",
"//Source/common:SNTBlockMessage",
"//Source/common:SNTCachedDecision",
Expand Down Expand Up @@ -706,6 +717,7 @@ objc_library(
":SNTNotificationQueue",
":SNTRuleTable",
":SNTSyncdQueue",
":TTYWriter",
":WatchItems",
"//Source/common:PrefixTree",
"//Source/common:SNTConfigurator",
Expand Down
7 changes: 4 additions & 3 deletions Source/santad/SNTExecutionController.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

#import <Foundation/Foundation.h>

#include "Source/santad/EventProviders/EndpointSecurity/Message.h"

#import "Source/common/SNTCommonEnums.h"
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
#include "Source/santad/TTYWriter.h"

const static NSString *kBlockBinary = @"BlockBinary";
const static NSString *kAllowBinary = @"AllowBinary";
Expand Down Expand Up @@ -56,7 +56,8 @@ const static NSString *kBlockLongPath = @"BlockLongPath";
- (instancetype)initWithRuleTable:(SNTRuleTable *)ruleTable
eventTable:(SNTEventTable *)eventTable
notifierQueue:(SNTNotificationQueue *)notifierQueue
syncdQueue:(SNTSyncdQueue *)syncdQueue;
syncdQueue:(SNTSyncdQueue *)syncdQueue
ttyWriter:(std::shared_ptr<santa::santad::TTYWriter>)ttyWriter;

///
/// Handles the logic of deciding whether to allow the binary to run or not, sends the response to
Expand Down
24 changes: 12 additions & 12 deletions Source/santad/SNTExecutionController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@

#import "Source/santad/SNTExecutionController.h"

#import <MOLCodesignChecker/MOLCodesignChecker.h>
#include <bsm/libbsm.h>
#include <copyfile.h>
#include <libproc.h>
#include <pwd.h>
#include <sys/param.h>
#include <utmpx.h>

#import <MOLCodesignChecker/MOLCodesignChecker.h>
#include <memory>

#include "Source/common/BranchPrediction.h"
#import "Source/common/SNTBlockMessage.h"
Expand All @@ -44,6 +45,7 @@
#import "Source/santad/SNTPolicyProcessor.h"
#import "Source/santad/SNTSyncdQueue.h"

using santa::santad::TTYWriter;
using santa::santad::event_providers::endpoint_security::Message;

static const size_t kMaxAllowedPathLength = MAXPATHLEN - 1; // -1 to account for null terminator
Expand All @@ -59,7 +61,9 @@ @interface SNTExecutionController ()
@property dispatch_queue_t eventQueue;
@end

@implementation SNTExecutionController
@implementation SNTExecutionController {
std::shared_ptr<TTYWriter> _ttyWriter;
}

static NSString *const kPrinterProxyPreMonterey =
(@"/System/Library/Frameworks/Carbon.framework/Versions/Current/"
Expand All @@ -74,13 +78,15 @@ @implementation SNTExecutionController
- (instancetype)initWithRuleTable:(SNTRuleTable *)ruleTable
eventTable:(SNTEventTable *)eventTable
notifierQueue:(SNTNotificationQueue *)notifierQueue
syncdQueue:(SNTSyncdQueue *)syncdQueue {
syncdQueue:(SNTSyncdQueue *)syncdQueue
ttyWriter:(std::shared_ptr<TTYWriter>)ttyWriter {
self = [super init];
if (self) {
_ruleTable = ruleTable;
_eventTable = eventTable;
_notifierQueue = notifierQueue;
_syncdQueue = syncdQueue;
_ttyWriter = std::move(ttyWriter);
_policyProcessor = [[SNTPolicyProcessor alloc] initWithRuleTable:_ruleTable];

_eventQueue =
Expand Down Expand Up @@ -298,7 +304,8 @@ - (void)validateExecEvent:(const Message &)esMsg postAction:(bool (^)(SNTAction)
NSAttributedString *s = [SNTBlockMessage attributedBlockMessageForEvent:se
customMessage:cd.customMsg];

if (targetProc->tty && targetProc->tty->path.length > 0 && !config.enableSilentTTYMode) {
if (targetProc->tty && targetProc->tty->path.length > 0 && !config.enableSilentTTYMode &&
self->_ttyWriter) {
NSMutableString *msg = [NSMutableString stringWithCapacity:1024];
[msg appendFormat:@"\n\033[1mSanta\033[0m\n\n%@\n\n", s.string];
[msg appendFormat:@"\033[1mPath: \033[0m %@\n"
Expand All @@ -310,7 +317,7 @@ - (void)validateExecEvent:(const Message &)esMsg postAction:(bool (^)(SNTAction)
[msg appendFormat:@"More info:\n%@\n\n", detailURL.absoluteString];
}

[self printMessage:msg toTTY:targetProc->tty->path.data];
self->_ttyWriter->Write(targetProc->tty->path.data, msg);
}

[self.notifierQueue addEvent:se customMessage:cd.customMsg];
Expand Down Expand Up @@ -363,13 +370,6 @@ - (SNTFileInfo *)printerProxyFileInfo {
return proxyInfo;
}

- (void)printMessage:(NSString *)msg toTTY:(const char *)path {
int fd = open(path, O_WRONLY | O_NOCTTY);
std::string_view str = santa::common::NSStringToUTF8StringView(msg);
write(fd, str.data(), str.length());
close(fd);
}

- (void)loggedInUsers:(NSArray **)users sessions:(NSArray **)sessions {
NSMutableSet *loggedInUsers = [NSMutableSet set];
NSMutableArray *loggedInHosts = [NSMutableArray array];
Expand Down
3 changes: 2 additions & 1 deletion Source/santad/SNTExecutionControllerTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ - (void)setUp {
self.sut = [[SNTExecutionController alloc] initWithRuleTable:self.mockRuleDatabase
eventTable:self.mockEventDatabase
notifierQueue:nil
syncdQueue:nil];
syncdQueue:nil
ttyWriter:nullptr];
}

- (void)tearDown {
Expand Down
11 changes: 10 additions & 1 deletion Source/santad/SantadDeps.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "Source/santad/SantadDeps.h"

#include <cstdlib>
#include <memory>

#import "Source/common/SNTLogging.h"
Expand All @@ -25,10 +26,12 @@
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
#import "Source/santad/SNTDatabaseController.h"
#include "Source/santad/SNTDecisionCache.h"
#include "Source/santad/TTYWriter.h"

using santa::common::PrefixTree;
using santa::common::Unit;
using santa::santad::Metrics;
using santa::santad::TTYWriter;
using santa::santad::data_layer::WatchItems;
using santa::santad::event_providers::AuthResultCache;
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
Expand Down Expand Up @@ -81,11 +84,17 @@
exit(EXIT_FAILURE);
}

std::shared_ptr<TTYWriter> tty_writer = TTYWriter::Create();
if (!tty_writer) {
LOGW(@"Unable to initialize TTY writer");
}

SNTExecutionController *exec_controller =
[[SNTExecutionController alloc] initWithRuleTable:rule_table
eventTable:event_table
notifierQueue:notifier_queue
syncdQueue:syncd_queue];
syncdQueue:syncd_queue
ttyWriter:tty_writer];
if (!exec_controller) {
LOGE(@"Failed to initialize exec controller.");
exit(EXIT_FAILURE);
Expand Down
48 changes: 48 additions & 0 deletions Source/santad/TTYWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// 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__TTYWRITER_H
#define SANTA__SANTAD__TTYWRITER_H

#import <Foundation/Foundation.h>
#include <dispatch/dispatch.h>

#include <memory>

namespace santa::santad {

// Small helper class to synchronize writing to TTYs
class TTYWriter {
public:
static std::unique_ptr<TTYWriter> Create();

TTYWriter(dispatch_queue_t q);

// Moves can be safe, but not currently needed/implemented
TTYWriter(TTYWriter &&other) = delete;
TTYWriter &operator=(TTYWriter &&rhs) = delete;

// No copies
TTYWriter(const TTYWriter &other) = delete;
TTYWriter &operator=(const TTYWriter &other) = delete;

void Write(const char *tty, NSString *msg);

private:
dispatch_queue_t q_;
};

} // namespace santa::santad

#endif
56 changes: 56 additions & 0 deletions Source/santad/TTYWriter.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// 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.

#include "Source/santad/TTYWriter.h"

#include <string.h>
#include <sys/errno.h>

#import "Source/common/SNTLogging.h"
#include "Source/common/String.h"

namespace santa::santad {

std::unique_ptr<TTYWriter> TTYWriter::Create() {
dispatch_queue_t q = dispatch_queue_create_with_target(
"com.google.santa.ttywriter", DISPATCH_QUEUE_SERIAL,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));

if (!q) {
return nullptr;
}

return std::make_unique<TTYWriter>(q);
}

TTYWriter::TTYWriter(dispatch_queue_t q) : q_(q) {}

void TTYWriter::Write(const char *tty, NSString *msg) {
dispatch_async(q_, ^{
@autoreleasepool {
int fd = open(tty, O_WRONLY | O_NOCTTY);
if (fd == -1) {
LOGW(@"Failed to open TTY for writing: %s", strerror(errno));
return;
}

std::string_view str = santa::common::NSStringToUTF8StringView(msg);
write(fd, str.data(), str.length());

close(fd);
}
});
}

} // namespace santa::santad

0 comments on commit 6a6aa6d

Please sign in to comment.