Skip to content

Commit

Permalink
feature: Add the es_socket_events table for Unix Domain sockets
Browse files Browse the repository at this point in the history
This new table implements collecting socket events for Unix Domain sockets,
specifically the Bind and Connect events.
  • Loading branch information
Smjert committed Oct 26, 2023
1 parent 4a8d99b commit 8f96c3a
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 9 deletions.
1 change: 1 addition & 0 deletions osquery/events/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function(generateOsqueryEvents)
darwin/es_utils.cpp
darwin/endpointsecurity.cpp
darwin/endpointsecurity_fim.cpp
darwin/endpointsecurity_socketevents.cpp
darwin/event_taps.cpp
darwin/fsevents.cpp
darwin/iokit.cpp
Expand Down
71 changes: 71 additions & 0 deletions osquery/events/darwin/endpointsecurity.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ struct EndpointSecurityFileEventContext : EndpointSecurityEventContext {
using EndpointSecurityFileEventContextRef =
std::shared_ptr<EndpointSecurityFileEventContext>;

struct EndpointSecuritySocketSubscriptionContext : public SubscriptionContext {
std::vector<es_event_type_t> es_socket_event_subscriptions_;
std::vector<Row> row_list;
};

using EndpointSecuritySocketSubscriptionContextRef =
std::shared_ptr<EndpointSecuritySocketSubscriptionContext>;

struct EndpointSecuritySocketEventContext
: public EndpointSecurityEventContext {
std::string socket_path;
int domain;
int protocol;
int mode;
int type;
};
using EndpointSecuritySocketEventContextRef =
std::shared_ptr<EndpointSecuritySocketEventContext>;

class EndpointSecurityPublisher
: public EventPublisher<EndpointSecuritySubscriptionContext,
EndpointSecurityEventContext> {
Expand Down Expand Up @@ -200,6 +219,45 @@ class EndpointSecurityFileEventPublisher
// clang-format on
};

class EndpointSecuritySocketEventPublisher
: public EventPublisher<EndpointSecuritySocketSubscriptionContext,
EndpointSecuritySocketEventContext> {
DECLARE_PUBLISHER("endpointsecurity_socketevents");

public:
explicit EndpointSecuritySocketEventPublisher(
const std::string& name = "EndpointSecuritySocketEventPublisher")
: EventPublisher() {
runnable_name_ = name;
}

Status setUp() override API_AVAILABLE(macos(10.15));

void configure() override API_AVAILABLE(macos(10.15));

void tearDown() override API_AVAILABLE(macos(10.15));

Status run() override API_AVAILABLE(macos(10.15)) {
return Status::success();
}

bool shouldFire(const EndpointSecuritySocketSubscriptionContextRef& sc,
const EndpointSecuritySocketEventContextRef& ec)
const override API_AVAILABLE(macos(10.15));

virtual ~EndpointSecuritySocketEventPublisher() API_AVAILABLE(macos(10.15)) {
tearDown();
}

public:
static void handleMessage(const es_message_t* message)
API_AVAILABLE(macos(10.15));

private:
es_client_s* es_socket_client_{nullptr};
bool es_socket_client_success_{false};
};

class ESProcessEventSubscriber
: public EventSubscriber<EndpointSecurityPublisher> {
public:
Expand All @@ -225,4 +283,17 @@ class ESProcessFileEventSubscriber
const EndpointSecurityFileSubscriptionContextRef& sc)
API_AVAILABLE(macos(10.15));
};

class ESProcessSocketEventSubscriber
: public EventSubscriber<EndpointSecuritySocketEventPublisher> {
public:
ESProcessSocketEventSubscriber() {
setName("es_process_socket_events");
}

Status init() override API_AVAILABLE(macos(10.15));
Status Callback(const EndpointSecuritySocketEventContextRef& ec,
const EndpointSecuritySocketSubscriptionContextRef& sc)
API_AVAILABLE(macos(10.15));
};
} // namespace osquery
151 changes: 151 additions & 0 deletions osquery/events/darwin/endpointsecurity_socketevents.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/

#include <iomanip>

#include <osquery/core/flags.h>
#include <osquery/events/darwin/endpointsecurity.h>
#include <osquery/events/darwin/es_utils.h>
#include <osquery/logger/logger.h>
#include <osquery/registry/registry_factory.h>

namespace osquery {

DECLARE_bool(disable_endpointsecurity);
DECLARE_bool(disable_endpointsecurity_socketevents);

REGISTER(EndpointSecuritySocketEventPublisher,
"event_publisher",
"endpointsecurity_socketevents")

Status EndpointSecuritySocketEventPublisher::setUp() {
if (__builtin_available(macos 10.15, *)) {
if (FLAGS_disable_endpointsecurity) {
return Status::failure(
1, "EndpointSecurity Socket Events is disabled via configuration");
}

if (FLAGS_disable_endpointsecurity_socketevents) {
return Status::failure(
1, "EndpointSecurity Socket Events is disabled via configuration");
}

auto handler = ^(es_client_t* client, const es_message_t* message) {
handleMessage(message);
};

auto result = es_new_client(&es_socket_client_, handler);

if (result == ES_NEW_CLIENT_RESULT_SUCCESS) {
es_socket_client_success_ = true;
return Status::success();
} else {
return Status::failure(1, getEsNewClientErrorMessage(result));
}
} else {
return Status::failure(
1, "EndpointSecurity is only available on macOS 10.15 and higher");
}
}

void EndpointSecuritySocketEventPublisher::configure() {
if (es_socket_client_ == nullptr) {
return;
}

auto cache = es_clear_cache(es_socket_client_);
if (cache != ES_CLEAR_CACHE_RESULT_SUCCESS) {
VLOG(1) << "Couldn't clear cache for EndpointSecurity client";
return;
}

for (auto& sub : subscriptions_) {
auto sc = getSubscriptionContext(sub->context);
auto events = sc->es_socket_event_subscriptions_;
auto es_sub = es_subscribe(es_socket_client_, &events[0], events.size());
if (es_sub != ES_RETURN_SUCCESS) {
VLOG(1) << "Couldn't subscribe to EndpointSecurity subsystem";
}
}
}

void EndpointSecuritySocketEventPublisher::tearDown() {
if (es_socket_client_ == nullptr) {
return;
}
es_unsubscribe_all(es_socket_client_);

if (es_socket_client_success_) {
auto result = es_delete_client(es_socket_client_);
if (result != ES_RETURN_SUCCESS) {
VLOG(1) << "endpointsecurity: error tearing down es_client";
}
es_socket_client_ = nullptr;
}
}

void EndpointSecuritySocketEventPublisher::handleMessage(
const es_message_t* message) {
if (message == nullptr) {
return;
}

if (message->action_type == ES_ACTION_TYPE_AUTH) {
return;
}

auto ec = createEventContext();

ec->version = message->version;
if (ec->version >= 2) {
ec->seq_num = message->seq_num;
}

if (ec->version >= 4) {
ec->global_seq_num = message->global_seq_num;
}

getProcessProperties(message->process, ec);

switch (message->event_type) {
case ES_EVENT_TYPE_NOTIFY_UIPC_BIND: {
ec->es_event = ES_EVENT_TYPE_NOTIFY_UIPC_BIND;
ec->event_type = "bind";

auto dir = getStringFromToken(&message->event.uipc_bind.dir->path);
auto filename = getStringFromToken(&message->event.uipc_bind.filename);

ec->socket_path = dir + "/" + filename;

} break;
case ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT: {
ec->es_event = ES_EVENT_TYPE_NOTIFY_UIPC_BIND;
ec->event_type = "connect";

const auto& connect_event = message->event.uipc_connect;
ec->socket_path = getStringFromToken(&connect_event.file->path);

ec->domain = connect_event.domain;
ec->protocol = connect_event.protocol;
ec->type = connect_event.type;
} break;
default:
break;
}

EventFactory::fire<EndpointSecuritySocketEventPublisher>(ec);
}

bool EndpointSecuritySocketEventPublisher::shouldFire(
const EndpointSecuritySocketSubscriptionContextRef& sc,
const EndpointSecuritySocketEventContextRef& ec) const {
return true;
}

} // namespace osquery
21 changes: 13 additions & 8 deletions osquery/events/darwin/es_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@

namespace osquery {

FLAG(bool,
disable_endpointsecurity,
true,
"Disable receiving events from the EndpointSecurity subsystem");
CLI_FLAG(bool,
disable_endpointsecurity,
true,
"Disable receiving events from the EndpointSecurity subsystem");

FLAG(bool,
disable_endpointsecurity_fim,
true,
"Disable file events from the EndpointSecurity subsystem");
CLI_FLAG(bool,
disable_endpointsecurity_fim,
true,
"Disable file events from the EndpointSecurity subsystem");

FLAG(string,
es_fim_mute_path_literal,
Expand All @@ -40,6 +40,11 @@ FLAG(string,
// document performance issues
FLAG(bool, es_fim_enable_open_events, false, "Enable open events");

CLI_FLAG(bool,
disable_endpointsecurity_socketevents,
true,
"Disable socket events from the EndpointSecurity subsystem");

std::string getEsNewClientErrorMessage(const es_new_client_result_t r) {
switch (r) {
case ES_NEW_CLIENT_RESULT_ERR_INTERNAL:
Expand Down
1 change: 1 addition & 0 deletions osquery/tables/events/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function(generateOsqueryTablesEventsEventstable)
darwin/disk_events.cpp
darwin/es_process_events.cpp
darwin/es_process_file_events.cpp
darwin/es_process_socket_events.cpp
darwin/file_events.cpp
darwin/hardware_events.cpp
darwin/socket_events.cpp
Expand Down
70 changes: 70 additions & 0 deletions osquery/tables/events/darwin/es_process_socket_events.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/

#include <Availability.h>
#include <EndpointSecurity/EndpointSecurity.h>
#include <os/availability.h>

#include <osquery/core/flags.h>
#include <osquery/events/darwin/endpointsecurity.h>
#include <osquery/events/events.h>
#include <osquery/registry/registry_factory.h>

namespace osquery {

REGISTER(ESProcessSocketEventSubscriber,
"event_subscriber",
"es_process_socket_events");

Status ESProcessSocketEventSubscriber::init() {
if (__builtin_available(macos 10.15, *)) {
auto sc = createSubscriptionContext();

sc->es_socket_event_subscriptions_.push_back(
ES_EVENT_TYPE_NOTIFY_UIPC_BIND);
sc->es_socket_event_subscriptions_.push_back(
ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT);

subscribe(&ESProcessSocketEventSubscriber::Callback, sc);

return Status::success();
} else {
return Status::failure(1, "Only available on macOS 10.15 and higher");
}
}

Status ESProcessSocketEventSubscriber::Callback(
const EndpointSecuritySocketEventContextRef& ec,
const EndpointSecuritySocketSubscriptionContextRef& sc) {
Row r;

r["version"] = INTEGER(ec->version);
r["seq_num"] = BIGINT(ec->seq_num);
r["global_seq_num"] = BIGINT(ec->global_seq_num);

r["event_type"] = ec->event_type;

r["pid"] = BIGINT(ec->pid);
r["parent"] = BIGINT(ec->parent);

r["path"] = ec->path;

r["family"] = INTEGER(ec->domain);
r["protocol"] = INTEGER(ec->protocol);
r["type"] = INTEGER(ec->type);
r["socket"] = TEXT(ec->socket_path);

sc->row_list = {r};
if (!sc->row_list.empty()) {
addBatch(sc->row_list);
}

return Status::success();
}
} // namespace osquery
1 change: 1 addition & 0 deletions specs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function(generateNativeTables)
"darwin/disk_events.table:macos"
"darwin/es_process_events.table:macos"
"darwin/es_process_file_events.table:macos"
"darwin/es_process_socket_events.table:macos"
"darwin/event_taps.table:macos"
"darwin/fan_speed_sensors.table:macos"
"darwin/gatekeeper.table:macos"
Expand Down
2 changes: 1 addition & 1 deletion specs/darwin/es_process_file_events.table
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ schema([
Column("seq_num", BIGINT, "Per event sequence number"),
Column("global_seq_num", BIGINT, "Global sequence number"),
Column("pid", BIGINT, "Process (or thread) ID"),
Column("parent", BIGINT, "Parent process ID"),
Column("parent", BIGINT, "Parent process ID"),
Column("path", TEXT, "Path of executed file"),
Column("filename", TEXT, "The source or target filename for the event"),
Column("dest_filename", TEXT, "Destination filename for the event"),
Expand Down
Loading

0 comments on commit 8f96c3a

Please sign in to comment.