From 9bc8b7466e1a7f8167a510a6ea1553a0a7536df7 Mon Sep 17 00:00:00 2001 From: Sangwan Kwon Date: Tue, 14 Jan 2020 14:08:10 +0900 Subject: [PATCH] osquery: Remove events Signed-off-by: Sangwan Kwon --- src/osquery/CMakeLists.txt | 1 - src/osquery/core/init.cpp | 10 - src/osquery/devtools/devtools.h | 3 - src/osquery/events/CMakeLists.txt | 18 - src/osquery/events/events.cpp | 971 --------------- src/osquery/events/linux/auditdnetlink.cpp | 881 ------------- src/osquery/events/linux/auditdnetlink.h | 176 --- .../events/linux/auditeventpublisher.cpp | 351 ------ .../events/linux/auditeventpublisher.h | 125 -- src/osquery/events/linux/inotify.cpp | 468 ------- src/osquery/events/linux/inotify.h | 294 ----- src/osquery/events/linux/process_events.h | 16 - .../events/linux/process_file_events.h | 48 - src/osquery/events/linux/selinux_events.h | 68 -- src/osquery/events/linux/socket_events.h | 17 - src/osquery/events/linux/syslog.cpp | 221 ---- src/osquery/events/linux/syslog.h | 204 ---- src/osquery/events/linux/udev.cpp | 180 --- src/osquery/events/linux/udev.h | 128 -- src/osquery/events/pathset.h | 157 --- .../events/tests/events_database_tests.cpp | 429 ------- src/osquery/events/tests/events_tests.cpp | 538 -------- .../events/tests/linux/audit_tests.cpp | 136 --- .../events/tests/linux/inotify_tests.cpp | 548 --------- .../tests/linux/process_file_events_tests.cpp | 369 ------ .../events/tests/linux/syslog_tests.cpp | 81 -- src/osquery/include/osquery/events.h | 1087 ----------------- src/osquery/logger/logger.cpp | 36 +- src/osquery/logger/tests/logger.cpp | 6 - src/osquery/main/main.cpp | 1 - src/osquery/sql/virtual_table.cpp | 5 +- src/osquery/tests/test_util.cpp | 8 - src/osquery/tests/test_util.h | 4 - tools/codegen/templates/amalgamation.cpp.in | 1 - tools/codegen/templates/default.cpp.in | 10 - tools/codegen/templates/foreign.cpp.in | 1 - 36 files changed, 9 insertions(+), 7588 deletions(-) delete mode 100644 src/osquery/events/CMakeLists.txt delete mode 100644 src/osquery/events/events.cpp delete mode 100644 src/osquery/events/linux/auditdnetlink.cpp delete mode 100644 src/osquery/events/linux/auditdnetlink.h delete mode 100644 src/osquery/events/linux/auditeventpublisher.cpp delete mode 100644 src/osquery/events/linux/auditeventpublisher.h delete mode 100644 src/osquery/events/linux/inotify.cpp delete mode 100644 src/osquery/events/linux/inotify.h delete mode 100644 src/osquery/events/linux/process_events.h delete mode 100644 src/osquery/events/linux/process_file_events.h delete mode 100644 src/osquery/events/linux/selinux_events.h delete mode 100644 src/osquery/events/linux/socket_events.h delete mode 100644 src/osquery/events/linux/syslog.cpp delete mode 100644 src/osquery/events/linux/syslog.h delete mode 100644 src/osquery/events/linux/udev.cpp delete mode 100644 src/osquery/events/linux/udev.h delete mode 100644 src/osquery/events/pathset.h delete mode 100644 src/osquery/events/tests/events_database_tests.cpp delete mode 100644 src/osquery/events/tests/events_tests.cpp delete mode 100644 src/osquery/events/tests/linux/audit_tests.cpp delete mode 100644 src/osquery/events/tests/linux/inotify_tests.cpp delete mode 100644 src/osquery/events/tests/linux/process_file_events_tests.cpp delete mode 100644 src/osquery/events/tests/linux/syslog_tests.cpp delete mode 100644 src/osquery/include/osquery/events.h diff --git a/src/osquery/CMakeLists.txt b/src/osquery/CMakeLists.txt index 47aef40..cb80e4e 100644 --- a/src/osquery/CMakeLists.txt +++ b/src/osquery/CMakeLists.txt @@ -45,7 +45,6 @@ ENDIF(DEFINED GBS_BUILD) ## osquery v4.0.0 ADD_SUBDIRECTORY(core) ADD_SUBDIRECTORY(database) -ADD_SUBDIRECTORY(events) ADD_SUBDIRECTORY(filesystem) ADD_SUBDIRECTORY(logger) ADD_SUBDIRECTORY(plugins) diff --git a/src/osquery/core/init.cpp b/src/osquery/core/init.cpp index 4237b31..340a547 100644 --- a/src/osquery/core/init.cpp +++ b/src/osquery/core/init.cpp @@ -37,7 +37,6 @@ #include "osquery/utils/info/platform_type.h" #include #include -#include #include #include #include @@ -155,7 +154,6 @@ DECLARE_bool(config_dump); DECLARE_bool(database_dump); DECLARE_string(database_path); DECLARE_bool(disable_database); -DECLARE_bool(disable_events); DECLARE_bool(disable_logging); CLI_FLAG(bool, S, false, "Run as a shell process"); @@ -298,7 +296,6 @@ Initializer::Initializer(int& argc, // The shell is transient, rewrite config-loaded paths. FLAGS_disable_logging = true; // The shell never will not fork a worker. - FLAGS_disable_events = true; } if (default_flags && isReadable(kBackupDefaultFlagfile)) { @@ -471,10 +468,6 @@ void Initializer::start() const { initActivePlugin("logger", FLAGS_logger_plugin); initLogger(binary_); } - - // Start event threads. - osquery::attachEvents(); - EventFactory::delay(); } void Initializer::waitForShutdown() { @@ -490,9 +483,6 @@ void Initializer::waitForShutdown() { } } - // End any event type run loops. - EventFactory::end(true); - // Hopefully release memory used by global string constructors in gflags. GFLAGS_NAMESPACE::ShutDownCommandLineFlags(); DatabasePlugin::shutdown(); diff --git a/src/osquery/devtools/devtools.h b/src/osquery/devtools/devtools.h index c97f8d7..4c01c40 100644 --- a/src/osquery/devtools/devtools.h +++ b/src/osquery/devtools/devtools.h @@ -26,9 +26,6 @@ DECLARE_string(A); /// The shell may request execution of all queries in a pack immediately. DECLARE_string(pack); -/// The shell may need to disable events for fast operations. -DECLARE_bool(disable_events); - /** * @brief Run an interactive SQL query shell. * diff --git a/src/osquery/events/CMakeLists.txt b/src/osquery/events/CMakeLists.txt deleted file mode 100644 index 673be8d..0000000 --- a/src/osquery/events/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved -# -# 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 -# -# http://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 - -ADD_OSQUERY_LIBRARY(osquery_event events.cpp) - -FILE(GLOB OSQUERY_EVENT_TESTS "tests/*.cpp") -ADD_OSQUERY_TEST(${OSQUERY_EVENT_TESTS}) diff --git a/src/osquery/events/events.cpp b/src/osquery/events/events.cpp deleted file mode 100644 index 149521e..0000000 --- a/src/osquery/events/events.cpp +++ /dev/null @@ -1,971 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace osquery { - -CREATE_REGISTRY(EventPublisherPlugin, "event_publisher"); -CREATE_REGISTRY(EventSubscriberPlugin, "event_subscriber"); - -/// Checkpoint interval to inspect max event buffering. -#define EVENTS_CHECKPOINT 256 - -FLAG(bool, disable_events, false, "Disable osquery publish/subscribe system"); - -FLAG(bool, - events_optimize, - true, - "Optimize subscriber select queries (scheduler only)"); - -// Access this flag through EventSubscriberPlugin::getEventsExpiry to allow for -// overriding in subclasses -FLAG(uint64, events_expiry, 3600, "Timeout to expire event subscriber results"); - -// Access this flag through EventSubscriberPlugin::getEventsMax to allow for -// overriding in subclasses -FLAG(uint64, events_max, 50000, "Maximum number of events per type to buffer"); - -static inline EventTime timeFromRecord(const std::string& record) { - // Convert a stored index "as string bytes" to a time value. - return static_cast(tryTo(record).takeOr(0ll)); -} - -static inline std::string toIndex(size_t i) { - auto str_index = std::to_string(i); - if (str_index.size() < 10) { - str_index.insert(str_index.begin(), 10 - str_index.size(), '0'); - } - return str_index; -} - -static inline void getOptimizeData(EventTime& o_time, - size_t& o_eid, - std::string& query_name, - const std::string& publisher) { - // Read the optimization time for the current executing query. - getDatabaseValue(kPersistentSettings, "", query_name); - if (query_name.empty()) { - o_time = 0; - o_eid = 0; - return; - } - - { - std::string content; - getDatabaseValue(kEvents, "optimize." + query_name, content); - o_time = timeFromRecord(content); - } - - { - std::string content; - getDatabaseValue(kEvents, "optimize_eid." + query_name, content); - o_eid = tryTo(content).takeOr(std::size_t{0}); - } -} - -static inline void setOptimizeData(EventTime time, - size_t eid, - const std::string& publisher) { - // Store the optimization time and eid. - std::string query_name; - getDatabaseValue(kPersistentSettings, "", query_name); - if (query_name.empty()) { - return; - } - - setDatabaseValue(kEvents, "optimize." + query_name, std::to_string(time)); - setDatabaseValue(kEvents, "optimize_eid." + query_name, toIndex(eid)); -} - -EventContextID EventPublisherPlugin::numEvents() const { - return next_ec_id_.load(); -} - -size_t EventPublisherPlugin::numSubscriptions() { - ReadLock lock(subscription_lock_); - return subscriptions_.size(); -} - -void EventPublisherPlugin::fire(const EventContextRef& ec, EventTime time) { - if (isEnding()) { - // Cannot emit/fire while ending - return; - } - - EventContextID ec_id = 0; - ec_id = next_ec_id_.fetch_add(1); - - // Fill in EventContext ID and time if needed. - if (ec != nullptr) { - ec->id = ec_id; - if (ec->time == 0) { - if (time == 0) { - time = getUnixTime(); - } - ec->time = time; - } - } - - ReadLock lock(subscription_lock_); - for (const auto& subscription : subscriptions_) { - auto es = EventFactory::getEventSubscriber(subscription->subscriber_name); - if (es != nullptr && es->state() == EventState::EVENT_RUNNING) { - fireCallback(subscription, ec); - } - } -} - -std::vector EventSubscriberPlugin::getIndexes(EventTime start, - EventTime stop, - bool sort) { - auto index_key = "indexes." + dbNamespace(); - std::vector indexes; - - EventTime l_start = (start > 0) ? start / 60 : 0; - EventTime r_stop = (stop > 0) ? stop / 60 + 1 : 0; - - std::string content; - getDatabaseValue(kEvents, index_key + ".60", content); - if (content.empty()) { - return indexes; - } - - std::vector bins, expirations; - boost::split(bins, content, boost::is_any_of(",")); - for (const auto& bin : bins) { - auto step = timeFromRecord(bin); - auto step_start = step * 60; - auto step_stop = (step + 1) * 60; - if (step_stop <= expire_time_) { - expirations.push_back(bin); - } else if (step_start < expire_time_ && sort) { - expireRecords("60", bin, false); - } - - if (step >= l_start && (r_stop == 0 || step < r_stop) && sort) { - indexes.push_back("60." + bin); - } - } - - // Rewrite the index lists and delete each expired item. - if (!expirations.empty()) { - expireIndexes("60", bins, expirations); - } - - // Return indexes in binning order. - if (sort) { - std::sort(indexes.begin(), - indexes.end(), - [](const std::string& left, const std::string& right) { - auto n1 = timeFromRecord(left.substr(left.find('.') + 1)); - auto n2 = timeFromRecord(right.substr(right.find('.') + 1)); - return n1 < n2; - }); - } - - // Update the new time that events expire to now - expiry. - return indexes; -} - -void EventSubscriberPlugin::expireRecords(const std::string& list_type, - const std::string& index, - bool all) { - if (!executedAllQueries()) { - return; - } - - auto record_key = "records." + dbNamespace(); - auto data_key = "data." + dbNamespace(); - - // If the expirations is not removing all records, rewrite the persisting. - std::vector persisting_records; - // Request all records within this list-size + bin offset. - auto expired_records = getRecords({list_type + '.' + index}, false); - if (all && expired_records.size() > 1) { - deleteDatabaseRange(kEvents, - data_key + '.' + expired_records.begin()->first, - data_key + '.' + expired_records.rbegin()->first); - } else { - for (const auto& record : expired_records) { - if (record.second <= expire_time_) { - deleteDatabaseValue(kEvents, data_key + '.' + record.first); - } else { - persisting_records.push_back(record.first + ':' + - std::to_string(record.second)); - } - } - } - - // Either drop or overwrite the record list. - if (all) { - deleteDatabaseValue(kEvents, record_key + "." + list_type + "." + index); - } else if (persisting_records.size() < expired_records.size()) { - auto new_records = boost::algorithm::join(persisting_records, ","); - setDatabaseValue( - kEvents, record_key + "." + list_type + "." + index, new_records); - } -} - -void EventSubscriberPlugin::expireIndexes( - const std::string& list_type, - const std::vector& indexes, - const std::vector& expirations) { - if (!executedAllQueries()) { - return; - } - - auto index_key = "indexes." + dbNamespace(); - - // Construct a mutable list of persisting indexes to rewrite as records. - std::vector persisting_indexes = indexes; - // Remove the records using the list of expired indexes. - for (const auto& bin : expirations) { - expireRecords(list_type, bin, true); - persisting_indexes.erase( - std::remove(persisting_indexes.begin(), persisting_indexes.end(), bin), - persisting_indexes.end()); - } - - // Update the list of indexes with the non-expired indexes. - auto new_indexes = boost::algorithm::join(persisting_indexes, ","); - setDatabaseValue(kEvents, index_key + "." + list_type, new_indexes); -} - -void EventSubscriberPlugin::expireCheck() { - auto data_key = "data." + dbNamespace(); - auto eid_key = "eid." + dbNamespace(); - // Min key will be the last surviving key. - size_t threshold_key = 0; - - { - auto limit = getEventsMax(); - std::vector keys; - scanDatabaseKeys(kEvents, keys, data_key); - if (keys.size() <= limit) { - return; - } - - // There is an overflow of events buffered for this subscriber. - LOG(WARNING) << "Expiring events for subscriber: " << getName() - << " (overflowed limit " << limit << ")"; - VLOG(1) << "Subscriber events " << getName() << " exceeded limit " << limit - << " by: " << keys.size() - limit; - // Inspect the N-FLAGS_events_max -th event's value and expire before the - // time within the content. - std::string last_key; - getDatabaseValue(kEvents, eid_key, last_key); - // The EID is the next-index. - // EID - events_max is the most last-recent event to keep. - threshold_key = boost::lexical_cast(last_key) - getEventsMax(); - - // Scan each of the keys in keys, if their ID portion is < threshold. - // Nix them, this requires lots of conversions, use with care. - std::string max_key; - std::string min_key; - unsigned long min_key_value = 0; - unsigned long max_key_value = 0; - for (const auto& key : keys) { - auto const key_value = - tryTo(key.substr(key.rfind('.') + 1), 10) - .takeOr(0ul); - - if (key_value < static_cast(threshold_key)) { - min_key_value = (min_key_value == 0 || key_value < min_key_value) - ? key_value - : min_key_value; - if (min_key_value == key_value) { - min_key = key; - } - - max_key_value = (key_value > max_key_value) ? key_value : max_key_value; - if (max_key_value == key_value) { - max_key = key; - } - } - } - - if (!min_key.empty()) { - if (max_key_value == min_key_value) { - deleteDatabaseValue(kEvents, min_key); - } else { - deleteDatabaseRange(kEvents, min_key, max_key); - } - } - } - - // Convert the key index into a time using the content. - // The last-recent event is fetched and the corresponding time is used as - // the expiration time for the subscriber. - std::string content; - getDatabaseValue(kEvents, data_key + "." + toIndex(threshold_key), content); - - // Decode the value into a row structure to extract the time. - Row r; - if (!deserializeRowJSON(content, r) || r.count("time") == 0) { - return; - } - - // The last time will become the implicit expiration time. - size_t last_time = boost::lexical_cast(r.at("time")); - if (last_time > 0) { - expire_time_ = last_time - (last_time % 60); - } - - // Finally, attempt an index query to trigger expirations. - // In this case the result set is not used. - getIndexes(expire_time_, 0, false); -} - -bool EventSubscriberPlugin::executedAllQueries() const { - ReadLock lock(event_query_record_); - return queries_.size() >= query_count_; -} - -std::vector EventSubscriberPlugin::getRecords( - const std::vector& indexes, bool optimize) { - auto record_key = "records." + dbNamespace(); - - std::vector records; - for (const auto& index : indexes) { - std::vector bin_records; - { - std::string record_value; - getDatabaseValue(kEvents, record_key + "." + index, record_value); - if (record_value.empty()) { - // There are actually no events in this bin, interesting error case. - continue; - } - - // Each list is tokenized into a record=event_id:time. - bin_records = split(record_value, ","); - } - - // Iterate over every 2 items: EID:TIME. - for (const auto& record : bin_records) { - const auto vals = split(record, ":"); - if (vals.size() != 2) { - LOG(WARNING) << "Event records mismatch: " << record - << " does not have a matching eid/event_time"; - continue; - } - const auto eid = vals[0]; - const EventTime et = timeFromRecord(vals[1]); - if (FLAGS_events_optimize && optimize && et <= optimize_time_ + 1) { - auto eidr = timeFromRecord(eid); - if (eidr <= optimize_eid_) { - continue; - } - } - records.push_back(std::make_pair(eid, et)); - } - } - - return records; -} - -Status EventSubscriberPlugin::recordEvents( - const std::vector& event_id_list, EventTime event_time) { - WriteLock lock(event_record_lock_); - - DatabaseStringValueList database_data; - database_data.reserve(2U); - - // The list key includes the list type (bin size) and the list ID (bin). - // The list_id is the MOST-Specific key ID, the bin for this list. - // If the event time was 13 and the time_list is 5 seconds, lid = 2. - auto list_id = boost::lexical_cast(event_time / 60); - std::string time_value = boost::lexical_cast(event_time); - - // The record is identified by the event type then module name. - // Append the record (eid, unix_time) to the list bin. - auto database_key = "records." + dbNamespace() + ".60." + list_id; - auto index_key = "indexes." + dbNamespace() + ".60"; - - std::string record_value; - getDatabaseValue(kEvents, database_key, record_value); - - for (const auto& eid : event_id_list) { - if (record_value.length() == 0) { - // This is a new list_id for list_key, append the ID to the indirect - // lookup for this list_key. - std::string index_value; - getDatabaseValue(kEvents, index_key, index_value); - if (index_value.length() == 0) { - // A new index. - index_value = list_id; - } else { - index_value += "," + list_id; - } - database_data.push_back(std::make_pair(index_key, index_value)); - record_value = eid + ":" + time_value; - } else { - // Tokenize a record using ',' and the EID/time using ':'. - record_value += "," + eid + ":" + time_value; - } - } - - database_data.push_back(std::make_pair(database_key, record_value)); - auto status = setDatabaseBatch(kEvents, database_data); - if (!status.ok()) { - LOG(ERROR) << "Could not put Event Records"; - } - - return status; -} - -size_t EventSubscriberPlugin::getEventsExpiry() { - return FLAGS_events_expiry; -} - -size_t EventSubscriberPlugin::getEventsMax() { - return FLAGS_events_max; -} - -const std::string EventSubscriberPlugin::getEventID() { - Status status; - // First get an event ID from the meta key. - std::string eid_key = "eid." + dbNamespace(); - - { - WriteLock lock(event_id_lock_); - if (last_eid_ == 0) { - std::string last_eid_value; - status = getDatabaseValue(kEvents, eid_key, last_eid_value); - if (!status.ok() || last_eid_value.empty()) { - last_eid_value = "0"; - } - last_eid_ = boost::lexical_cast(last_eid_value); - } - - if (last_eid_ % 10 == 0) { - status = setDatabaseValue(kEvents, eid_key, toIndex(last_eid_ + 10)); - } - last_eid_++; - } - - return toIndex(last_eid_); -} - -Status EventSubscriberPlugin::add(const Row& r) { - std::vector batch = {r}; - return addBatch(batch, getUnixTime()); -} - -Status EventSubscriberPlugin::addBatch(std::vector& row_list) { - return addBatch(row_list, getUnixTime()); -} - -Status EventSubscriberPlugin::addBatch(std::vector& row_list, - EventTime custom_event_time) { - DatabaseStringValueList database_data; - database_data.reserve(row_list.size()); - - std::vector event_id_list; - event_id_list.reserve(row_list.size()); - - auto event_time = custom_event_time != 0 ? custom_event_time : getUnixTime(); - auto event_time_str = std::to_string(event_time); - - for (auto& row : row_list) { - row["time"] = event_time_str; - row["eid"] = getEventID(); - - // Serialize and store the row data, for query-time retrieval. - std::string serialized_row; - auto status = serializeRowJSON(row, serialized_row); - if (!status.ok()) { - VLOG(1) << status.getMessage(); - continue; - } - - // Then remove the newline. - if (serialized_row.size() > 0 && serialized_row.back() == '\n') { - serialized_row.pop_back(); - } - - // Logger plugins may request events to be forwarded directly. - // If no active logger is marked 'usesLogEvent' then this is a no-op. - EventFactory::forwardEvent(serialized_row); - - // Store the event data in the batch - database_data.push_back(std::make_pair( - "data." + dbNamespace() + "." + row["eid"], serialized_row)); - - event_id_list.push_back(std::move(row["eid"])); - event_count_++; - - // Use the last EventID and a checkpoint bucket size to periodically apply - // buffer eviction. Eviction occurs if the total count exceeds events_max. - if (last_eid_ % EVENTS_CHECKPOINT == 0) { - expireCheck(); - } - } - - if (database_data.empty()) { - return Status(1, "Failed to process the rows"); - } - - // Save the batched data inside the database - auto status = setDatabaseBatch(kEvents, database_data); - if (!status.ok()) { - return status; - } - - return recordEvents(event_id_list, event_time); -} - -EventPublisherRef EventSubscriberPlugin::getPublisher() const { - return EventFactory::getEventPublisher(getType()); -} - -void EventSubscriberPlugin::removeSubscriptions() { - subscription_count_ = 0; - auto publisher = getPublisher(); - if (publisher == nullptr) { - LOG(WARNING) << "Cannot remove subscriptions from: " << getName(); - return; - } - - getPublisher()->removeSubscriptions(getName()); -} - -void EventFactory::delay() { - // Caller may disable event publisher threads. - if (FLAGS_disable_events) { - return; - } - - // Create a thread for each event publisher. - auto& ef = EventFactory::getInstance(); - for (const auto& publisher : EventFactory::getInstance().event_pubs_) { - // Publishers that did not set up correctly are put into an ending state. - if (!publisher.second->isEnding()) { - auto thread_ = std::make_shared( - std::bind(&EventFactory::run, publisher.first)); - ef.threads_.push_back(thread_); - } - } -} - -Status EventPublisherPlugin::addSubscription( - const SubscriptionRef& subscription) { - // The publisher threads may be running and if they fire events the list of - // subscriptions will be walked. - WriteLock lock(subscription_lock_); - subscriptions_.push_back(subscription); - return Status(0); -} - -void EventPublisherPlugin::removeSubscriptions(const std::string& subscriber) { - // See addSubscription for details on the critical section. - WriteLock lock(subscription_lock_); - auto end = - std::remove_if(subscriptions_.begin(), - subscriptions_.end(), - [&subscriber](const SubscriptionRef& subscription) { - return (subscription->subscriber_name == subscriber); - }); - subscriptions_.erase(end, subscriptions_.end()); -} - -void EventFactory::addForwarder(const std::string& logger) { - getInstance().loggers_.push_back(logger); -} - -void EventFactory::forwardEvent(const std::string& event) { - for (const auto& logger : getInstance().loggers_) { - Registry::call("logger", logger, {{"event", event}}); - } -} - -void EventFactory::configUpdate() { - // Scan the schedule for queries that touch "_events" tables. - // We will count the queries - std::map subscriber_details; - auto& ef = EventFactory::getInstance(); - for (const auto& details : subscriber_details) { - if (!ef.exists(details.first)) { - continue; - } - - WriteLock lock(ef.factory_lock_); - auto subscriber = ef.getEventSubscriber(details.first); - subscriber->min_expiration_ = details.second.max_interval * 3; - subscriber->min_expiration_ += (60 - (subscriber->min_expiration_ % 60)); - - // Emit a warning for each subscriber affected by the small expiration. - auto expiry = subscriber->getEventsExpiry(); - if (expiry > 0 && subscriber->min_expiration_ > expiry) { - LOG(INFO) << "Subscriber expiration is too low: " - << subscriber->getName(); - } - subscriber->query_count_ = details.second.query_count; - - WriteLock subscriber_lock(subscriber->event_query_record_); - subscriber->queries_.clear(); - } - - // If events are enabled configure the subscribers before publishers. - if (!FLAGS_disable_events) { - RegistryFactory::get().registry("event_subscriber")->configure(); - RegistryFactory::get().registry("event_publisher")->configure(); - } -} - -Status EventFactory::run(const std::string& type_id) { - if (FLAGS_disable_events) { - return Status::success(); - } - - // An interesting take on an event dispatched entrypoint. - // There is little introspection into the event type. - // Assume it can either make use of an entrypoint poller/selector or - // take care of async callback registrations in setUp/configure/run - // only once and handle event queuing/firing in callbacks. - EventPublisherRef publisher = nullptr; - { - auto& ef = EventFactory::getInstance(); - WriteLock lock(ef.factory_lock_); - publisher = ef.getEventPublisher(type_id); - } - - if (publisher == nullptr) { - return Status(1, "Event publisher is missing"); - } else if (publisher->hasStarted()) { - return Status(1, "Cannot restart an event publisher"); - } - VLOG(1) << "Starting event publisher run loop: " + type_id; - publisher->hasStarted(true); - - auto status = Status(0, "OK"); - while (!publisher->isEnding()) { - // Can optionally implement a global cooloff latency here. - status = publisher->run(); - if (!status.ok()) { - break; - } - publisher->restart_count_++; - } - if (!status.ok()) { - // The runloop status is not reflective of the event type's. - VLOG(1) << "Event publisher " << publisher->type() - << " run loop terminated for reason: " << status.getMessage(); - // Publishers auto tear down when their run loop stops. - } - publisher->tearDown(); - publisher->state(EventState::EVENT_NONE); - - // Do not remove the publisher from the event factory. - // If the event factory's `end` method was called these publishers will be - // cleaned up after their thread context is removed; otherwise, a removed - // thread context and failed publisher will remain available for stats. - return Status::success(); -} - -// There's no reason for the event factory to keep multiple instances. -EventFactory& EventFactory::getInstance() { - static EventFactory ef; - return ef; -} - -Status EventFactory::registerEventPublisher(const PluginRef& pub) { - // Try to downcast the plugin to an event publisher. - EventPublisherRef specialized_pub; - try { - auto base_pub = std::dynamic_pointer_cast(pub); - specialized_pub = std::static_pointer_cast(base_pub); - } catch (const std::bad_cast& /* e */) { - return Status(1, "Incorrect plugin"); - } - - if (specialized_pub == nullptr || specialized_pub.get() == nullptr) { - return Status::success(); - } - - auto type_id = specialized_pub->type(); - if (type_id.empty()) { - // This subscriber did not override its name. - return Status(1, "Publishers must have a type"); - } - - auto& ef = EventFactory::getInstance(); - { - WriteLock lock(getInstance().factory_lock_); - if (ef.event_pubs_.count(type_id) != 0) { - // This is a duplicate event publisher. - return Status(1, "Duplicate publisher type"); - } - - ef.event_pubs_[type_id] = specialized_pub; - } - - // Do not set up event publisher if events are disabled. - if (!FLAGS_disable_events) { - if (specialized_pub->state() != EventState::EVENT_NONE) { - specialized_pub->tearDown(); - } - - auto status = specialized_pub->setUp(); - specialized_pub->state(EventState::EVENT_SETUP); - if (!status.ok()) { - // Only start event loop if setUp succeeds. - LOG(INFO) << "Event publisher not enabled: " << type_id << ": " - << status.what(); - specialized_pub->isEnding(true); - return status; - } - } - - return Status::success(); -} - -Status EventFactory::registerEventSubscriber(const PluginRef& sub) { - // Try to downcast the plugin to an event subscriber. - EventSubscriberRef specialized_sub; - try { - auto base_sub = std::dynamic_pointer_cast(sub); - specialized_sub = std::static_pointer_cast(base_sub); - } catch (const std::bad_cast& /* e */) { - return Status(1, "Incorrect plugin"); - } - - if (specialized_sub == nullptr || specialized_sub.get() == nullptr) { - return Status(1, "Invalid subscriber"); - } - - // The config may use an "events" key to explicitly enabled or disable - // event subscribers. See EventSubscriber::disable. - auto name = specialized_sub->getName(); - if (name.empty()) { - // This subscriber did not override its name. - return Status(1, "Subscribers must have set a name"); - } - - if (specialized_sub->state() != EventState::EVENT_NONE) { - specialized_sub->tearDown(); - } - - // Allow subscribers a configure-time setup to determine if they should run. - auto status = specialized_sub->setUp(); - if (!status) { - specialized_sub->disabled = true; - } - specialized_sub->state(EventState::EVENT_SETUP); - - // Let the subscriber initialize any Subscriptions. - if (!FLAGS_disable_events && !specialized_sub->disabled) { - specialized_sub->expireCheck(); - status = specialized_sub->init(); - specialized_sub->state(EventState::EVENT_RUNNING); - } else { - specialized_sub->state(EventState::EVENT_PAUSED); - } - - auto& ef = EventFactory::getInstance(); - { - WriteLock lock(getInstance().factory_lock_); - ef.event_subs_[name] = specialized_sub; - } - - // Set state of subscriber. - if (!status.ok()) { - specialized_sub->state(EventState::EVENT_FAILED); - return Status(1, status.getMessage()); - } else { - return Status::success(); - } -} - -Status EventFactory::addSubscription(const std::string& type_id, - const std::string& name_id, - const SubscriptionContextRef& mc, - EventCallback cb) { - auto subscription = Subscription::create(name_id, mc, cb); - return EventFactory::addSubscription(type_id, subscription); -} - -Status EventFactory::addSubscription(const std::string& type_id, - const SubscriptionRef& subscription) { - EventPublisherRef publisher = getInstance().getEventPublisher(type_id); - if (publisher == nullptr) { - return Status(1, "Unknown event publisher"); - } - - // The event factory is responsible for configuring the event types. - return publisher->addSubscription(subscription); -} - -size_t EventFactory::numSubscriptions(const std::string& type_id) { - EventPublisherRef publisher; - try { - publisher = EventFactory::getInstance().getEventPublisher(type_id); - } catch (std::out_of_range& /* e */) { - return 0; - } - if (publisher == nullptr) { - return 0; - } - return publisher->numSubscriptions(); -} - -EventPublisherRef EventFactory::getEventPublisher(const std::string& type_id) { - if (getInstance().event_pubs_.count(type_id) == 0) { - LOG(ERROR) << "Requested unknown/failed event publisher: " + type_id; - return nullptr; - } - return getInstance().event_pubs_.at(type_id); -} - -EventSubscriberRef EventFactory::getEventSubscriber( - const std::string& name_id) { - if (!exists(name_id)) { - LOG(ERROR) << "Requested unknown event subscriber: " + name_id; - return nullptr; - } - return getInstance().event_subs_.at(name_id); -} - -bool EventFactory::exists(const std::string& name_id) { - return (getInstance().event_subs_.count(name_id) > 0); -} - -Status EventFactory::deregisterEventPublisher(const EventPublisherRef& pub) { - return EventFactory::deregisterEventPublisher(pub->type()); -} - -Status EventFactory::deregisterEventPublisher(const std::string& type_id) { - auto& ef = EventFactory::getInstance(); - - WriteLock lock(ef.factory_lock_); - EventPublisherRef publisher = ef.getEventPublisher(type_id); - if (publisher == nullptr) { - return Status(1, "No event publisher to deregister"); - } - - if (!FLAGS_disable_events) { - publisher->isEnding(true); - if (!publisher->hasStarted()) { - // If a publisher's run loop was not started, call tearDown since - // the setUp happened at publisher registration time. - publisher->tearDown(); - publisher->state(EventState::EVENT_NONE); - // If the run loop did run the tear down and erase will happen in the - // event thread wrapper when isEnding is next checked. - ef.event_pubs_.erase(type_id); - } - } - return Status::success(); -} - -Status EventFactory::deregisterEventSubscriber(const std::string& sub) { - auto& ef = EventFactory::getInstance(); - - WriteLock lock(ef.factory_lock_); - if (ef.event_subs_.count(sub) == 0) { - return Status(1, "Event subscriber is missing"); - } - - auto& subscriber = ef.event_subs_.at(sub); - subscriber->state(EventState::EVENT_NONE); - subscriber->tearDown(); - ef.event_subs_.erase(sub); - return Status(0); -} - -std::vector EventFactory::publisherTypes() { - WriteLock lock(getInstance().factory_lock_); - std::vector types; - for (const auto& publisher : getInstance().event_pubs_) { - types.push_back(publisher.first); - } - return types; -} - -std::vector EventFactory::subscriberNames() { - WriteLock lock(getInstance().factory_lock_); - std::vector names; - for (const auto& subscriber : getInstance().event_subs_) { - names.push_back(subscriber.first); - } - return names; -} - -void EventFactory::end(bool join) { - auto& ef = EventFactory::getInstance(); - - // Call deregister on each publisher. - for (const auto& publisher : ef.publisherTypes()) { - deregisterEventPublisher(publisher); - } - - // Stop handling exceptions for the publisher threads. - for (const auto& thread : ef.threads_) { - if (join) { - thread->join(); - } else { - thread->detach(); - } - } - - { - WriteLock lock(getInstance().factory_lock_); - // A small cool off helps OS API event publisher flushing. - if (!FLAGS_disable_events) { - ef.threads_.clear(); - } - - // Threads may still be executing, when they finish, release publishers. - ef.event_pubs_.clear(); - ef.event_subs_.clear(); - } -} - -void attachEvents() { - const auto& publishers = RegistryFactory::get().plugins("event_publisher"); - for (const auto& publisher : publishers) { - EventFactory::registerEventPublisher(publisher.second); - } - - const auto& subscribers = RegistryFactory::get().plugins("event_subscriber"); - for (const auto& subscriber : subscribers) { - if (!boost::ends_with(subscriber.first, "_events")) { - LOG(ERROR) << "Error registering subscriber: " << subscriber.first - << ": Must use a '_events' suffix"; - continue; - } - - auto status = EventFactory::registerEventSubscriber(subscriber.second); - if (!status.ok()) { - VLOG(1) << "Error registering subscriber: " << subscriber.first << ": " - << status.getMessage(); - } - } - - // Configure the event publishers and subscribers. - EventFactory::configUpdate(); -} -} // namespace osquery diff --git a/src/osquery/events/linux/auditdnetlink.cpp b/src/osquery/events/linux/auditdnetlink.cpp deleted file mode 100644 index 4b74793..0000000 --- a/src/osquery/events/linux/auditdnetlink.cpp +++ /dev/null @@ -1,881 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace osquery { -/// Control the audit subsystem by electing to be the single process sink. -FLAG(bool, audit_persist, true, "Attempt to retain control of audit"); - -/// Audit debugger helper -HIDDEN_FLAG(bool, audit_debug, false, "Debug Linux audit messages"); - -/// Control the audit subsystem by allowing subscriptions to apply rules. -FLAG(bool, - audit_allow_config, - false, - "Allow the audit publisher to change auditing configuration"); - -/// Always uninstall all the audit rules that osquery uses when exiting -FLAG(bool, - audit_force_unconfigure, - false, - "Always uninstall all rules, regardless of whether they were already " - "installed or not"); - -/// Forces osquery to remove all rules upon startup -FLAG(bool, - audit_force_reconfigure, - false, - "Configure the audit subsystem from scratch"); - -// External flags; they are used to determine which rules need to be installed -DECLARE_bool(audit_allow_fim_events); -DECLARE_bool(audit_allow_process_events); -DECLARE_bool(audit_allow_sockets); -DECLARE_bool(audit_allow_user_events); -DECLARE_bool(audit_allow_selinux_events); - -// user messages should be filtered -// also, we should handle the 2nd user message type -namespace { -bool IsSELinuxRecord(const audit_reply& reply) noexcept { - static const auto& selinux_event_set = kSELinuxEventList; - return (selinux_event_set.find(reply.type) != selinux_event_set.end()); -} - -bool ShouldHandle(const audit_reply& reply) noexcept { - if (IsSELinuxRecord(reply)) { - return FLAGS_audit_allow_selinux_events; - } - - switch (reply.type) { - case NLMSG_NOOP: - case NLMSG_DONE: - case NLMSG_ERROR: - case AUDIT_LIST_RULES: - case AUDIT_SECCOMP: - case AUDIT_GET: - case (AUDIT_GET + 1)...(AUDIT_LIST_RULES - 1): - case (AUDIT_LIST_RULES + 1)...(AUDIT_FIRST_USER_MSG - 1): - case AUDIT_DAEMON_START ... AUDIT_DAEMON_CONFIG: // 1200 - 1203 - case AUDIT_CONFIG_CHANGE: - return false; - - default: - return true; - } -} -} // namespace - -enum AuditStatus { - AUDIT_DISABLED = 0, - AUDIT_ENABLED = 1, - AUDIT_IMMUTABLE = 2, -}; - -AuditdNetlink::AuditdNetlink() { - try { - auditd_context_ = std::make_shared(); - - Dispatcher::addService( - std::make_shared(auditd_context_)); - - Dispatcher::addService( - std::make_shared(auditd_context_)); - - } catch (const std::bad_alloc&) { - VLOG(1) << "Failed to initialize the AuditdNetlink services due to a " - "memory allocation error"; - throw; - } -} - -std::vector AuditdNetlink::getEvents() noexcept { - std::vector record_list; - - { - std::unique_lock queue_lock( - auditd_context_->processed_events_mutex); - - if (auditd_context_->processed_records_cv.wait_for( - queue_lock, std::chrono::seconds(1)) == - std::cv_status::no_timeout) { - record_list = std::move(auditd_context_->processed_events); - auditd_context_->processed_events.clear(); - } - } - - return record_list; -} - -AuditdNetlinkReader::AuditdNetlinkReader(AuditdContextRef context) - : InternalRunnable("AuditdNetlinkReader"), - auditd_context_(std::move(context)), - read_buffer_(4096U) {} - -void AuditdNetlinkReader::start() { - int counter_to_next_status_request = 0; - const int status_request_countdown = 1000; - - while (!interrupted()) { - if (auditd_context_->acquire_handle) { - if (FLAGS_audit_debug) { - std::cout << "(re)acquiring the audit handle.." << std::endl; - } - - NetlinkStatus netlink_status = acquireHandle(); - - if (netlink_status == NetlinkStatus::Disabled || - netlink_status == NetlinkStatus::Error) { - std::this_thread::sleep_for(std::chrono::seconds(5)); - continue; - } - - auditd_context_->acquire_handle = false; - counter_to_next_status_request = status_request_countdown; - } - - if (counter_to_next_status_request == 0) { - errno = 0; - - if (audit_request_status(audit_netlink_handle_) <= 0) { - if (errno == ENOBUFS) { - VLOG(1) << "Warning: Failed to request audit status (ENOBUFS). " - "Retrying again later"; - - } else { - VLOG(1) << "Error: Failed to request audit status. Requesting a " - "handle reset"; - - auditd_context_->acquire_handle = true; - } - } - - counter_to_next_status_request = status_request_countdown; - } else { - --counter_to_next_status_request; - } - - if (!acquireMessages()) { - auditd_context_->acquire_handle = true; - } - } -} - -void AuditdNetlinkReader::stop() { - if (audit_netlink_handle_ == -1) { - return; - } - - VLOG(1) << "Releasing the audit handle..."; - - auditd_context_->unprocessed_records_cv.notify_all(); - restoreAuditServiceConfiguration(); - - audit_close(audit_netlink_handle_); - audit_netlink_handle_ = -1; -} - -bool AuditdNetlinkReader::acquireMessages() noexcept { - pollfd fds[] = {{audit_netlink_handle_, POLLIN, 0}}; - - struct sockaddr_nl nladdr = {}; - socklen_t nladdrlen = sizeof(nladdr); - - bool reset_handle = false; - size_t events_received = 0; - - // Attempt to read as many messages as possible before we exit, and terminate - // early if we have been asked to terminate - for (events_received = 0; - !interrupted() && events_received < read_buffer_.size(); - events_received++) { - errno = 0; - int poll_status = ::poll(fds, 1, 2000); - if (poll_status == 0) { - break; - } - - if (poll_status < 0) { - if (errno != EINTR) { - reset_handle = true; - VLOG(1) << "poll() failed with error " << errno; - } - - break; - } - - if ((fds[0].revents & POLLIN) == 0) { - break; - } - - audit_reply reply = {}; - ssize_t len = recvfrom(audit_netlink_handle_, - &reply.msg, - sizeof(reply.msg), - 0, - reinterpret_cast(&nladdr), - &nladdrlen); - - if (len < 0) { - VLOG(1) << "Failed to receive data from the audit netlink"; - reset_handle = true; - break; - } - - if (nladdrlen != sizeof(nladdr)) { - VLOG(1) << "Protocol error"; - reset_handle = true; - break; - } - - if (nladdr.nl_pid) { - VLOG(1) << "Invalid netlink endpoint"; - reset_handle = true; - break; - } - - if (!NLMSG_OK(&reply.msg.nlh, static_cast(len))) { - if (len == sizeof(reply.msg)) { - VLOG(1) << "Netlink event too big (EFBIG)"; - } else { - VLOG(1) << "Broken netlink event (EBADE)"; - } - - reset_handle = true; - break; - } - - read_buffer_[events_received] = reply; - } - - if (events_received != 0) { - std::unique_lock lock( - auditd_context_->unprocessed_records_mutex); - - auditd_context_->unprocessed_records.reserve( - auditd_context_->unprocessed_records.size() + events_received); - - auditd_context_->unprocessed_records.insert( - auditd_context_->unprocessed_records.end(), - read_buffer_.begin(), - std::next(read_buffer_.begin(), events_received)); - - auditd_context_->unprocessed_records_cv.notify_all(); - } - - if (reset_handle) { - VLOG(1) << "Requesting audit handle reset"; - return false; - } - - return true; -} - -bool AuditdNetlinkReader::configureAuditService() noexcept { - VLOG(1) << "Attempting to configure the audit service"; - - // Want to set a min sane buffer and maximum number of events/second min. - // This is normally controlled through the audit config, but we must - // enforce sane minimums: -b 8192 -e 100 - audit_set_backlog_wait_time(audit_netlink_handle_, 1); - audit_set_backlog_limit(audit_netlink_handle_, 4096); - audit_set_failure(audit_netlink_handle_, AUDIT_FAIL_SILENT); - - // Request only the highest priority of audit status messages. - set_aumessage_mode(MSG_QUIET, DBG_NO); - - // - // Audit rules - // - - // Rules required by the socket_events table - if (FLAGS_audit_allow_sockets) { - VLOG(1) << "Enabling audit rules for the socket_events table"; - - for (int syscall : kSocketEventsSyscalls) { - monitored_syscall_list_.insert(syscall); - } - } - - // Rules required by the process_events table - if (FLAGS_audit_allow_process_events) { - VLOG(1) << "Enabling audit rules for the process_events table"; - - for (int syscall : kProcessEventsSyscalls) { - monitored_syscall_list_.insert(syscall); - } - } - - // Rules required by the process_file_events table - if (FLAGS_audit_allow_fim_events) { - VLOG(1) << "Enabling audit rules for the process_file_events table"; - - for (int syscall : kProcessFileEventsSyscalls) { - monitored_syscall_list_.insert(syscall); - } - } - - // Attempt to add each one of the rules we collected - for (int syscall_number : monitored_syscall_list_) { - audit_rule_data rule = {}; - audit_rule_syscall_data(&rule, syscall_number); - - // clang-format off - int rule_add_error = audit_add_rule_data(audit_netlink_handle_, &rule, - // We want to be notified when we exit from the syscall - AUDIT_FILTER_EXIT, - - // Always audit this syscall event - AUDIT_ALWAYS - ); - // clang-format on - - // When exiting, don't remove the rules that were already installed, unless - // we have been asked to - if (rule_add_error >= 0) { - if (FLAGS_audit_debug) { - std::cout << "Audit rule installed for syscall " << syscall_number - << std::endl; - } - - installed_rule_list_.push_back(rule); - continue; - } - - if (FLAGS_audit_debug) { - std::cout << "Audit rule for syscall " << syscall_number - << " could not be installed. Errno: " << (-errno) << std::endl; - } - - if (FLAGS_audit_force_unconfigure) { - installed_rule_list_.push_back(rule); - } - - rule_add_error = -rule_add_error; - - if (rule_add_error != EEXIST) { - VLOG(1) << "The following syscall number could not be added to the audit " - "service rules: " - << syscall_number << ". Some of the auditd " - << "table may not work properly (process_events, " - << "socket_events, process_file_events, user_events)"; - } - } - - return true; -} - -bool AuditdNetlinkReader::clearAuditConfiguration() noexcept { - int seq = audit_request_rules_list_data(audit_netlink_handle_); - if (seq <= 0) { - VLOG(1) << "Failed to list the audit rules"; - return false; - } - - // Attempt to list all rules - std::vector rule_object_list; - auto timeout = getUnixTime() + 5; - - for (size_t read_retry = 0U; read_retry < 3U; ++read_retry) { - if (timeout < getUnixTime()) { - VLOG(1) << "Failed to unconfigure the audit service (timeout)"; - return false; - } - - bool netlink_ready = false; - - for (size_t poll_retry = 0U; poll_retry < 3U; ++poll_retry) { - pollfd fds[] = {{audit_netlink_handle_, POLLIN, 0}}; - - errno = 0; - int poll_status = ::poll(fds, 1, 4); - if (poll_status == 0) { - continue; - } - - if (poll_status < 0) { - VLOG(1) << "poll() failed with errno " << errno; - return false; - } - - if ((fds[0].revents & POLLIN) != 0) { - netlink_ready = true; - break; - } - } - - if (!netlink_ready) { - VLOG(1) << "Could not read from the audit netlink"; - return false; - } - - // Get the reply from the audit link - struct audit_reply reply = {}; - if (audit_get_reply( - audit_netlink_handle_, &reply, GET_REPLY_NONBLOCKING, 0) <= 0) { - continue; - } - - read_retry = 0; - if (reply.nlh->nlmsg_seq != static_cast(seq)) { - continue; - } - - if (reply.type == NLMSG_DONE) { - // We have finished listing the rules - break; - } - - if (reply.type == NLMSG_ERROR && reply.error->error != 0) { - return false; - } - - if (reply.type != AUDIT_LIST_RULES) { - // Skip this reply if it is not part of the rule list output - continue; - } - - // Save the rule - const auto reply_size = sizeof(reply) + reply.ruledata->buflen; - - AuditRuleDataObject reply_object(reply_size); - - std::memcpy(reply_object.data(), reply.ruledata, reply_size); - rule_object_list.push_back(reply_object); - } - - // Delete each rule - size_t error_count = 0U; - for (auto& rule_object : rule_object_list) { - if (!deleteAuditRule(rule_object)) { - error_count++; - } - } - - if (error_count != 0U) { - VLOG(1) << error_count << " audit rules could not be correctly removed"; - return false; - } - - VLOG(1) << "The audit configuration has been cleared"; - return true; -} - -bool AuditdNetlinkReader::deleteAuditRule( - const AuditRuleDataObject& rule_object) { - if (NLMSG_SPACE(rule_object.size()) > MAX_AUDIT_MESSAGE_LENGTH) { - return false; - } - - auto rule_data = - reinterpret_cast(rule_object.data()); - - struct audit_message request = {}; - request.nlh.nlmsg_len = static_cast<__u32>(NLMSG_SPACE(rule_object.size())); - request.nlh.nlmsg_type = AUDIT_DEL_RULE; - request.nlh.nlmsg_flags = NLM_F_REQUEST; - std::memcpy(NLMSG_DATA(&request.nlh), rule_data, rule_object.size()); - - struct sockaddr_nl address = {}; - address.nl_family = AF_NETLINK; - - bool success = false; - - for (size_t retry = 0U; retry < 3U; retry++) { - ssize_t bytes_sent; - - while (true) { - errno = 0; - bytes_sent = sendto(audit_netlink_handle_, - &request, - request.nlh.nlmsg_len, - 0, - reinterpret_cast(&address), - sizeof(address)); - if (bytes_sent >= 0) { - break; - } - - if (errno != EINTR) { - return false; - } - } - - if (bytes_sent == static_cast(request.nlh.nlmsg_len)) { - success = true; - break; - } - } - - return success; -} - -void AuditdNetlinkReader::restoreAuditServiceConfiguration() noexcept { - if (FLAGS_audit_debug) { - std::cout << "Uninstalling audit rules" << std::endl; - } - - // Remove the rules we have added - VLOG(1) << "Uninstalling the audit rules we have installed"; - - for (auto& rule : installed_rule_list_) { - audit_delete_rule_data( - audit_netlink_handle_, &rule, AUDIT_FILTER_EXIT, AUDIT_ALWAYS); - } - - installed_rule_list_.clear(); - - // Restore audit configuration defaults. - if (FLAGS_audit_debug) { - std::cout << "Restoring default settings and disabling the service" - << std::endl; - } - - VLOG(1) << "Restoring the default configuration for the audit service"; - - audit_set_backlog_limit(audit_netlink_handle_, 0); - audit_set_backlog_wait_time(audit_netlink_handle_, 60000); - audit_set_failure(audit_netlink_handle_, AUDIT_FAIL_PRINTK); - audit_set_enabled(audit_netlink_handle_, AUDIT_DISABLED); -} - -NetlinkStatus AuditdNetlinkReader::acquireHandle() noexcept { - // Returns the audit netlink status - auto L_GetNetlinkStatus = [](int netlink_handle) -> NetlinkStatus { - if (netlink_handle <= 0) { - return NetlinkStatus::Error; - } - - errno = 0; - if (audit_request_status(netlink_handle) < 0 && errno != ENOBUFS) { - VLOG(1) << "Failed to query the audit netlink status"; - return NetlinkStatus::Error; - } - - auto enabled = audit_is_enabled(netlink_handle); - - if (enabled == AUDIT_IMMUTABLE || getuid() != 0 || - !FLAGS_audit_allow_config) { - return NetlinkStatus::ActiveImmutable; - - } else if (enabled == AUDIT_ENABLED) { - return NetlinkStatus::ActiveMutable; - - } else if (enabled == AUDIT_DISABLED) { - return NetlinkStatus::Disabled; - - } else { - return NetlinkStatus::Error; - } - }; - - if (audit_netlink_handle_ != -1) { - audit_close(audit_netlink_handle_); - audit_netlink_handle_ = -1; - } - - audit_netlink_handle_ = audit_open(); - if (audit_netlink_handle_ <= 0) { - VLOG(1) << "Failed to acquire the netlink handle"; - - audit_netlink_handle_ = -1; - return NetlinkStatus::Error; - } - - if (audit_set_pid(audit_netlink_handle_, getpid(), WAIT_NO) < 0) { - VLOG(1) << "Failed to set the netlink owner"; - - audit_close(audit_netlink_handle_); - audit_netlink_handle_ = -1; - - return NetlinkStatus::Error; - } - - NetlinkStatus netlink_status = L_GetNetlinkStatus(audit_netlink_handle_); - if (FLAGS_audit_allow_config && - (netlink_status != NetlinkStatus::ActiveMutable && - netlink_status != NetlinkStatus::ActiveImmutable)) { - if (audit_set_enabled(audit_netlink_handle_, AUDIT_ENABLED) < 0) { - VLOG(1) << "Failed to enable the audit service"; - - audit_close(audit_netlink_handle_); - audit_netlink_handle_ = -1; - - return NetlinkStatus::Error; - } - - if (FLAGS_audit_debug) { - std::cout << "Audit service enabled" << std::endl; - } - } - - if (FLAGS_audit_allow_config) { - if (FLAGS_audit_force_reconfigure) { - if (!clearAuditConfiguration()) { - audit_netlink_handle_ = -1; - return NetlinkStatus::Error; - } - } - - if (!configureAuditService()) { - return NetlinkStatus::ActiveImmutable; - } - - if (FLAGS_audit_debug) { - std::cout << "Audit service configured" << std::endl; - } - } - - return NetlinkStatus::ActiveMutable; -} - -AuditdNetlinkParser::AuditdNetlinkParser(AuditdContextRef context) - : InternalRunnable("AuditdNetlinkParser"), - auditd_context_(std::move(context)) {} - -void AuditdNetlinkParser::start() { - while (!interrupted()) { - std::vector queue; - - { - std::unique_lock lock( - auditd_context_->unprocessed_records_mutex); - - while (auditd_context_->unprocessed_records.empty() && !interrupted()) { - auditd_context_->unprocessed_records_cv.wait_for( - lock, std::chrono::seconds(1)); - } - - queue = std::move(auditd_context_->unprocessed_records); - auditd_context_->unprocessed_records.clear(); - } - - std::vector audit_event_record_queue; - audit_event_record_queue.reserve(queue.size()); - - for (auto& reply : queue) { - if (interrupted()) { - break; - } - - AdjustAuditReply(reply); - - // This record carries the process id of the controlling daemon; in case - // we lost control of the audit service, we are going to request a reset - // as soon as we finish processing the pending queue - if (reply.type == AUDIT_GET) { - reply.status = static_cast(NLMSG_DATA(reply.nlh)); - auto new_pid = static_cast(reply.status->pid); - - if (new_pid != getpid()) { - VLOG(1) << "Audit control lost to pid: " << new_pid; - - if (FLAGS_audit_persist) { - VLOG(1) << "Attempting to reacquire control of the audit service"; - auditd_context_->acquire_handle = true; - } - } - - continue; - } - - // We are not interested in all messages; only get the ones related to - // user events, syscalls and SELinux events - if (!ShouldHandle(reply)) { - continue; - } - - AuditEventRecord audit_event_record = {}; - if (!ParseAuditReply(reply, audit_event_record)) { - VLOG(1) << "Malformed audit record received"; - continue; - } - - audit_event_record_queue.push_back(audit_event_record); - } - - // Save the new records and notify the reader - if (!audit_event_record_queue.empty()) { - std::lock_guard queue_lock( - auditd_context_->processed_events_mutex); - - auditd_context_->processed_events.reserve( - auditd_context_->processed_events.size() + - audit_event_record_queue.size()); - - auditd_context_->processed_events.insert( - auditd_context_->processed_events.end(), - audit_event_record_queue.begin(), - audit_event_record_queue.end()); - - auditd_context_->processed_records_cv.notify_all(); - } - - queue.clear(); - audit_event_record_queue.clear(); - } -} - -bool AuditdNetlinkParser::ParseAuditReply( - const audit_reply& reply, AuditEventRecord& event_record) noexcept { - event_record = {}; - - if (FLAGS_audit_debug) { - std::cout << reply.type << ", " << std::string(reply.message, reply.len) - << std::endl; - } - - // Parse the record header - event_record.type = reply.type; - boost::string_ref message_view(reply.message, - static_cast(reply.len)); - - auto preamble_end = message_view.find("): "); - if (preamble_end == std::string::npos) { - return false; - } - - event_record.time = - tryTo(message_view.substr(6, 10).to_string(), 10) - .takeOr(event_record.time); - event_record.audit_id = message_view.substr(6, preamble_end - 6).to_string(); - - // SELinux doesn't output valid audit records; just save them as they are - if (IsSELinuxRecord(reply)) { - event_record.raw_data = reply.message; - return true; - } - - // Tokenize the message - boost::string_ref field_view(message_view.substr(preamble_end + 3)); - - // The linear search will construct series of key value pairs. - std::string key, value; - key.reserve(20); - value.reserve(256); - - // There are several ways of representing value data (enclosed strings, - // etc). - bool found_assignment{false}; - bool found_enclose{false}; - - for (const auto& c : field_view) { - // Iterate over each character in the audit message. - if ((found_enclose && c == '"') || (!found_enclose && c == ' ')) { - if (c == '"') { - value += c; - } - - // This is a terminating sequence, the end of an enclosure or space - // tok. - if (!key.empty()) { - // Multiple space tokens are supported. - event_record.fields.emplace( - std::make_pair(std::move(key), std::move(value))); - } - - found_enclose = false; - found_assignment = false; - - key.clear(); - value.clear(); - - } else if (!found_assignment && c == ' ') { - // A field tokenizer. - - } else if (found_assignment) { - // Enclosure sequences appear immediately following assignment. - if (c == '"') { - found_enclose = true; - } - - value += c; - - } else if (c == '=') { - found_assignment = true; - - } else { - key += c; - } - } - - // Last step, if there was no trailing tokenizer. - if (!key.empty()) { - event_record.fields.emplace( - std::make_pair(std::move(key), std::move(value))); - } - - return true; -} - -void AuditdNetlinkParser::AdjustAuditReply(audit_reply& reply) noexcept { - reply.type = reply.msg.nlh.nlmsg_type; - reply.len = reply.msg.nlh.nlmsg_len; - reply.nlh = &reply.msg.nlh; - - reply.status = nullptr; - reply.ruledata = nullptr; - reply.login = nullptr; - reply.message = nullptr; - reply.error = nullptr; - reply.signal_info = nullptr; - reply.conf = nullptr; - - switch (reply.type) { - case NLMSG_ERROR: { - reply.error = static_cast(NLMSG_DATA(reply.nlh)); - break; - } - - case AUDIT_LIST_RULES: { - reply.ruledata = - static_cast(NLMSG_DATA(reply.nlh)); - break; - } - - case AUDIT_USER: - case AUDIT_LOGIN: - case AUDIT_KERNEL: - case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: - case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: - case AUDIT_FIRST_EVENT ... AUDIT_INTEGRITY_LAST_MSG: { - reply.message = static_cast(NLMSG_DATA(reply.nlh)); - break; - } - - case AUDIT_SIGNAL_INFO: { - reply.signal_info = static_cast(NLMSG_DATA(reply.nlh)); - break; - } - - default: - break; - } -} -} // namespace osquery diff --git a/src/osquery/events/linux/auditdnetlink.h b/src/osquery/events/linux/auditdnetlink.h deleted file mode 100644 index 4476cc3..0000000 --- a/src/osquery/events/linux/auditdnetlink.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace osquery { - -/// Netlink status, used by AuditNetlink::acquireHandle() -enum class NetlinkStatus { ActiveMutable, ActiveImmutable, Disabled, Error }; - -/// Contains an audit_rule_data structure -using AuditRuleDataObject = std::vector; - -/// A single, prepared audit event record. -struct AuditEventRecord final { - /// Record type (i.e.: AUDIT_SYSCALL, AUDIT_PATH, ...) - int type; - - /// Event time. - unsigned long int time; - - /// Audit event id that owns this record. Remember: PRIMARY KEY(id, timestamp) - std::string audit_id; - - /// The field list for this record. Valid for everything except SELinux - /// records - std::map fields; - - /// The raw message, only valid for SELinux records (because they have broken - /// syntax) - std::string raw_data; -}; - -static_assert(std::is_move_constructible::value, - "not move constructible"); - -// This structure is used to share data between the reading and processing -// services -struct AuditdContext final { - /// Unprocessed audit records - std::vector unprocessed_records; - static_assert( - std::is_move_constructible::value, - "not move constructible"); - - /// Mutex for the list of unprocessed records - std::mutex unprocessed_records_mutex; - - /// Processed events condition variable - std::condition_variable unprocessed_records_cv; - - /// This queue contains processed events - std::vector processed_events; - - /// Processed events queue mutex. - std::mutex processed_events_mutex; - - /// Used to wake up the thread that processes the raw audit records - std::condition_variable processed_records_cv; - - /// When set to true, the audit handle is (re)acquired - std::atomic_bool acquire_handle{true}; -}; - -using AuditdContextRef = std::shared_ptr; - -/// This is the service responsible for reading data from the audit netlink -class AuditdNetlinkReader final : public InternalRunnable { - public: - explicit AuditdNetlinkReader(AuditdContextRef context); - - protected: - virtual void start() override; - virtual void stop() override; - - private: - /// Reads as many audit event records as possible before returning. - bool acquireMessages() noexcept; - - /// Configures the audit service and applies required rules - bool configureAuditService() noexcept; - - /// Clears out the audit configuration - bool clearAuditConfiguration() noexcept; - - /// Deletes the given audit rule - bool deleteAuditRule(const AuditRuleDataObject& rule_object); - - /// Removes the rules that we have applied - void restoreAuditServiceConfiguration() noexcept; - - /// (Re)acquire the netlink handle. - NetlinkStatus acquireHandle() noexcept; - - private: - /// Shared data - AuditdContextRef auditd_context_; - - /// Read buffer used when receiving events from the netlink - std::vector read_buffer_; - - /// The set of rules we applied (and that we'll uninstall when exiting) - std::vector installed_rule_list_; - - /// The syscalls we are listening for - std::set monitored_syscall_list_; - - /// Netlink handle. - int audit_netlink_handle_{-1}; -}; - -/// This service parses the raw audit records -class AuditdNetlinkParser final : public InternalRunnable { - public: - explicit AuditdNetlinkParser(AuditdContextRef context); - virtual void start() override; - - /// Parses an audit_reply structure into an AuditEventRecord object - static bool ParseAuditReply(const audit_reply& reply, - AuditEventRecord& event_record) noexcept; - - /// Adjusts the internal pointers of the audit_reply object - static void AdjustAuditReply(audit_reply& reply) noexcept; - - private: - /// Shared data - AuditdContextRef auditd_context_; -}; - -/// This class provides access to the audit netlink data -class AuditdNetlink final : private boost::noncopyable { - public: - AuditdNetlink(); - virtual ~AuditdNetlink() = default; - - /// Prepares the raw audit event records stored in the given context. - std::vector getEvents() noexcept; - - private: - /// Shared data - AuditdContextRef auditd_context_; -}; - -/// Handle quote and hex-encoded audit field content. -inline std::string DecodeAuditPathValues(const std::string& s) { - if (s.size() > 1 && s[0] == '"') { - return s.substr(1, s.size() - 2); - } - - try { - return boost::algorithm::unhex(s); - } catch (const boost::algorithm::hex_decode_error& e) { - return s; - } -} -} // namespace osquery diff --git a/src/osquery/events/linux/auditeventpublisher.cpp b/src/osquery/events/linux/auditeventpublisher.cpp deleted file mode 100644 index 50cc01d..0000000 --- a/src/osquery/events/linux/auditeventpublisher.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include -#include -#include -#include -#include - -namespace osquery { -/// The audit subsystem may have a performance impact on the system. -FLAG(bool, - disable_audit, - true, - "Disable receiving events from the audit subsystem"); - -// External flags; they are used to determine whether we should run or not -DECLARE_bool(audit_allow_fim_events); -DECLARE_bool(audit_allow_process_events); -DECLARE_bool(audit_allow_sockets); -DECLARE_bool(audit_allow_user_events); -DECLARE_bool(audit_allow_selinux_events); - -REGISTER(AuditEventPublisher, "event_publisher", "auditeventpublisher"); - -namespace { -bool IsPublisherEnabled() noexcept { - if (FLAGS_disable_audit) { - return false; - } - - return (FLAGS_audit_allow_fim_events || FLAGS_audit_allow_process_events || - FLAGS_audit_allow_sockets || FLAGS_audit_allow_user_events || - FLAGS_audit_allow_selinux_events); -} -} // namespace - -std::string AuditEventPublisher::executable_path_; - -Status AuditEventPublisher::setUp() { - if (!IsPublisherEnabled()) { - return Status(1, "Publisher disabled via configuration"); - } - - if (executable_path_.empty()) { - char buffer[PATH_MAX] = {}; - assert(readlink("/proc/self/exe", buffer, sizeof(buffer)) != -1); - executable_path_ = buffer; - } - - return Status::success(); -} - -void AuditEventPublisher::configure() { - if (!IsPublisherEnabled()) { - return; - } - - if (audit_netlink_ == nullptr) { - audit_netlink_ = std::make_unique(); - } -} - -void AuditEventPublisher::tearDown() { - if (!IsPublisherEnabled()) { - return; - } - - audit_netlink_.reset(); -} - -Status AuditEventPublisher::run() { - if (!IsPublisherEnabled()) { - return Status(1, "Publisher disabled via configuration"); - } - - auto audit_event_record_queue = audit_netlink_->getEvents(); - - auto event_context = createEventContext(); - - // This is a simple estimate based on the process_file_events_tests.cpp - // records - auto event_count_estimate = audit_event_record_queue.size() / 4U; - event_context->audit_events.reserve(event_count_estimate); - - ProcessEvents(event_context, audit_event_record_queue, audit_trace_context_); - if (!event_context->audit_events.empty()) { - fire(event_context); - } - - return Status::success(); -} - -void AuditEventPublisher::ProcessEvents( - AuditEventContextRef event_context, - const std::vector& record_list, - AuditTraceContext& trace_context) noexcept { - static const auto& selinux_event_set = kSELinuxEventList; - - // Assemble each record into a AuditEvent object; multi-record events - // are complete when we receive the terminator (AUDIT_EOE) - for (const auto& audit_event_record : record_list) { - auto audit_event_it = trace_context.find(audit_event_record.audit_id); - - // We have two entry points here; the first one is for user messages, while - // the second one is for syscalls - if (audit_event_record.type >= AUDIT_FIRST_USER_MSG && - audit_event_record.type <= AUDIT_LAST_USER_MSG) { - UserAuditEventData data = {}; - data.user_event_id = static_cast(audit_event_record.type); - - AuditEvent audit_event; - audit_event.type = AuditEvent::Type::UserEvent; - audit_event.record_list.push_back(std::move(audit_event_record)); - audit_event.data = data; - - event_context->audit_events.push_back(audit_event); - - // SELinux events - } else if (selinux_event_set.find(audit_event_record.type) != - selinux_event_set.end()) { - AuditEvent audit_event; - audit_event.type = AuditEvent::Type::SELinux; - audit_event.record_list.push_back(audit_event_record); - - event_context->audit_events.push_back(audit_event); - - } else if (audit_event_record.type == AUDIT_SYSCALL) { - if (audit_event_it != trace_context.end()) { - VLOG(1) << "Received a duplicated event."; - trace_context.erase(audit_event_it); - } - - AuditEvent audit_event; - audit_event.type = AuditEvent::Type::Syscall; - - // Estimate based on the process_file_events_tests.cpp records - audit_event.record_list.reserve(4U); - - SyscallAuditEventData data; - - std::string raw_executable_path; - if (!GetStringFieldFromMap( - raw_executable_path, audit_event_record.fields, "exe")) { - VLOG(1) << "Malformed AUDIT_SYSCALL record received. The " - "executable path field is either missing or not valid."; - - continue; - } - - data.executable_path = DecodeAuditPathValues(raw_executable_path); - - // Do not process events originated by the osquery watchdog or daemon - if (executable_path_ == data.executable_path) { - continue; - } - - if (!GetIntegerFieldFromMap( - data.syscall_number, audit_event_record.fields, "syscall")) { - VLOG(1) << "Malformed AUDIT_SYSCALL record received. The " - "syscall field " - "is either missing or not valid."; - - continue; - } - - std::string syscall_status; - GetStringFieldFromMap( - syscall_status, audit_event_record.fields, "success", "yes"); - - // By discarding this event, we will also automatically discard any other - // attached record - if (syscall_status != "yes") { - continue; - } - - std::uint64_t process_id; - if (!GetIntegerFieldFromMap( - process_id, audit_event_record.fields, "pid")) { - VLOG(1) << "Malformed AUDIT_SYSCALL record received. The process id " - "field is either missing or not valid."; - - continue; - } - - std::uint64_t parent_process_id; - if (!GetIntegerFieldFromMap( - parent_process_id, audit_event_record.fields, "ppid")) { - VLOG(1) << "Malformed AUDIT_SYSCALL record received. The parent " - "process id field is either missing or not valid."; - - continue; - } - - data.process_id = static_cast(process_id); - data.parent_process_id = static_cast(parent_process_id); - audit_event.data = data; - - std::uint64_t process_uid; - if (!GetIntegerFieldFromMap( - process_uid, audit_event_record.fields, "uid")) { - VLOG(1) << "Missing or invalid uid field in AUDIT_SYSCALL"; - - continue; - } - - std::uint64_t process_euid; - if (!GetIntegerFieldFromMap( - process_euid, audit_event_record.fields, "euid")) { - VLOG(1) << "Missing or invalid euid field in AUDIT_SYSCALL"; - - continue; - } - - std::uint64_t process_gid; - if (!GetIntegerFieldFromMap( - process_gid, audit_event_record.fields, "gid")) { - VLOG(1) << "Missing or invalid gid field in AUDIT_SYSCALL"; - - continue; - } - - std::uint64_t process_egid; - if (!GetIntegerFieldFromMap( - process_egid, audit_event_record.fields, "egid")) { - VLOG(1) << "Missing or invalid egid field in AUDIT_SYSCALL"; - - continue; - } - - data.process_uid = static_cast(process_uid); - data.process_euid = static_cast(process_euid); - data.process_gid = static_cast(process_gid); - data.process_egid = static_cast(process_egid); - - audit_event.record_list.push_back(audit_event_record); - trace_context[audit_event_record.audit_id] = std::move(audit_event); - - // This is the terminator for multi-record audit events - } else if (audit_event_record.type == AUDIT_EOE) { - if (audit_event_it == trace_context.end()) { - continue; - } - - auto completed_audit_event = audit_event_it->second; - trace_context.erase(audit_event_it); - - event_context->audit_events.push_back(std::move(completed_audit_event)); - - } else { - if (audit_event_it == trace_context.end()) { - continue; - } - - audit_event_it->second.record_list.push_back(audit_event_record); - } - } - - // Drop events that are older than 5 minutes; it means that we have failed to - // receive the end of record and will never complete them correctly - - std::time_t current_time; - std::time(¤t_time); - - std::unordered_map timestamp_cache; - - // The first part of the audit id is a timestamp: 1501323932.710:7670542 - for (auto event_it = trace_context.begin(); - event_it != trace_context.end();) { - const auto& audit_event_id = event_it->first; - std::time_t event_timestamp; - - auto timestamp_it = timestamp_cache.find(audit_event_id); - if (timestamp_it == timestamp_cache.end()) { - std::string string_timestamp = audit_event_id.substr(0, 10); - - event_timestamp = tryTo(string_timestamp).takeOr(0ll); - - timestamp_cache[audit_event_id] = event_timestamp; - - } else { - event_timestamp = timestamp_it->second; - } - - if (current_time - event_timestamp >= 300) { - event_it = trace_context.erase(event_it); - } else { - event_it++; - } - } -} - -const AuditEventRecord* GetEventRecord(const AuditEvent& event, - int record_type) noexcept { - auto it = std::find_if(event.record_list.begin(), - event.record_list.end(), - [record_type](const AuditEventRecord& record) -> bool { - return (record.type == record_type); - }); - - if (it == event.record_list.end()) { - return nullptr; - } - - return &(*it); -}; - -bool GetStringFieldFromMap(std::string& value, - const std::map& fields, - const std::string& name, - const std::string& default_value) noexcept { - auto it = fields.find(name); - if (it == fields.end()) { - value = default_value; - return false; - } - - value = it->second; - return true; -} - -bool GetIntegerFieldFromMap(std::uint64_t& value, - const std::map& field_map, - const std::string& field_name, - std::size_t base, - std::uint64_t default_value) noexcept { - std::string string_value; - if (!GetStringFieldFromMap(string_value, field_map, field_name, "")) { - value = default_value; - return false; - } - auto exp = tryTo(string_value, base); - value = exp.takeOr(std::move(default_value)); - return exp.isValue(); -} - -void CopyFieldFromMap(Row& row, - const std::map& fields, - const std::string& name, - const std::string& default_value) noexcept { - GetStringFieldFromMap(row[name], fields, name, default_value); -} -} // namespace osquery diff --git a/src/osquery/events/linux/auditeventpublisher.h b/src/osquery/events/linux/auditeventpublisher.h deleted file mode 100644 index 1e220b0..0000000 --- a/src/osquery/events/linux/auditeventpublisher.h +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include - -#include -#include - -namespace osquery { - -struct UserAuditEventData final { - std::uint64_t user_event_id; -}; - -struct SyscallAuditEventData final { - std::uint64_t syscall_number; - - pid_t process_id; - pid_t parent_process_id; - - uid_t process_uid; - uid_t process_euid; - - gid_t process_gid; - gid_t process_egid; - - std::string executable_path; -}; - -/// Audit event descriptor -struct AuditEvent final { - enum class Type { UserEvent, Syscall, SELinux }; - - Type type; - boost::variant data; - - std::vector record_list; -}; - -/// Audit event pretty printer, used for the --audit_fim_debug flag -std::ostream& operator<<(std::ostream& stream, const AuditEvent& audit_event); - -struct AuditSubscriptionContext final : public SubscriptionContext { - private: - friend class AuditEventPublisher; -}; - -struct AuditEventContext final : public EventContext { - std::vector audit_events; -}; - -using AuditEventContextRef = std::shared_ptr; -using AuditSubscriptionContextRef = std::shared_ptr; - -/// This type maps audit event id with the corresponding audit event object -using AuditTraceContext = std::map; - -class AuditEventPublisher final - : public EventPublisher { - DECLARE_PUBLISHER("auditeventpublisher"); - - public: - Status setUp() override; - void configure() override; - void tearDown() override; - Status run() override; - - virtual ~AuditEventPublisher() { - tearDown(); - } - - /// Executable path - static std::string executable_path_; - - /// Aggregates raw event records into audit events - static void ProcessEvents(AuditEventContextRef event_context, - const std::vector& record_list, - AuditTraceContext& trace_context) noexcept; - - private: - /// Netlink reader - std::unique_ptr audit_netlink_; - - /// This is where audit records are assembled - AuditTraceContext audit_trace_context_; -}; - -/// Extracts the specified audit event record from the given audit event -const AuditEventRecord* GetEventRecord(const AuditEvent& event, - int record_type) noexcept; - -/// Extracts the specified string key from the given string map -bool GetStringFieldFromMap( - std::string& value, - const std::map& fields, - const std::string& name, - const std::string& default_value = std::string()) noexcept; - -/// Extracts the specified integer key from the given string map -bool GetIntegerFieldFromMap( - std::uint64_t& value, - const std::map& field_map, - const std::string& field_name, - std::size_t base = 10, - std::uint64_t default_value = - std::numeric_limits::max()) noexcept; - -/// Copies a named field from the 'fields' map to the specified row -void CopyFieldFromMap( - Row& row, - const std::map& fields, - const std::string& name, - const std::string& default_value = std::string()) noexcept; -} // namespace osquery diff --git a/src/osquery/events/linux/inotify.cpp b/src/osquery/events/linux/inotify.cpp deleted file mode 100644 index 0705b07..0000000 --- a/src/osquery/events/linux/inotify.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "osquery/events/linux/inotify.h" - -namespace fs = boost::filesystem; - -namespace osquery { - -static const size_t kINotifyMaxEvents = 512; -static const size_t kINotifyEventSize = - sizeof(struct inotify_event) + (NAME_MAX + 1); -static const size_t kINotifyBufferSize = - (kINotifyMaxEvents * kINotifyEventSize); - -std::map kMaskActions = { - {IN_ACCESS, "ACCESSED"}, - {IN_ATTRIB, "ATTRIBUTES_MODIFIED"}, - {IN_CLOSE_WRITE, "UPDATED"}, - {IN_CREATE, "CREATED"}, - {IN_DELETE, "DELETED"}, - {IN_MODIFY, "UPDATED"}, - {IN_MOVED_FROM, "MOVED_FROM"}, - {IN_MOVED_TO, "MOVED_TO"}, - {IN_OPEN, "OPENED"}, -}; - -const uint32_t kFileDefaultMasks = IN_MOVED_TO | IN_MOVED_FROM | IN_MODIFY | - IN_DELETE | IN_CREATE | IN_CLOSE_WRITE | - IN_ATTRIB; -const uint32_t kFileAccessMasks = IN_OPEN | IN_ACCESS; - -REGISTER(INotifyEventPublisher, "event_publisher", "inotify"); - -Status INotifyEventPublisher::setUp() { - inotify_handle_ = ::inotify_init(); - // If this does not work throw an exception. - if (inotify_handle_ == -1) { - return Status(1, "Could not start inotify: inotify_init failed"); - } - - WriteLock lock(scratch_mutex_); - scratch_ = (char*)malloc(kINotifyBufferSize); - if (scratch_ == nullptr) { - return Status(1, "Could not allocate scratch space"); - } - return Status::success(); -} - -bool INotifyEventPublisher::needMonitoring(const std::string& path, - INotifySubscriptionContextRef& isc, - uint32_t mask, - bool recursive, - bool add_watch) { - bool rc = true; - struct stat file_dir_stat; - time_t sc_time = isc->path_sc_time_[path]; - - if (stat(path.c_str(), &file_dir_stat) == -1) { - LOG(WARNING) << "Failed to do stat on: " << path; - return false; - } - - if (sc_time != file_dir_stat.st_ctime) { - if ((rc = addMonitor(path, isc, isc->mask, isc->recursive, add_watch))) { - isc->path_sc_time_[path] = file_dir_stat.st_ctime; - } - } - return rc; -} - -bool INotifyEventPublisher::monitorSubscription( - INotifySubscriptionContextRef& sc, bool add_watch) { - std::string discovered = sc->path; - if (sc->path.find("**") != std::string::npos) { - sc->recursive = true; - discovered = sc->path.substr(0, sc->path.find("**")); - sc->path = discovered; - } - - if (sc->path.find('*') != std::string::npos) { - // If the wildcard exists within the file (leaf), remove and monitor the - // directory instead. Apply a fnmatch on fired events to filter leafs. - auto fullpath = fs::path(sc->path); - if (fullpath.filename().string().find('*') != std::string::npos) { - discovered = fullpath.parent_path().string() + '/'; - } - - if (discovered.find('*') != std::string::npos) { - // If a wildcard exists within the tree (stem), resolve at configure - // time and monitor each path. - std::vector paths; - resolveFilePattern(discovered, paths); - sc->recursive_match = sc->recursive; - for (const auto& _path : paths) { - needMonitoring(_path, sc, sc->mask, sc->recursive, add_watch); - } - return true; - } - } - - if (isDirectory(discovered) && discovered.back() != '/') { - sc->path += '/'; - discovered += '/'; - } - - return needMonitoring(discovered, sc, sc->mask, sc->recursive, add_watch); -} - -void INotifyEventPublisher::buildExcludePathsSet() { - auto parser = Config::getParser("file_paths"); - - WriteLock lock(subscription_lock_); - exclude_paths_.clear(); - - const auto& doc = parser->getData(); - if (!doc.doc().HasMember("exclude_paths")) { - return; - } - - for (const auto& category : doc.doc()["exclude_paths"].GetObject()) { - for (const auto& excl_path : category.value.GetArray()) { - std::string pattern = excl_path.GetString(); - if (pattern.empty()) { - continue; - } - exclude_paths_.insert(pattern); - } - } -} - -void INotifyEventPublisher::configure() { - if (inotify_handle_ == -1) { - // This publisher has not been setup correctly. - return; - } - - SubscriptionVector delete_subscriptions; - { - WriteLock lock(subscription_lock_); - auto end = std::remove_if( - subscriptions_.begin(), - subscriptions_.end(), - [&delete_subscriptions](const SubscriptionRef& subscription) { - auto inotify_sc = getSubscriptionContext(subscription->context); - if (inotify_sc->mark_for_deletion == true) { - delete_subscriptions.push_back(subscription); - return true; - } - return false; - }); - subscriptions_.erase(end, subscriptions_.end()); - } - - for (auto& sub : delete_subscriptions) { - auto ino_sc = getSubscriptionContext(sub->context); - for (const auto& path : ino_sc->descriptor_paths_) { - removeMonitor(path.first, true, true); - } - ino_sc->descriptor_paths_.clear(); - } - delete_subscriptions.clear(); - - buildExcludePathsSet(); - - for (auto& sub : subscriptions_) { - // Anytime a configure is called, try to monitor all subscriptions. - // Configure is called as a response to removing/adding subscriptions. - // This means recalculating all monitored paths. - auto sc = getSubscriptionContext(sub->context); - monitorSubscription(sc); - } -} - -void INotifyEventPublisher::tearDown() { - if (inotify_handle_ > -1) { - ::close(inotify_handle_); - } - inotify_handle_ = -1; - - WriteLock lock(scratch_mutex_); - if (scratch_ != nullptr) { - free(scratch_); - scratch_ = nullptr; - } -} - -void INotifyEventPublisher::handleOverflow() { - if (inotify_events_ < kINotifyMaxEvents) { - VLOG(1) << "inotify was overflown: increasing scratch buffer"; - // Exponential increment. - inotify_events_ = inotify_events_ * 2; - } else if (last_overflow_ != -1 && getUnixTime() - last_overflow_ < 60) { - return; - } else { - VLOG(1) << "inotify was overflown"; - last_overflow_ = getUnixTime(); - } -} - -Status INotifyEventPublisher::run() { - struct pollfd fds[1]; - fds[0].fd = getHandle(); - fds[0].events = POLLIN; - int selector = ::poll(fds, 1, 1000); - if (selector == -1) { - if (errno == EINTR) { - return Status::success(); - } - LOG(WARNING) << "Could not read inotify handle"; - return Status(1, "inotify poll failed"); - } - - if (selector == 0) { - // Read timeout. - return Status::success(); - } - - if (!(fds[0].revents & POLLIN)) { - return Status::success(); - } - - WriteLock lock(scratch_mutex_); - ssize_t record_num = - ::read(getHandle(), scratch_, inotify_events_ * kINotifyEventSize); - if (record_num == 0 || record_num == -1) { - return Status(1, "INotify read failed"); - } - - for (char* p = scratch_; p < scratch_ + record_num;) { - // Cast the inotify struct, make shared pointer, and append to contexts. - auto event = reinterpret_cast(p); - if (event->mask & IN_Q_OVERFLOW) { - // The inotify queue was overflown (try to receive more events from OS). - handleOverflow(); - } else if (event->mask & IN_IGNORED) { - // This inotify watch was removed. - removeMonitor(event->wd, false); - } else if (event->mask & IN_MOVE_SELF) { - // This inotify path was moved, but is still watched. - removeMonitor(event->wd, true); - } else if (event->mask & IN_DELETE_SELF) { - // A file was moved to replace the watched path. - removeMonitor(event->wd, false); - } else { - auto ec = createEventContextFrom(event); - if (!ec->action.empty()) { - fire(ec); - } - } - // Continue to iterate - p += (sizeof(struct inotify_event)) + event->len; - } - - return Status::success(); -} - -INotifyEventContextRef INotifyEventPublisher::createEventContextFrom( - struct inotify_event* event) const { - auto ec = createEventContext(); - ec->event = std::make_unique(*event); - - // Get the pathname the watch fired on. - { - WriteLock lock(path_mutex_); - if (descriptor_inosubctx_.find(event->wd) == descriptor_inosubctx_.end()) { - // return a blank event context if we can't find the paths for the event - return ec; - } else { - auto isc = descriptor_inosubctx_.at(event->wd); - ec->path = isc->descriptor_paths_.at(event->wd); - ec->isub_ctx = isc; - } - } - - if (event->len > 1) { - ec->path += event->name; - } - - for (const auto& action : kMaskActions) { - if (event->mask & action.first) { - ec->action = action.second; - break; - } - } - return ec; -} - -bool INotifyEventPublisher::shouldFire(const INotifySubscriptionContextRef& sc, - const INotifyEventContextRef& ec) const { - if (sc.get() != ec->isub_ctx.get()) { - /// Not my event. - return false; - } - - // The subscription may supply a required event mask. - if (sc->mask != 0 && !(ec->event->mask & sc->mask)) { - return false; - } - - // inotify will not monitor recursively, new directories need watches. - if (sc->recursive && ec->action == "CREATED" && isDirectory(ec->path)) { - const_cast(this)->addMonitor( - ec->path + '/', - const_cast(sc), - sc->mask, - true); - } - - // exclude paths should be applied at last - auto path = ec->path.substr(0, ec->path.rfind('/')); - // Need to have two finds, - // what if somebody excluded an individual file inside a directory - if (!exclude_paths_.empty() && - (exclude_paths_.find(path) || exclude_paths_.find(ec->path))) { - return false; - } - - return true; -} - -bool INotifyEventPublisher::addMonitor(const std::string& path, - INotifySubscriptionContextRef& isc, - uint32_t mask, - bool recursive, - bool add_watch) { - { - WriteLock lock(path_mutex_); - int watch = ::inotify_add_watch( - getHandle(), path.c_str(), ((mask == 0) ? kFileDefaultMasks : mask)); - if (add_watch && watch == -1) { - LOG(WARNING) << "Could not add inotify watch on: " << path; - return false; - } - - if (descriptor_inosubctx_.find(watch) != descriptor_inosubctx_.end()) { - auto ino_sc = descriptor_inosubctx_.at(watch); - if (inotify_sanity_check) { - std::string watched_path = ino_sc->descriptor_paths_[watch]; - path_descriptors_.erase(watched_path); - } - ino_sc->descriptor_paths_.erase(watch); - descriptor_inosubctx_.erase(watch); - } - - // Keep a map of (descriptor -> path) - isc->descriptor_paths_[watch] = path; - descriptor_inosubctx_[watch] = isc; - if (inotify_sanity_check) { - // Keep a map of the path -> watch descriptor - path_descriptors_[path] = watch; - } - } - - if (recursive && isDirectory(path).ok()) { - std::vector children; - // Get a list of children of this directory (requested recursive watches). - listDirectoriesInDirectory(path, children, true); - - boost::system::error_code ec; - for (const auto& child : children) { - auto canonicalized = fs::canonical(child, ec).string() + '/'; - addMonitor(canonicalized, isc, mask, false); - } - } - - return true; -} - -bool INotifyEventPublisher::removeMonitor(int watch, - bool force, - bool batch_del) { - { - WriteLock lock(path_mutex_); - if (descriptor_inosubctx_.find(watch) == descriptor_inosubctx_.end()) { - return false; - } - - auto isc = descriptor_inosubctx_.at(watch); - descriptor_inosubctx_.erase(watch); - - if (inotify_sanity_check) { - std::string watched_path = isc->descriptor_paths_[watch]; - path_descriptors_.erase(watched_path); - } - - if (!batch_del) { - isc->descriptor_paths_.erase(watch); - } - } - - if (force) { - ::inotify_rm_watch(getHandle(), watch); - } - - return true; -} - -void INotifyEventPublisher::removeSubscriptions(const std::string& subscriber) { - WriteLock lock(subscription_lock_); - std::for_each(subscriptions_.begin(), - subscriptions_.end(), - [&subscriber](const SubscriptionRef& sub) { - if (sub->subscriber_name == subscriber) { - getSubscriptionContext(sub->context)->mark_for_deletion = - true; - } - }); -} - -Status INotifyEventPublisher::addSubscription( - const SubscriptionRef& subscription) { - WriteLock lock(subscription_lock_); - auto received_inotify_sc = getSubscriptionContext(subscription->context); - for (auto& sub : subscriptions_) { - auto inotify_sc = getSubscriptionContext(sub->context); - if (*received_inotify_sc == *inotify_sc) { - if (inotify_sc->mark_for_deletion) { - inotify_sc->mark_for_deletion = false; - return Status(0); - } - // Returning non zero signals EventSubscriber::subscribe - // do not bump up subscription_count_. - return Status(1); - } - } - - subscriptions_.push_back(subscription); - return Status(0); -} - -bool INotifyEventPublisher::isPathMonitored(const std::string& path) const { - WriteLock lock(path_mutex_); - std::string parent_path; - if (!isDirectory(path).ok()) { - if (path_descriptors_.find(path) != path_descriptors_.end()) { - // Path is a file, and is directly monitored. - return true; - } - // Important to add a trailing "/" for inotify. - parent_path = fs::path(path).parent_path().string() + '/'; - } else { - parent_path = path; - } - // Directory or parent of file monitoring - auto path_iterator = path_descriptors_.find(parent_path); - return (path_iterator != path_descriptors_.end()); -} -} diff --git a/src/osquery/events/linux/inotify.h b/src/osquery/events/linux/inotify.h deleted file mode 100644 index c6abfe3..0000000 --- a/src/osquery/events/linux/inotify.h +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include - -#include - -#include "osquery/events/pathset.h" - -namespace osquery { - -extern std::map kMaskActions; - -extern const uint32_t kFileDefaultMasks; -extern const uint32_t kFileAccessMasks; - -// INotifySubscriptionContext containers -using PathDescriptorMap = std::map; -using DescriptorPathMap = std::map; -using PathStatusChangeTimeMap = std::map; - -/** - * @brief Subscription details for INotifyEventPublisher events. - * - * This context is specific to INotifyEventPublisher. It allows the - * subscribing EventSubscriber to set a path (file or directory) and a - * limited action mask. - * Events are passed to the EventSubscriber if they match the context - * path (or anything within a directory if the path is a directory) and if the - * event action is part of the mask. If the mask is 0 then all actions are - * passed to the EventSubscriber. - */ -struct INotifySubscriptionContext : public SubscriptionContext { - /// Subscription the following filesystem path. - std::string path; - - /// original path, read from config - std::string opath; - - /// Limit the `inotify` actions to the subscription mask (if not 0). - uint32_t mask{0}; - - /// Treat this path as a directory and subscription recursively. - bool recursive{false}; - - /// Save the category this path originated form within the config. - std::string category; - - /// Lazy deletion of a subscription. - bool mark_for_deletion{false}; - - /** - * @brief Helper method to map a string action to `inotify` action mask bit. - * - * This helper method will set the `mask` value for this SubscriptionContext. - * - * @param action The string action, a value in kMaskAction%s. - */ - void requireAction(const std::string& action) { - for (const auto& bit : kMaskActions) { - if (action == bit.second) { - mask = mask | bit.first; - } - } - } - - private: - /// A configure-time pattern was expanded to match absolute paths. - bool recursive_match{false}; - - /// Map of inotify watch file descriptor to watched path string. - DescriptorPathMap descriptor_paths_; - - /// Map of path and status change time of file/directory. - PathStatusChangeTimeMap path_sc_time_; - - private: - friend class INotifyEventPublisher; -}; - -/// Overloaded '==' operator, to check if two inotify subscriptions are same. -inline bool operator==(const INotifySubscriptionContext& lsc, - const INotifySubscriptionContext& rsc) { - return ((lsc.category == rsc.category) && (lsc.opath == rsc.opath)); -} - -using INotifySubscriptionContextRef = - std::shared_ptr; - -/** - * @brief Event details for INotifyEventPublisher events. - */ -struct INotifyEventContext : public EventContext { - /// The inotify_event structure if the EventSubscriber want to interact. - std::unique_ptr event{nullptr}; - - /// A string path parsed from the inotify_event. - std::string path; - - /// A string action representing the event action `inotify` bit. - std::string action; - - /// A no-op event transaction id. - uint32_t transaction_id{0}; - - /// This event ctx belongs to isub_ctx - INotifySubscriptionContextRef isub_ctx; -}; - -using INotifyEventContextRef = std::shared_ptr; - -// Publisher container -using DescriptorINotifySubCtxMap = std::map; - -using ExcludePathSet = PathSet; - -/** - * @brief A Linux `inotify` EventPublisher. - * - * This EventPublisher allows EventSubscriber%s to subscription for Linux - *`inotify` events. - * Since these events are limited this EventPublisher will optimize the watch - * descriptors, keep track of the usage, implement optimizations/priority - * where possible, and abstract file system events to a path/action context. - * - * Uses INotifySubscriptionContext and INotifyEventContext for subscriptioning, - *eventing. - */ -class INotifyEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("inotify"); - - public: - //@param unit_test publisher is instantiated for unit test. - INotifyEventPublisher(bool unit_test = false) - : inotify_sanity_check(unit_test) {} - - virtual ~INotifyEventPublisher() { - tearDown(); - } - - /// Create an `inotify` handle descriptor. - Status setUp() override; - - /// The configuration finished loading or was updated. - void configure() override; - - /// Release the `inotify` handle descriptor. - void tearDown() override; - - /// The calling for beginning the thread's run loop. - Status run() override; - - /// Mark for delete, subscriptions. - void removeSubscriptions(const std::string& subscriber) override; - - /// Only add the subscription, if it not already part of subscription list. - Status addSubscription(const SubscriptionRef& subscription) override; - - private: - /// Helper/specialized event context creation. - INotifyEventContextRef createEventContextFrom( - struct inotify_event* event) const; - - /// Check if the application-global `inotify` handle is alive. - bool isHandleOpen() const { - return inotify_handle_ > 0; - } - - /// Check all added Subscription%s for a path. - /// Used for sanity check from unit test(s). - bool isPathMonitored(const std::string& path) const; - - /** - * @brief Add an INotify watch (monitor) on this path. - * - * Check if a given path is already monitored (perhaps the parent path) has - * and existing monitor and this is a non-directory leaf? On success the - * file descriptor is stored for lookup when events fire. - * - * A recursive flag will tell addMonitor to enumerate all subdirectories - * recursively and add monitors to them. - * - * @param path complete (non-glob) canonical path to monitor. - * @param subscription context tracking the path. - * @param recursive perform a single recursive search of subdirectories. - * @param add_watch (testing only) should an inotify watch be created. - * @return success if the inotify watch was created. - */ - bool addMonitor(const std::string& path, - INotifySubscriptionContextRef& isc, - uint32_t mask, - bool recursive, - bool add_watch = true); - - /** - * Some decision making code refactored in needMonitoring before calling - * addMonitor in the context of monitorSubscription. - * Decision to call addMonitor from the context of monitorSubscription - * is done based on the status change time of file/directory, since - * creation time is not available on linux. - */ - bool needMonitoring(const std::string& path, - INotifySubscriptionContextRef& isc, - uint32_t mask, - bool recursive, - bool add_watch); - - /// Helper method to parse a subscription and add an equivalent monitor. - bool monitorSubscription(INotifySubscriptionContextRef& sc, - bool add_watch = true); - - /// Build the set of excluded paths for which events are not to be propogated. - void buildExcludePathsSet(); - - /// Remove an INotify watch (monitor) from our tracking. - bool removeMonitor(int watch, bool force = false, bool batch_del = false); - - /// Given a SubscriptionContext and INotifyEventContext match path and action. - bool shouldFire(const INotifySubscriptionContextRef& mc, - const INotifyEventContextRef& ec) const override; - - /// Get the INotify file descriptor. - int getHandle() const { - return inotify_handle_; - } - - /// Get the number of actual INotify active descriptors. - size_t numDescriptors() const { - return descriptor_inosubctx_.size(); - } - - /// If we overflow, try to read more events from OS at time. - void handleOverflow(); - - /// Map of watched path string to inotify watch file descriptor. - /// Used for sanity check from unit test(s). - PathDescriptorMap path_descriptors_; - - /// Map of inotify watch file descriptor to subscription context. - DescriptorINotifySubCtxMap descriptor_inosubctx_; - - /// Events pertaining to these paths not to be propagated. - ExcludePathSet exclude_paths_; - - /// The inotify file descriptor handle. - std::atomic inotify_handle_{-1}; - - /// Time in seconds of the last inotify overflow. - std::atomic last_overflow_{-1}; - - /// Tracks how many events to be received from OS. - size_t inotify_events_{16}; - - /// Enable for sanity check from unit test(s). - bool inotify_sanity_check{false}; - - /** - * @brief Scratch space for reading INotify responses. - * - * We place this here, and include a mutex to do heap/lazy allocation of the - * near-3k buffer when the publisher loads. This reduces the need to stack - * allocate a local buffer every 200mils and also improves the eventless-case. - * - * Allocated during setUp, removed in tearDown, protected by scratch_mutex_. - */ - char* scratch_{nullptr}; - - /// Access to path and descriptor mappings. - mutable Mutex path_mutex_; - - /// Access the Inofity response scratch space. - mutable Mutex scratch_mutex_; - - public: - friend class INotifyTests; - FRIEND_TEST(INotifyTests, test_inotify_init); - FRIEND_TEST(INotifyTests, test_inotify_optimization); - FRIEND_TEST(INotifyTests, DISABLED_test_inotify_recursion); - FRIEND_TEST(INotifyTests, test_inotify_match_subscription); - FRIEND_TEST(INotifyTests, test_inotify_embedded_wildcards); -}; -} diff --git a/src/osquery/events/linux/process_events.h b/src/osquery/events/linux/process_events.h deleted file mode 100644 index f7ffaea..0000000 --- a/src/osquery/events/linux/process_events.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include - -const std::set kProcessEventsSyscalls = { - __NR_execve}; diff --git a/src/osquery/events/linux/process_file_events.h b/src/osquery/events/linux/process_file_events.h deleted file mode 100644 index 171c8b7..0000000 --- a/src/osquery/events/linux/process_file_events.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include - -const std::set kProcessFileEventsSyscalls = { - __NR_linkat, - __NR_symlink, - __NR_symlinkat, - __NR_unlink, - __NR_unlinkat, - __NR_rename, - __NR_renameat, - __NR_renameat2, - __NR_creat, - __NR_mknod, - __NR_mknodat, - __NR_open, - __NR_openat, - __NR_open_by_handle_at, - __NR_name_to_handle_at, - __NR_close, - __NR_dup, - __NR_dup2, - __NR_dup3, - __NR_pread64, - __NR_preadv, - __NR_read, - __NR_readv, - __NR_mmap, - __NR_write, - __NR_writev, - __NR_pwrite64, - __NR_pwritev, - __NR_truncate, - __NR_ftruncate, - __NR_clone, - __NR_fork, - __NR_vfork}; diff --git a/src/osquery/events/linux/selinux_events.h b/src/osquery/events/linux/selinux_events.h deleted file mode 100644 index 5f68b57..0000000 --- a/src/osquery/events/linux/selinux_events.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include - -// This map must contain exactly the same elements that -// SELinuxEventSubscriber::GetEventSet() returns! -// clang-format off -const std::map kSELinuxRecordLabels = { - {AUDIT_USER_AVC, "USER_AVC"}, - {AUDIT_AVC, "AVC"}, - {AUDIT_SELINUX_ERR, "SELINUX_ERR"}, - {AUDIT_AVC_PATH, "AVC_PATH"}, - {AUDIT_MAC_POLICY_LOAD, "MAC_POLICY_LOAD"}, - {AUDIT_MAC_STATUS, "MAC_STATUS"}, - {AUDIT_MAC_CONFIG_CHANGE, "MAC_CONFIG_CHANGE"}, - {AUDIT_MAC_UNLBL_ALLOW, "MAC_UNLBL_ALLOW"}, - {AUDIT_MAC_CIPSOV4_ADD, "MAC_CIPSOV4_ADD"}, - {AUDIT_MAC_CIPSOV4_DEL, "MAC_CIPSOV4_DEL"}, - {AUDIT_MAC_MAP_ADD, "MAC_MAP_ADD"}, - {AUDIT_MAC_MAP_DEL, "MAC_MAP_DEL"}, - {AUDIT_MAC_IPSEC_ADDSA, "MAC_IPSEC_ADDSA"}, - {AUDIT_MAC_IPSEC_DELSA, "MAC_IPSEC_DELSA"}, - {AUDIT_MAC_IPSEC_ADDSPD, "MAC_IPSEC_ADDSPD"}, - {AUDIT_MAC_IPSEC_DELSPD, "MAC_IPSEC_DELSPD"}, - {AUDIT_MAC_IPSEC_EVENT, "MAC_IPSEC_EVENT"}, - {AUDIT_MAC_UNLBL_STCADD, "MAC_UNLBL_STCADD"}, - {AUDIT_MAC_UNLBL_STCDEL, "MAC_UNLBL_STCDEL"} -}; -// clang-format on - -// Documented events that could not be found in the headers: -// - USER_SELINUX_ERR -// - USER_MAC_POLICY_LOAD -// - USER_ROLE_CHANGE -// - USER_LABEL_EXPORT -const std::set kSELinuxEventList = { - // This is outside the documented numeric range (1400-1499) - AUDIT_USER_AVC, - - AUDIT_AVC, - AUDIT_SELINUX_ERR, - AUDIT_AVC_PATH, - AUDIT_MAC_POLICY_LOAD, - AUDIT_MAC_STATUS, - AUDIT_MAC_CONFIG_CHANGE, - AUDIT_MAC_UNLBL_ALLOW, - AUDIT_MAC_CIPSOV4_ADD, - AUDIT_MAC_CIPSOV4_DEL, - AUDIT_MAC_MAP_ADD, - AUDIT_MAC_MAP_DEL, - AUDIT_MAC_IPSEC_ADDSA, - AUDIT_MAC_IPSEC_DELSA, - AUDIT_MAC_IPSEC_ADDSPD, - AUDIT_MAC_IPSEC_DELSPD, - AUDIT_MAC_IPSEC_EVENT, - AUDIT_MAC_UNLBL_STCADD, - AUDIT_MAC_UNLBL_STCDEL}; diff --git a/src/osquery/events/linux/socket_events.h b/src/osquery/events/linux/socket_events.h deleted file mode 100644 index cb5303f..0000000 --- a/src/osquery/events/linux/socket_events.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include - -const std::set kSocketEventsSyscalls = { - __NR_bind, - __NR_connect}; diff --git a/src/osquery/events/linux/syslog.cpp b/src/osquery/events/linux/syslog.cpp deleted file mode 100644 index 6ffd656..0000000 --- a/src/osquery/events/linux/syslog.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "osquery/events/linux/syslog.h" - -namespace fs = boost::filesystem; - -namespace osquery { - -FLAG(bool, enable_syslog, false, "Enable the syslog ingestion event publisher"); - -FLAG(string, - syslog_pipe_path, - "/var/osquery/syslog_pipe", - "Path to the named pipe used for forwarding rsyslog events"); - -FLAG(uint64, - syslog_rate_limit, - 100, - "Maximum number of logs to ingest per run (~200ms between runs)"); - -REGISTER(SyslogEventPublisher, "event_publisher", "syslog"); - -// rsyslog needs read/write access, osquery process needs read access -const mode_t kPipeMode = 0460; -const std::string kPipeGroupName = "syslog"; -const char* kTimeFormat = "%Y-%m-%dT%H:%M:%S"; -const std::vector kCsvFields = { - "time", "host", "severity", "facility", "tag", "message"}; -const size_t kErrorThreshold = 10; - -Status SyslogEventPublisher::setUp() { - if (!FLAGS_enable_syslog) { - return Status(1, "Publisher disabled via configuration"); - } - - Status s; - if (!pathExists(FLAGS_syslog_pipe_path)) { - VLOG(1) << "Pipe does not exist: creating pipe " << FLAGS_syslog_pipe_path; - s = createPipe(FLAGS_syslog_pipe_path); - if (!s.ok()) { - LOG(WARNING) << RLOG(1964) - << "Problems encountered creating pipe: " << s.getMessage(); - } - } - - fs::file_status file_status = fs::status(FLAGS_syslog_pipe_path); - if (file_status.type() != fs::fifo_file) { - return Status(1, "Not a FIFO file: " + FLAGS_syslog_pipe_path); - } - - // Try to acquire a lock on the pipe, to make sure we're the only osquery - // related process reading from it. - s = lockPipe(FLAGS_syslog_pipe_path); - if (!s.ok()) { - return s; - } - - // Opening with both flags appears to be the only way to open the pipe - // without blocking for a writer. We won't ever write to the pipe, but we - // don't want to block here and will instead block waiting for a read in the - // run() method - readStream_.open(FLAGS_syslog_pipe_path, - std::ifstream::in | std::ifstream::out); - if (!readStream_.good()) { - return Status(1, - "Error opening pipe for reading: " + FLAGS_syslog_pipe_path); - } - VLOG(1) << "Successfully opened pipe for syslog ingestion: " - << FLAGS_syslog_pipe_path; - - return Status::success(); -} - -Status SyslogEventPublisher::createPipe(const std::string& path) { - if (mkfifo(FLAGS_syslog_pipe_path.c_str(), kPipeMode) != 0) { - return Status(1, "Error in mkfifo: " + std::string(strerror(errno))); - } - - // Explicitly set the permissions since the umask will effect the - // permissions created by mkfifo - if (chmod(FLAGS_syslog_pipe_path.c_str(), kPipeMode) != 0) { - return Status(1, "Error in chmod: " + std::string(strerror(errno))); - } - - // Try to set the group so that rsyslog will be able to write to the pipe - struct group* group = getgrnam(kPipeGroupName.c_str()); - if (group == nullptr) { - VLOG(1) << "No group " << kPipeGroupName - << " found. Not changing group for the pipe."; - return Status::success(); - } - if (chown(FLAGS_syslog_pipe_path.c_str(), -1, group->gr_gid) == -1) { - return Status(1, - "Error in chown to group " + kPipeGroupName + ": " + - std::string(strerror(errno))); - } - return Status::success(); -} - -Status SyslogEventPublisher::lockPipe(const std::string& path) { - lockFd_ = open(path.c_str(), O_NONBLOCK); - if (lockFd_ == -1) { - return Status( - 1, "Error in open for locking pipe: " + std::string(strerror(errno))); - } - if (flock(lockFd_, LOCK_EX | LOCK_NB) != 0) { - close(lockFd_); - lockFd_ = -1; - return Status( - 1, "Unable to acquire pipe lock: " + std::string(strerror(errno))); - } - return Status::success(); -} - -void SyslogEventPublisher::unlockPipe() { - if (lockFd_ != -1) { - if (flock(lockFd_, LOCK_UN) != 0) { - LOG(WARNING) << "Error unlocking pipe: " << std::string(strerror(errno)); - } - close(lockFd_); - lockFd_ = -1; - } -} - -Status SyslogEventPublisher::run() { - // This run function will be called by the event factory with ~100ms pause - // (see InterruptableRunnable::pause()) between runs. In case something goes - // weird and there is a huge amount of input, we limit how many logs we - // take in per run to avoid pegging the CPU. - for (size_t i = 0; i < FLAGS_syslog_rate_limit; ++i) { - if (readStream_.rdbuf()->in_avail() == 0) { - // If there is no pending data, we have flushed everything and can wait - // until the next time EventFactory calls run(). This also allows the - // thread to join when it is stopped by EventFactory. - return Status::success(); - } - std::string line; - std::getline(readStream_, line); - auto ec = createEventContext(); - Status status = populateEventContext(line, ec); - if (status.ok()) { - fire(ec); - if (errorCount_ > 0) { - --errorCount_; - } - } else { - LOG(ERROR) << status.getMessage() << " in line: " << line; - ++errorCount_; - if (errorCount_ >= kErrorThreshold) { - return Status(1, "Too many errors in syslog parsing."); - } - } - } - return Status::success(); -} - -void SyslogEventPublisher::tearDown() { - unlockPipe(); -} - -Status SyslogEventPublisher::populateEventContext(const std::string& line, - SyslogEventContextRef& ec) { - boost::tokenizer tokenizer(line); - auto key = kCsvFields.begin(); - for (std::string value : tokenizer) { - if (key == kCsvFields.end()) { - return Status(1, "Received more fields than expected"); - } - - boost::trim(value); - if (*key == "time") { - ec->fields["datetime"] = value; - } else if (*key == "tag" && !value.empty() && value.back() == ':') { - // rsyslog sends "tag" with a trailing colon that we don't need - ec->fields.emplace(*key, value.substr(0, value.size() - 1)); - } else { - ec->fields.emplace(*key, value); - } - ++key; - } - - if (key == kCsvFields.end()) { - return Status::success(); - } else { - return Status(1, "Received fewer fields than expected"); - } -} - -bool SyslogEventPublisher::shouldFire(const SyslogSubscriptionContextRef& sc, - const SyslogEventContextRef& ec) const { - return true; -} -} diff --git a/src/osquery/events/linux/syslog.h b/src/osquery/events/linux/syslog.h deleted file mode 100644 index 3d4cb37..0000000 --- a/src/osquery/events/linux/syslog.h +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include - -#include - -namespace osquery { - -/** - * @brief Subscription context for syslog events - * - * Currently there is no use for the subscription context, so this class - * remains empty. - */ - -struct SyslogSubscriptionContext : public SubscriptionContext { - private: - friend class SyslogEventPublisher; -}; - -/** - * @brief Event details for SyslogEventPublisher events - */ -struct SyslogEventContext : public EventContext { - /** - * @brief The syslog message tokenized into fields. - * - * Fields will be stripped of extra space - */ - std::map fields; -}; - -using SyslogEventContextRef = std::shared_ptr; -using SyslogSubscriptionContextRef = std::shared_ptr; - -/** - * @brief Event publisher for syslog lines forwarded through rsyslog - * - * This event publisher ingests JSON representations of syslog entries, and - * publishes them to it's subscribers. In order for it to function properly, - * rsyslog must be configured to forward JSON to a named pipe that this - * publisher will read from. - */ -class SyslogEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("syslog"); - - public: - Status setUp() override; - - void configure() override {} - - void tearDown() override; - - Status run() override; - - public: - SyslogEventPublisher() : EventPublisher(), errorCount_(0), lockFd_(-1) {} - - private: - /// Apply normal subscription to event matching logic. - bool shouldFire(const SyslogSubscriptionContextRef& mc, - const SyslogEventContextRef& ec) const override; - - /** - * @brief Create the named pipe for log forwarding. - * - * Attempts to properly set the permissions so that rsyslog will be able to - * write logs to the pipe. If osquery is not running with the appropriate - * permissions, the named pipe permissions may have to be manually edited by - * the user in order for rsyslog to be able to write to it. - */ - Status createPipe(const std::string& path); - - /** - * @brief Attempt to lock the pipe for reading. - * - * We lock the pipe to ensure that (for example) a user opening osqueryi - * while osqueryd is running will not try to simultaneously read from the - * pipe and invalidate the reads from osqueryd. Only the first osquery - * process to successfully lock the pipe will be allowed to read. - * - * @param path Path to the file to lock. - * @return 0 if successful, nonzero if unable to lock the file. - */ - Status lockPipe(const std::string& path); - - /** - * @brief Attempt to unlock the pipe. - */ - void unlockPipe(); - - /** - * @brief Populate the SyslogEventContext with the syslog JSON. - * - * Performs basic cleanup on the JSON data as it is populated into the - * context. - */ - static Status populateEventContext(const std::string& line, - SyslogEventContextRef& ec); - - /** - * @brief Input stream for reading from the pipe. - */ - std::fstream readStream_; - - /** - * @brief Counter used to shut down thread when too many errors occur. - * - * This counter is incremented when an error occurs, and decremented when a - * log line is processed successfully. If it goes over kErrorThreshold, the - * thread will return a nonzero status and stop, preventing us from flooding - * the logs when things are in a bad state. - */ - size_t errorCount_; - - /** - * @brief File descriptor used to lock the pipe for reading. - * - * This fd should not be used for reading from the pipe, instead use - * readStream_. - */ - int lockFd_; - - private: - FRIEND_TEST(SyslogTests, test_populate_event_context); -}; - -/** - * Boost TokenizerFunction functor for tokenizing rsyslog CSV data - * - * This functor is intended to be used with boost::tokenizer in order to - * properly parse CSV data generated by rsyslog. The default - * boost::escaped_list_separator provided with boost::tokenizer chokes on - * rsyslog CSV output, because rsyslog escapes " with "", and also does not - * escape backslashes. Our implementation closely follows the one provided with - * Boost, but allows for the idiosyncrasies of rsyslog output and simplifies - * the implementation for our limited use case. - */ -class RsyslogCsvSeparator { - public: - RsyslogCsvSeparator() : last_(false) {} - - void reset() { - last_ = false; - } - - template - bool operator()(InputIterator& next, InputIterator end, Token& tok) { - bool in_quote = false; - tok = Token(); - - if (next == end) { - if (last_) { - // The last character was a comma, so we got an empty field at the end - last_ = false; - return true; - } else { - return false; - } - } - last_ = false; - for (; next != end; ++next) { - if (*next == ',') { - if (!in_quote) { - ++next; - last_ = true; - return true; - } else { - tok += *next; - } - } else if (*next == '"') { - auto after = next + 1; - if (!in_quote) { - in_quote = true; - } else if (after != end && *after == '"') { - // rsyslog escapes " with "", so reverse this by inserting " - tok += "\""; - ++next; - } else { - in_quote = false; - } - } else { - tok += *next; - } - } - return true; - } - - private: - bool last_; -}; -} diff --git a/src/osquery/events/linux/udev.cpp b/src/osquery/events/linux/udev.cpp deleted file mode 100644 index 3736283..0000000 --- a/src/osquery/events/linux/udev.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include -#include -#include - -#include "osquery/events/linux/udev.h" - -namespace osquery { - -static const int kUdevMLatency = 200; - -REGISTER(UdevEventPublisher, "event_publisher", "udev"); - -Status UdevEventPublisher::setUp() { - // The Setup and Teardown workflows should be protected against races. - // Just in case let's protect the publisher's resources. - WriteLock lock(mutex_); - - // Create the udev object. - handle_ = udev_new(); - if (handle_ == nullptr) { - return Status(1, "Could not create udev object."); - } - - // Set up the udev monitor before scanning/polling. - monitor_ = udev_monitor_new_from_netlink(handle_, "udev"); - if (monitor_ == nullptr) { - udev_unref(handle_); - handle_ = nullptr; - return Status(1, "Could not create udev monitor."); - } - - udev_monitor_enable_receiving(monitor_); - return Status::success(); -} - -void UdevEventPublisher::tearDown() { - WriteLock lock(mutex_); - if (monitor_ != nullptr) { - udev_monitor_unref(monitor_); - monitor_ = nullptr; - } - - if (handle_ != nullptr) { - udev_unref(handle_); - handle_ = nullptr; - } -} - -Status UdevEventPublisher::run() { - { - WriteLock lock(mutex_); - if (monitor_ == nullptr) { - return Status(1); - } - int fd = udev_monitor_get_fd(monitor_); - if (fd < 0) { - LOG(ERROR) << "Could not get udev monitor fd"; - return Status::failure("udev monitor failed"); - } - - struct pollfd fds[1]; - fds[0].fd = fd; - fds[0].events = POLLIN; - - int selector = ::poll(fds, 1, 1000); - if (selector == -1 && errno != EINTR && errno != EAGAIN) { - LOG(ERROR) << "Could not read udev monitor"; - return Status(1, "udev monitor failed."); - } - - if (selector == 0 || !(fds[0].revents & POLLIN)) { - // Read timeout. - return Status::success(); - } - - struct udev_device* device = udev_monitor_receive_device(monitor_); - if (device == nullptr) { - LOG(ERROR) << "udev monitor returned invalid device"; - return Status(1, "udev monitor failed."); - } - - auto ec = createEventContextFrom(device); - fire(ec); - - udev_device_unref(device); - } - - pause(std::chrono::milliseconds(kUdevMLatency)); - return Status::success(); -} - -std::string UdevEventPublisher::getValue(struct udev_device* device, - const std::string& property) { - auto value = udev_device_get_property_value(device, property.c_str()); - if (value != nullptr) { - return std::string(value); - } - return ""; -} - -std::string UdevEventPublisher::getAttr(struct udev_device* device, - const std::string& attr) { - auto value = udev_device_get_sysattr_value(device, attr.c_str()); - if (value != nullptr) { - return std::string(value); - } - return ""; -} - -UdevEventContextRef UdevEventPublisher::createEventContextFrom( - struct udev_device* device) { - auto ec = createEventContext(); - ec->device = device; - // Map the action string to the eventing enum. - ec->action = UDEV_EVENT_ACTION_UNKNOWN; - ec->action_string = std::string(udev_device_get_action(device)); - if (ec->action_string == "add") { - ec->action = UDEV_EVENT_ACTION_ADD; - } else if (ec->action_string == "remove") { - ec->action = UDEV_EVENT_ACTION_REMOVE; - } else if (ec->action_string == "change") { - ec->action = UDEV_EVENT_ACTION_CHANGE; - } - - // Set the subscription-aware variables for the event. - auto value = udev_device_get_subsystem(device); - if (value != nullptr) { - ec->subsystem = std::string(value); - } - - value = udev_device_get_devnode(device); - if (value != nullptr) { - ec->devnode = std::string(value); - } - - value = udev_device_get_devtype(device); - if (value != nullptr) { - ec->devtype = std::string(value); - } - - value = udev_device_get_driver(device); - if (value != nullptr) { - ec->driver = std::string(value); - } - - return ec; -} - -bool UdevEventPublisher::shouldFire(const UdevSubscriptionContextRef& sc, - const UdevEventContextRef& ec) const { - if (sc->action != UDEV_EVENT_ACTION_ALL) { - if (sc->action != ec->action) { - return false; - } - } - - if (sc->subsystem.length() != 0 && sc->subsystem != ec->subsystem) { - return false; - } else if (sc->devnode.length() != 0 && sc->devnode != ec->devnode) { - return false; - } else if (sc->devtype.length() != 0 && sc->devtype != ec->devtype) { - return false; - } else if (sc->driver.length() != 0 && sc->driver != ec->driver) { - return false; - } - - return true; -} -} // namespace osquery diff --git a/src/osquery/events/linux/udev.h b/src/osquery/events/linux/udev.h deleted file mode 100644 index 0fa295b..0000000 --- a/src/osquery/events/linux/udev.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include - -namespace osquery { - -enum udev_event_action { - UDEV_EVENT_ACTION_ADD = 1, - UDEV_EVENT_ACTION_REMOVE = 2, - UDEV_EVENT_ACTION_CHANGE = 3, - UDEV_EVENT_ACTION_UNKNOWN = 4, - - // Custom subscriber-only catch-all for actions. - UDEV_EVENT_ACTION_ALL = 10, -}; - -/** - * @brief Subscriptioning details for UdevEventPublisher events. - * - */ -struct UdevSubscriptionContext : public SubscriptionContext { - /// The hardware event action, add/remove/change. - udev_event_action action; - - /// Restrict to a specific subsystem. - std::string subsystem; - - /// Restrict to a specific devnode. - std::string devnode; - - /// Restrict to a specific devtype. - std::string devtype; - - /// Limit to a specific driver name. - std::string driver; -}; - -/** - * @brief Event details for UdevEventPublisher events. - */ -struct UdevEventContext : public EventContext { - /// A pointer to the device object, most subscribers will only use device. - struct udev_device* device{nullptr}; - - /// The udev_event_action identifier. - udev_event_action action; - - /// Action as a string (as given by udev). - std::string action_string; - - std::string subsystem; - std::string devnode; - std::string devtype; - std::string driver; -}; - -using UdevEventContextRef = std::shared_ptr; -using UdevSubscriptionContextRef = std::shared_ptr; - -/** - * @brief A Linux `udev` EventPublisher. - * - */ -class UdevEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("udev"); - - public: - virtual ~UdevEventPublisher() { - tearDown(); - } - - Status setUp() override; - - void tearDown() override; - - Status run() override; - - /** - * @brief Return a string representation of a udev property. - * - * @param device the udev device pointer. - * @param property the udev property identifier string. - * @return string representation of the property or empty if null. - */ - static std::string getValue(struct udev_device* device, - const std::string& property); - - /** - * @brief Return a string representation of a udev system attribute. - * - * @param device the udev device pointer. - * @param property the udev system attribute identifier string. - * @return string representation of the attribute or empty if null. - */ - static std::string getAttr(struct udev_device* device, - const std::string& attr); - - private: - /// udev handle (socket descriptor contained within). - struct udev* handle_{nullptr}; - - /// udev monitor. - struct udev_monitor* monitor_{nullptr}; - - /// Protection around udev resources. - Mutex mutex_; - - private: - /// Check subscription details. - bool shouldFire(const UdevSubscriptionContextRef& mc, - const UdevEventContextRef& ec) const override; - - /// Helper function to create an EventContext using a udev_device pointer. - UdevEventContextRef createEventContextFrom(struct udev_device* device); -}; -} diff --git a/src/osquery/events/pathset.h b/src/osquery/events/pathset.h deleted file mode 100644 index 538360c..0000000 --- a/src/osquery/events/pathset.h +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace osquery { - -/** - * @brief multiset based implementation for path search. - * - * 'multiset' is used because with patterns we can serach for equivalent keys. - * Since '/This/Path/is' ~= '/This/Path/%' ~= '/This/Path/%%' (equivalent). - * - * multiset is protected by lock. It is threadsafe. - * - * PathSet can take any of the two policies - - * 1. patternedPath - Path can contain pattern '%' and '%%'. - * Path components containing only '%' and '%%' are supported - * e.g. '/This/Path/%'. - * Path components containing partial patterns are not - * supported e.g. '/This/Path/xyz%' ('xyz%' will not be - * treated as pattern). - */ -template -class PathSet : private boost::noncopyable { - public: - void insert(const std::string& str) { - auto pattern = str; - replaceGlobWildcards(pattern); - auto vpath = PathType::createVPath(pattern); - - WriteLock lock(mset_lock_); - for (auto& path : vpath) { - paths_.insert(std::move(path)); - } - } - - bool find(const std::string& str) const { - auto path = PathType::createPath(str); - - ReadLock lock(mset_lock_); - if (paths_.find(path) != paths_.end()) { - return true; - } - return false; - } - - void clear() { - WriteLock lock(mset_lock_); - paths_.clear(); - } - - bool empty() const { - ReadLock lock(mset_lock_); - return paths_.empty(); - } - - private: - typedef typename PathType::Path Path; - typedef typename PathType::Compare Compare; - std::multiset paths_; - mutable Mutex mset_lock_; -}; - -class patternedPath { - public: - typedef boost::tokenizer> tokenizer; - typedef std::vector Path; - typedef std::vector VPath; - struct Compare { - bool operator()(const Path& lhs, const Path& rhs) const { - size_t psize = (lhs.size() < rhs.size()) ? lhs.size() : rhs.size(); - unsigned ndx; - for (ndx = 0; ndx < psize; ++ndx) { - if (lhs[ndx] == "**" || rhs[ndx] == "**") { - return false; - } - - if (lhs[ndx] == "*" || rhs[ndx] == "*") { - continue; - } - - int rc = lhs[ndx].compare(rhs[ndx]); - - if (rc > 0) { - return false; - } - - if (rc < 0) { - return true; - } - } - - if ((ndx == rhs.size() && rhs[ndx - 1] == "*") || - (ndx == lhs.size() && lhs[ndx - 1] == "*")) { - return false; - } - - return (lhs.size() < rhs.size()); - } - }; - - static Path createPath(const std::string& str) { - boost::char_separator sep{"/"}; - tokenizer tokens(str, sep); - Path path; - - if (str == "/") { - path.push_back(""); - } - - for (std::string component : tokens) { - path.push_back(std::move(component)); - } - return path; - } - - static VPath createVPath(const std::string& str) { - boost::char_separator sep{"/"}; - tokenizer tokens(str, sep); - VPath vpath; - Path path; - - if (str == "/") { - path.push_back(""); - } - - for (std::string component : tokens) { - if (component == "**") { - vpath.push_back(path); - path.push_back(std::move(component)); - break; - } - path.push_back(std::move(component)); - } - vpath.push_back(std::move(path)); - return vpath; - } -}; - -} // namespace osquery diff --git a/src/osquery/events/tests/events_database_tests.cpp b/src/osquery/events/tests/events_database_tests.cpp deleted file mode 100644 index a66d67c..0000000 --- a/src/osquery/events/tests/events_database_tests.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace osquery { -DECLARE_bool(disable_database); - -static TableRows genRows(EventSubscriberPlugin* sub) { - auto vtc = std::make_shared(); - QueryContext context(vtc); - TableRows results; - return results; -} - -DECLARE_uint64(events_expiry); -DECLARE_uint64(events_max); -DECLARE_bool(events_optimize); - -class EventsDatabaseTests : public ::testing::Test { - void SetUp() override { - registryAndPluginInit(); - - FLAGS_disable_database = true; - DatabasePlugin::setAllowOpen(true); - DatabasePlugin::initPlugin(); - - std::vector event_keys; - scanDatabaseKeys(kEvents, event_keys); - for (const auto& key : event_keys) { - deleteDatabaseValue(kEvents, key); - } - } - - void TearDown() override { - FLAGS_events_optimize = optimize_; - } - - private: - bool optimize_; -}; - -class DBFakeEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("DBFakePublisher"); -}; - -class DBFakeEventSubscriber : public EventSubscriber { - public: - DBFakeEventSubscriber() { - setName("DBFakeSubscriber"); - setEventsMax(FLAGS_events_max); - setEventsExpiry(FLAGS_events_expiry); - } - - /// Add num_of_events fake events at time t - Status testAdd(time_t t, size_t num_of_events = 1) { - auto indexes = getIndexes(0, t); - auto records = getRecords(indexes); - const size_t old_records_size = records.size(); - - Row r; - r["testing"] = "hello from space"; - r["time"] = INTEGER(t); - r["uptime"] = INTEGER(10); - - std::vector row_list; - for (size_t i = 0U; i < num_of_events; i++) { - row_list.push_back(r); - } - - auto status = addBatch(row_list, t); - if (!status.ok()) { - return Status::failure( - "Failed to save the batch to the database, with error: " + - status.getMessage()); - } - - indexes = getIndexes(0, t); - records = getRecords(indexes); - - if (records.size() != row_list.size() + old_records_size) { - return Status::failure("We expected " + std::to_string(row_list.size()) + - " records but only " + - std::to_string(records.size()) + " were found!"); - } - - return Status::success(); - } - - size_t getEventsMax() override { - return max_; - } - - void setEventsMax(size_t max) { - max_ = max; - } - - size_t getEventsExpiry() override { - return expiry_; - } - - void setEventsExpiry(size_t expiry) { - expiry_ = expiry; - } - - private: - size_t max_; - - size_t expiry_; -}; - -TEST_F(EventsDatabaseTests, test_event_module_id) { - auto sub = std::make_shared(); - sub->doNotExpire(); - - // Not normally available outside of EventSubscriber->Add(). - auto event_id1 = sub->getEventID(); - EXPECT_EQ(event_id1, "0000000001"); - auto event_id2 = sub->getEventID(); - EXPECT_EQ(event_id2, "0000000002"); -} - -TEST_F(EventsDatabaseTests, test_event_add) { - auto sub = std::make_shared(); - auto status = sub->testAdd(1); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsDatabaseTests, test_event_add_batch) { - auto sub = std::make_shared(); - auto status = sub->testAdd(1, 10); - EXPECT_TRUE(status.ok()) << status.getMessage(); -} - -TEST_F(EventsDatabaseTests, test_record_indexing) { - auto sub = std::make_shared(); - auto status = sub->testAdd(2); - status = sub->testAdd(11); - status = sub->testAdd(61); - status = sub->testAdd((1 * 3600) + 1); - status = sub->testAdd((2 * 3600) + 1); - - // An "all" range, will pick up everything in the largest index. - auto indexes = sub->getIndexes(0, 3 * 3600); - auto output = boost::algorithm::join(indexes, ", "); - EXPECT_EQ("60.0, 60.1, 60.60, 60.120", output); - - // Restrict range to "most specific", which is an index by 10. - indexes = sub->getIndexes(0, 5); - output = boost::algorithm::join(indexes, ", "); - // The order 10, 0th index include results with t = [0, 10). - EXPECT_EQ("60.0", output); - - // Add specific indexes to the upper bound. - status = sub->testAdd((2 * 3600) + 11); - status = sub->testAdd((2 * 3600) + 61); - indexes = sub->getIndexes(2 * 3600, (2 * 3600) + 62); - output = boost::algorithm::join(indexes, ", "); - EXPECT_EQ("60.120, 60.121", output); - - // Request specific lower and upper bounding. - indexes = sub->getIndexes(2, (2 * 3600) + 62); - output = boost::algorithm::join(indexes, ", "); - EXPECT_EQ("60.0, 60.1, 60.60, 60.120, 60.121", output); -} - -TEST_F(EventsDatabaseTests, test_record_range) { - auto sub = std::make_shared(); - auto status = sub->testAdd(1); - status = sub->testAdd(2); - status = sub->testAdd(11); - status = sub->testAdd(61); - status = sub->testAdd((1 * 3600) + 1); - status = sub->testAdd((2 * 3600) + 1); - - // Search within a specific record range. - auto indexes = sub->getIndexes(0, 10); - EXPECT_EQ(1U, indexes.size()); - auto records = sub->getRecords(indexes); - // This will return 3 results, ::get filters records by an absolute range. - EXPECT_EQ(3U, records.size()); // 1, 2, 11 - - // Search within a large bound. - indexes = sub->getIndexes(3, 3601); - // This will include the 0-10 bucket meaning 1, 2 will show up. - records = sub->getRecords(indexes); - EXPECT_EQ(5U, records.size()); // 1, 2, 11, 61, 3601 - - // Get all of the records. - indexes = sub->getIndexes(0, 3 * 3600); - records = sub->getRecords(indexes); - EXPECT_EQ(6U, records.size()); // 1, 2, 11, 61, 3601, 7201 - - // stop = 0 is an alias for everything. - indexes = sub->getIndexes(0, 0); - records = sub->getRecords(indexes); - EXPECT_EQ(6U, records.size()); - - for (size_t j = 0; j < 30; j++) { - // 110 is 10 below an index (60.2). - sub->testAdd(110 + static_cast(j)); - } - - indexes = sub->getIndexes(110, 0); - auto output = boost::algorithm::join(indexes, ", "); - EXPECT_EQ("60.1, 60.2, 60.60, 60.120", output); - records = sub->getRecords(indexes); - EXPECT_EQ(33U, records.size()); // (61) 110 - 139 + 3601, 7201 -} - -TEST_F(EventsDatabaseTests, test_record_corruption) { - auto sub = std::make_shared(); - - std::string corrupted_index = "60.25440186"; - std::string key = - "records.DBFakePublisher.DBFakeSubscriber." + corrupted_index; - std::string value = - "0002985852:1526411162,0002985853:1526411162,00??E/" - "?:1526411170,0002985912:1526411170,0002??E/" - "?526411178,0002985921:1526411178,0002985922:1526411178"; - - // Set some corrupted values in the DB - auto s = setDatabaseValue(kEvents, key, value); - auto records = sub->getRecords({corrupted_index}); - - // We should gracefully skip over corrupted record entries - EXPECT_EQ(6U, records.size()); -} - -TEST_F(EventsDatabaseTests, test_record_expiration) { - auto sub = std::make_shared(); - auto status = sub->testAdd(1); - status = sub->testAdd(2); - status = sub->testAdd(11); - status = sub->testAdd(61); - status = sub->testAdd((1 * 3600) + 1); - status = sub->testAdd((2 * 3600) + 1); - - // No expiration - auto indexes = sub->getIndexes(0, 5000); - auto records = sub->getRecords(indexes); - EXPECT_EQ(5U, records.size()); // 1, 2, 11, 61, 3601 - - sub->expire_events_ = true; - sub->expire_time_ = 10; - indexes = sub->getIndexes(0, 5000); - records = sub->getRecords(indexes); - EXPECT_EQ(3U, records.size()); // 11, 61, 3601 - - indexes = sub->getIndexes(0, 5000); - records = sub->getRecords(indexes); - EXPECT_EQ(3U, records.size()); // 11, 61, 3601 - - indexes = sub->getIndexes(0, 5000); - records = sub->getRecords(indexes); - EXPECT_EQ(3U, records.size()); // 11, 61, 3601 - - indexes = sub->getIndexes(0, 5000); - records = sub->getRecords(indexes); - EXPECT_EQ(3U, records.size()); // 11, 61, 3601 - - // Check that get/deletes did not act on cache. - // This implies that RocksDB is flushing the requested delete records. - sub->expire_time_ = 0; - indexes = sub->getIndexes(0, 5000); - records = sub->getRecords(indexes); - EXPECT_EQ(3U, records.size()); // 11, 61, 3601 -} - -TEST_F(EventsDatabaseTests, test_gentable) { - auto sub = std::make_shared(); - auto status = sub->testAdd(1); - status = sub->testAdd(2); - status = sub->testAdd(11); - status = sub->testAdd(61); - status = sub->testAdd((1 * 3600) + 1); - status = sub->testAdd((2 * 3600) + 1); - - ASSERT_EQ(0U, sub->optimize_time_); - ASSERT_EQ(0U, sub->expire_time_); - ASSERT_EQ(0U, sub->min_expiration_); - - auto t = getUnixTime(); - sub->testAdd(t - 1); - sub->testAdd(t); - sub->testAdd(t + 1); - - // Test the expire workflow by creating a short expiration time. - sub->setEventsExpiry(10); - - std::vector keys; - scanDatabaseKeys("events", keys); - // 9 data records, 1 eid counter, 3 indexes, 15 index records. - // Depending on the moment, an additional 3 indexes may be introduced. - EXPECT_LE(16U, keys.size()); - - // Perform a "select" equivalent. - auto results = genRows(sub.get()); - - // Expect all non-expired results: 11, + - EXPECT_EQ(9U, results.size()); - // The expiration time is now - events_expiry +/ 60. - EXPECT_LT(t - (sub->getEventsExpiry() * 2), sub->expire_time_ + 60); - EXPECT_GT(t, sub->expire_time_); - // The optimize time will not be changed. - ASSERT_EQ(0U, sub->optimize_time_); - - results = genRows(sub.get()); - EXPECT_EQ(3U, results.size()); - - results = genRows(sub.get()); - EXPECT_EQ(3U, results.size()); - - keys.clear(); - scanDatabaseKeys("events", keys); - EXPECT_LE(6U, keys.size()); -} - -TEST_F(EventsDatabaseTests, test_optimize) { - auto sub = std::make_shared(); - for (size_t i = 800; i < 800 + 10; ++i) { - sub->testAdd(i); - } - - // Lie about the tool type to enable optimizations. - auto default_type = kToolType; - kToolType = ToolType::DAEMON; - FLAGS_events_optimize = true; - - // Must also define an executing query. - setDatabaseValue(kPersistentSettings, "", "events_db_test"); - - auto t = getUnixTime(); - auto results = genRows(sub.get()); - EXPECT_EQ(10U, results.size()); - // Optimization will set the time NOW as the minimum event time. - // Thus it is not possible to set event in past. - EXPECT_GE(sub->optimize_time_ + 100, t); - EXPECT_LE(sub->optimize_time_ - 100, t); - // The last EID returned will also be stored for duplication checks. - EXPECT_EQ(10U, sub->optimize_eid_); - - for (size_t i = t + 800; i < t + 800 + 10; ++i) { - sub->testAdd(i); - } - - results = genRows(sub.get()); - EXPECT_EQ(10U, results.size()); - - // The optimize time should have been written to the database. - // It should be the same as the current (relative) optimize time. - std::string content; - getDatabaseValue("events", "optimize.events_db_test", content); - EXPECT_EQ(std::to_string(sub->optimize_time_), content); - - // Restore the tool type. - kToolType = default_type; -} - -TEST_F(EventsDatabaseTests, test_expire_check) { - auto sub = std::make_shared(); - // Set the max number of buffered events to something reasonably small. - sub->setEventsMax(50); - size_t t = 10000; - - // We are still at the mercy of the opaque EVENTS_CHECKPOINT define. - for (size_t x = 0; x < 3; x++) { - size_t num_events = 256 * x; - for (size_t i = 0; i < num_events; i++) { - sub->testAdd(t++); - } - - // Since events tests are dependent, expect 257 + 3 events. - auto results = genRows(sub.get()); - if (x == 0) { - // The first iteration is dependent on previous test state. - continue; - } - - // The number of events should remain constant. - // In practice there may be an event still in the write queue. - EXPECT_LT(results.size(), 60U); - } - - // Try again, this time with a scan - for (size_t k = 0; k < 3; k++) { - for (size_t x = 0; x < 3; x++) { - size_t num_events = 256 * x; - for (size_t i = 0; i < num_events; i++) { - sub->testAdd(t++); - } - - // Records hold the event_id + time indexes. - // Data hosts the event_id + JSON content. - auto record_key = "records." + sub->dbNamespace(); - auto data_key = "data." + sub->dbNamespace(); - - std::vector records, datas; - scanDatabaseKeys(kEvents, records, record_key); - scanDatabaseKeys(kEvents, datas, data_key); - - EXPECT_LT(records.size(), 20U); - EXPECT_LT(datas.size(), 60U); - } - } -} -} // namespace osquery diff --git a/src/osquery/events/tests/events_tests.cpp b/src/osquery/events/tests/events_tests.cpp deleted file mode 100644 index 5341a15..0000000 --- a/src/osquery/events/tests/events_tests.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace osquery { -DECLARE_bool(disable_database); - -class EventsTests : public ::testing::Test { - protected: - void SetUp() override { - kToolType = ToolType::TEST; - registryAndPluginInit(); - - // Force registry to use ephemeral database plugin - FLAGS_disable_database = true; - DatabasePlugin::setAllowOpen(true); - DatabasePlugin::initPlugin(); - - RegistryFactory::get().registry("config_parser")->setUp(); - } - void TearDown() override { - EventFactory::end(true); - } -}; - -// The most basic event publisher uses useless Subscription/Event. -class BasicEventPublisher - : public EventPublisher {}; - -class AnotherBasicEventPublisher - : public EventPublisher {}; - -// Create some semi-useless subscription and event structures. -struct FakeSubscriptionContext : SubscriptionContext { - int require_this_value; -}; - -struct FakeEventContext : EventContext { - int required_value; -}; - -// Typedef the shared_ptr accessors. -using FakeSubscriptionContextRef = std::shared_ptr; -using FakeEventContextRef = std::shared_ptr; - -// Now a publisher with a type. -class FakeEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("FakePublisher"); -}; - -class AnotherFakeEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("AnotherFakePublisher"); -}; - -TEST_F(EventsTests, test_event_publisher) { - auto pub = std::make_shared(); - EXPECT_EQ(pub->type(), "FakePublisher"); - - // Test type names. - auto pub_sub = pub->createSubscriptionContext(); - EXPECT_EQ(typeid(FakeSubscriptionContext), typeid(*pub_sub)); -} - -TEST_F(EventsTests, test_register_event_publisher) { - auto basic_pub = std::make_shared(); - auto status = EventFactory::registerEventPublisher(basic_pub); - EXPECT_FALSE(status.ok()); - - // Set a name for the publisher, which becomes the type by default. - basic_pub->setName("BasicPublisher"); - status = EventFactory::registerEventPublisher(basic_pub); - EXPECT_TRUE(status.ok()); - - // This class is the SAME, there was no type override. - auto another_basic_pub = std::make_shared(); - another_basic_pub->setName(basic_pub->getName()); - status = EventFactory::registerEventPublisher(another_basic_pub); - EXPECT_FALSE(status.ok()); - - // This class is different but also uses different types! - auto fake_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(fake_pub); - EXPECT_TRUE(status.ok()); - - // May also register a similar (same EC, SC), but different publisher. - auto another_fake_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(another_fake_pub); - EXPECT_TRUE(status.ok()); - - status = EventFactory::deregisterEventPublisher(basic_pub->type()); - EXPECT_TRUE(status.ok()); - status = EventFactory::deregisterEventPublisher(fake_pub->type()); - EXPECT_TRUE(status.ok()); - status = EventFactory::deregisterEventPublisher(another_fake_pub->type()); - EXPECT_TRUE(status.ok()); - - // Attempting to deregister a publisher a second time. - status = EventFactory::deregisterEventPublisher(another_fake_pub->type()); - EXPECT_FALSE(status.ok()); - - // Attempting to deregister a publish that failed registering. - status = EventFactory::deregisterEventPublisher(another_basic_pub->type()); - EXPECT_FALSE(status.ok()); -} - -TEST_F(EventsTests, test_event_publisher_types) { - auto pub = std::make_shared(); - EXPECT_EQ(pub->type(), "FakePublisher"); - - EventFactory::registerEventPublisher(pub); - auto pub2 = EventFactory::getEventPublisher("FakePublisher"); - EXPECT_EQ(pub->type(), pub2->type()); - - // It is possible to deregister by base event publisher type. - auto status = EventFactory::deregisterEventPublisher(pub2); - EXPECT_TRUE(status.ok()); - // And attempting to deregister by type afterward will fail. - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_FALSE(status.ok()); -} - -TEST_F(EventsTests, test_duplicate_event_publisher) { - auto pub = std::make_shared(); - pub->setName("BasicPublisher"); - auto status = EventFactory::registerEventPublisher(pub); - EXPECT_TRUE(status.ok()); - - // Make sure only the first event type was recorded. - EXPECT_EQ(EventFactory::numEventPublishers(), 1U); -} - -class UniqueEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("unique"); -}; - -TEST_F(EventsTests, test_create_using_registry) { - // The events API uses attachEvents to move registry event publishers and - // subscribers into the events factory. - EXPECT_EQ(EventFactory::numEventPublishers(), 0U); - attachEvents(); - - // Store the number of default event publishers (in core). - size_t default_publisher_count = EventFactory::numEventPublishers(); - - auto& rf = RegistryFactory::get(); - // Now add another registry item, but do not yet attach it. - rf.registry("event_publisher") - ->add("unique", std::make_shared()); - EXPECT_EQ(EventFactory::numEventPublishers(), default_publisher_count); - - // Now attach and make sure it was added. - attachEvents(); - EXPECT_EQ(EventFactory::numEventPublishers(), default_publisher_count + 1U); - - auto status = EventFactory::deregisterEventPublisher("unique"); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_create_subscription) { - std::string basic_publisher_type = "BasicPublisher"; - - auto pub = std::make_shared(); - pub->setName(basic_publisher_type); - EventFactory::registerEventPublisher(pub); - - // Make sure a subscription cannot be added for a non-existent event type. - // Note: It normally would not make sense to create a blank subscription. - auto subscription = Subscription::create("FakeSubscriber"); - auto status = EventFactory::addSubscription("FakePublisher", subscription); - EXPECT_FALSE(status.ok()); - - // In this case we can still add a blank subscription to an existing event - // type. - status = EventFactory::addSubscription(basic_publisher_type, subscription); - EXPECT_TRUE(status.ok()); - - // Make sure the subscription is added. - EXPECT_EQ(EventFactory::numSubscriptions(basic_publisher_type), 1U); - - status = EventFactory::deregisterEventPublisher(basic_publisher_type); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_multiple_subscriptions) { - std::string basic_publisher_type = "BasicPublisher"; - - auto pub = std::make_shared(); - pub->setName(basic_publisher_type); - EventFactory::registerEventPublisher(pub); - - auto subscription = Subscription::create("subscriber"); - auto status = - EventFactory::addSubscription(basic_publisher_type, subscription); - status = EventFactory::addSubscription(basic_publisher_type, subscription); - EXPECT_TRUE(status.ok()); - - EXPECT_EQ(EventFactory::numSubscriptions(basic_publisher_type), 2U); - - status = EventFactory::deregisterEventPublisher(basic_publisher_type); - EXPECT_TRUE(status.ok()); -} - -struct TestSubscriptionContext : public SubscriptionContext { - int smallest; -}; - -class TestEventPublisher - : public EventPublisher { - DECLARE_PUBLISHER("TestPublisher"); - - public: - Status setUp() override { - smallest_ever_ += 1; - return Status::success(); - } - - void configure() override { - int smallest_subscription = smallest_ever_; - - configure_run = true; - for (const auto& subscription : subscriptions_) { - auto subscription_context = getSubscriptionContext(subscription->context); - if (smallest_subscription > subscription_context->smallest) { - smallest_subscription = subscription_context->smallest; - } - } - - smallest_ever_ = smallest_subscription; - } - - void tearDown() override { - smallest_ever_ += 1; - } - - // Custom methods do not make sense, but for testing it exists. - int getTestValue() { - return smallest_ever_; - } - - public: - bool configure_run{false}; - - private: - int smallest_ever_{0}; -}; - -TEST_F(EventsTests, test_create_custom_event_publisher) { - auto basic_pub = std::make_shared(); - basic_pub->setName("BasicPublisher"); - EventFactory::registerEventPublisher(basic_pub); - - auto pub = std::make_shared(); - auto status = EventFactory::registerEventPublisher(pub); - ASSERT_TRUE(status.ok()); - - // These event types have unique event type IDs - EXPECT_EQ(EventFactory::numEventPublishers(), 2U); - - // Make sure the setUp function was called. - EXPECT_EQ(pub->getTestValue(), 1); - - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); - status = EventFactory::deregisterEventPublisher(basic_pub->type()); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_custom_subscription) { - // Step 1, register event type - auto pub = std::make_shared(); - auto status = EventFactory::registerEventPublisher(pub); - ASSERT_TRUE(status.ok()); - - // Step 2, create and configure a subscription context - auto sc = std::make_shared(); - sc->smallest = -1; - - // Step 3, add the subscription to the event type - status = EventFactory::addSubscription("TestPublisher", "TestSubscriber", sc); - EXPECT_TRUE(status.ok()); - EXPECT_EQ(pub->numSubscriptions(), 1U); - // Run configure on this publisher. - pub->configure(); - - // The event type must run configure for each added subscription. - EXPECT_TRUE(pub->configure_run); - EXPECT_EQ(pub->getTestValue(), -1); - - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_tear_down) { - auto pub = std::make_shared(); - auto status = EventFactory::registerEventPublisher(pub); - ASSERT_TRUE(status.ok()); - - // Make sure set up incremented the test value. - EXPECT_EQ(pub->getTestValue(), 1); - - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); - - // Make sure tear down incremented the test value. - EXPECT_EQ(pub->getTestValue(), 2); - - // Once more, now deregistering all event types. - status = EventFactory::registerEventPublisher(pub); - EXPECT_TRUE(status.ok()); - - EXPECT_EQ(pub->getTestValue(), 3); - EventFactory::end(); - EXPECT_EQ(pub->getTestValue(), 4); - - // Make sure the factory state represented. - EXPECT_EQ(EventFactory::numEventPublishers(), 0U); - - // Implicit deregister due to end of event factory. - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_FALSE(status.ok()); -} - -static int kBellHathTolled = 0; - -Status TestTheeCallback(const EventContextRef& ec, - const SubscriptionContextRef& sc) { - kBellHathTolled += 1; - return Status::success(); -} - -class FakeEventSubscriber : public EventSubscriber { - public: - bool bellHathTolled{false}; - bool contextBellHathTolled{false}; - bool shouldFireBethHathTolled{false}; - size_t timesConfigured{0}; - - FakeEventSubscriber() { - setName("fake_events"); - } - - explicit FakeEventSubscriber(bool skip_name) { - if (!skip_name) { - FakeEventSubscriber(); - } - } - - void configure() override { - timesConfigured++; - } - - Status Callback(const ECRef& ec, const SCRef& sc) { - // We don't care about the subscription or the event contexts. - bellHathTolled = true; - return Status::success(); - } - - Status SpecialCallback(const ECRef& ec, const SCRef& sc) { - // Now we care that the event context is corrected passed. - if (ec->required_value == 42) { - contextBellHathTolled = true; - } - return Status::success(); - } - - void lateInit() { - auto sub_ctx = createSubscriptionContext(); - subscribe(&FakeEventSubscriber::Callback, sub_ctx); - } - - void laterInit() { - auto sub_ctx = createSubscriptionContext(); - sub_ctx->require_this_value = 42; - subscribe(&FakeEventSubscriber::SpecialCallback, sub_ctx); - } - - private: - FRIEND_TEST(EventsTests, test_subscriber_names); - FRIEND_TEST(EventsTests, test_event_subscriber_configure); -}; - -TEST_F(EventsTests, test_event_subscriber) { - auto sub = std::make_shared(); - EXPECT_EQ(sub->getType(), "FakePublisher"); - EXPECT_EQ(sub->getName(), "fake_events"); -} - -TEST_F(EventsTests, test_event_subscriber_subscribe) { - auto pub = std::make_shared(); - EventFactory::registerEventPublisher(pub); - - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - // Don't overload the normal `init` Subscription member. - sub->lateInit(); - pub->configure(); - EXPECT_EQ(pub->numSubscriptions(), 1U); - - auto ec = pub->createEventContext(); - pub->fire(ec, 0); - - EXPECT_TRUE(sub->bellHathTolled); - - auto status = EventFactory::deregisterEventSubscriber(sub->getName()); - EXPECT_TRUE(status.ok()); - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_event_subscriber_context) { - auto pub = std::make_shared(); - EventFactory::registerEventPublisher(pub); - - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - sub->laterInit(); - pub->configure(); - auto ec = pub->createEventContext(); - ec->required_value = 42; - pub->fire(ec, 0); - - EXPECT_TRUE(sub->contextBellHathTolled); - - auto status = EventFactory::deregisterEventSubscriber(sub->getName()); - EXPECT_TRUE(status.ok()); - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); -} - -TEST_F(EventsTests, test_fire_event) { - auto pub = std::make_shared(); - pub->setName("BasicPublisher"); - auto status = EventFactory::registerEventPublisher(pub); - ASSERT_TRUE(status.ok()); - - auto sub = std::make_shared(); - status = EventFactory::registerEventSubscriber(sub); - ASSERT_TRUE(status.ok()); - - auto subscription = Subscription::create("fake_events"); - subscription->callback = TestTheeCallback; - status = EventFactory::addSubscription("BasicPublisher", subscription); - ASSERT_TRUE(status.ok()); - - pub->configure(); - - // The event context creation would normally happen in the event type. - auto ec = pub->createEventContext(); - pub->fire(ec, 0); - EXPECT_EQ(kBellHathTolled, 1); - - auto second_subscription = Subscription::create("fake_events"); - status = EventFactory::addSubscription("BasicPublisher", second_subscription); - ASSERT_TRUE(status.ok()); - - pub->configure(); - - // Now there are two subscriptions (one sans callback). - pub->fire(ec, 0); - EXPECT_EQ(kBellHathTolled, 2); - - // Now both subscriptions have callbacks. - second_subscription->callback = TestTheeCallback; - pub->fire(ec, 0); - EXPECT_EQ(kBellHathTolled, 4); - - status = EventFactory::deregisterEventSubscriber(sub->getName()); - EXPECT_TRUE(status.ok()); - - status = EventFactory::deregisterEventPublisher(pub->type()); - EXPECT_TRUE(status.ok()); -} - -class SubFakeEventSubscriber : public FakeEventSubscriber { - public: - SubFakeEventSubscriber() : FakeEventSubscriber(true) { - setName("sub_fake_events"); - } - - private: - FRIEND_TEST(EventsTests, test_subscriber_names); -}; - -TEST_F(EventsTests, test_subscriber_names) { - auto subsub = std::make_shared(); - EXPECT_EQ(subsub->getType(), "FakePublisher"); - EXPECT_EQ(subsub->getName(), "sub_fake_events"); - EXPECT_EQ(subsub->dbNamespace(), "FakePublisher.sub_fake_events"); - - auto sub = std::make_shared(); - EXPECT_EQ(sub->getName(), "fake_events"); - EXPECT_EQ(sub->dbNamespace(), "FakePublisher.fake_events"); -} - -class DisabledEventSubscriber : public EventSubscriber { - public: - DisabledEventSubscriber() : EventSubscriber(false) {} -}; - -TEST_F(EventsTests, test_event_toggle_subscribers) { - // Make sure subscribers can disable themselves using the event subscriber - // constructor parameter. - auto sub = std::make_shared(); - sub->setName("disabled_events"); - EXPECT_TRUE(sub->disabled); - - // Normal subscribers will be enabled. - auto sub2 = std::make_shared(); - EXPECT_FALSE(sub2->disabled); - - // Registering a disabled subscriber will put it into a paused state. - EventFactory::registerEventSubscriber(sub); - EXPECT_EQ(sub->state(), EventState::EVENT_PAUSED); - - auto status = EventFactory::deregisterEventSubscriber(sub->getName()); - EXPECT_TRUE(status.ok()); -} -} diff --git a/src/osquery/events/tests/linux/audit_tests.cpp b/src/osquery/events/tests/linux/audit_tests.cpp deleted file mode 100644 index aa47c84..0000000 --- a/src/osquery/events/tests/linux/audit_tests.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include "osquery/events/linux/auditdnetlink.h" -#include "osquery/tests/test_util.h" - -namespace osquery { - -DECLARE_bool(audit_allow_unix); - -/// Internal audit subscriber (socket events) testable methods. -extern void parseSockAddr(const std::string& saddr, Row& r, bool& unix_socket); - -using StringMap = std::map; - -/// Generates a fake audit id -std::string generateAuditId(std::uint32_t event_id) noexcept { - std::stringstream str_helper; - str_helper << std::time(nullptr) << ".000:" << event_id; - - return str_helper.str(); -} - -class AuditTests : public testing::Test { - protected: - void SetUp() override { - Row().swap(row_); - } - - protected: - Row row_; -}; - -TEST_F(AuditTests, test_handle_reply) { - // A 'fake' audit message. - std::string message = - "audit(1440542781.644:403030): argc=3 a0=\"H=1 \" a1=\"/bin/sh\" a2=c"; - - struct audit_reply reply; - reply.type = 1; - reply.len = message.size(); - reply.message = (char*)malloc(sizeof(char) * (message.size() + 1)); - memset((void*)reply.message, 0, message.size() + 1); - memcpy((void*)reply.message, message.c_str(), message.size()); - - // Perform the parsing. - AuditEventRecord audit_event_record = {}; - bool parser_status = - AuditdNetlinkParser::ParseAuditReply(reply, audit_event_record); - EXPECT_EQ(parser_status, true); - - free((char*)reply.message); - - EXPECT_EQ(reply.type, audit_event_record.type); - EXPECT_EQ("1440542781.644:403030", audit_event_record.audit_id); - EXPECT_EQ(audit_event_record.fields.size(), 4U); - EXPECT_EQ(audit_event_record.fields.count("argc"), 1U); - EXPECT_EQ(audit_event_record.fields["argc"], "3"); - EXPECT_EQ(audit_event_record.fields["a0"], "\"H=1 \""); - EXPECT_EQ(audit_event_record.fields["a1"], "\"/bin/sh\""); - EXPECT_EQ(audit_event_record.fields["a2"], "c"); -} - -TEST_F(AuditTests, test_audit_value_decode) { - // In the normal case the decoding only removes '"' characters from the ends. - auto decoded_normal = DecodeAuditPathValues("\"/bin/ls\""); - EXPECT_EQ(decoded_normal, "/bin/ls"); - - // If the first char is not '"', the value is expected to be hex-encoded. - auto decoded_hex = DecodeAuditPathValues("736C6565702031"); - EXPECT_EQ(decoded_hex, "sleep 1"); - - // When the hex fails to decode the input value is returned as the result. - auto decoded_fail = DecodeAuditPathValues("7"); - EXPECT_EQ(decoded_fail, "7"); -} - -size_t kAuditCounter{0}; - -bool SimpleUpdate(size_t t, const StringMap& f, StringMap& m) { - kAuditCounter++; - for (const auto& i : f) { - m[i.first] = i.second; - } - return true; -} - -TEST_F(AuditTests, test_parse_sock_addr) { - Row r; - std::string msg = "02001F907F0000010000000000000000"; - bool unix_socket; - parseSockAddr(msg, r, unix_socket); - ASSERT_FALSE(r["remote_address"].empty()); - EXPECT_EQ(r["remote_address"], "127.0.0.1"); - EXPECT_EQ(r["family"], "2"); - EXPECT_EQ(r["remote_port"], "8080"); - - Row r3; - std::string msg2 = "0A001F9100000000FE80000000000000022522FFFEB03684000000"; - parseSockAddr(msg2, r3, unix_socket); - ASSERT_FALSE(r3["remote_address"].empty()); - EXPECT_EQ(r3["remote_address"], "fe80:0000:0000:0000:0225:22ff:feb0:3684"); - EXPECT_EQ(r3["remote_port"], "8081"); - - auto socket_flag = FLAGS_audit_allow_unix; - FLAGS_audit_allow_unix = true; - Row r4; - std::string msg3 = "01002F746D702F6F7371756572792E656D0000"; - parseSockAddr(msg3, r4, unix_socket); - ASSERT_FALSE(r4["socket"].empty()); - EXPECT_EQ(r4["socket"], "/tmp/osquery.em"); - - msg3 = "0100002F746D702F6F7371756572792E656D"; - parseSockAddr(msg3, r4, unix_socket); - EXPECT_EQ(r4["socket"], "/tmp/osquery.em"); - FLAGS_audit_allow_unix = socket_flag; -} -} diff --git a/src/osquery/events/tests/linux/inotify_tests.cpp b/src/osquery/events/tests/linux/inotify_tests.cpp deleted file mode 100644 index b5f4ada..0000000 --- a/src/osquery/events/tests/linux/inotify_tests.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace fs = boost::filesystem; - -namespace osquery { -DECLARE_bool(disable_database); - -const int kMaxEventLatency = 3000; - -class INotifyTests : public testing::Test { - protected: - void SetUp() override { - kToolType = ToolType::TEST; - registryAndPluginInit(); - - FLAGS_disable_database = true; - DatabasePlugin::setAllowOpen(true); - DatabasePlugin::initPlugin(); - - // INotify will use data from the config and config parsers. - Registry::get().registry("config_parser")->setUp(); - - // Create a basic path trigger, this is a file path. - real_test_path = - fs::weakly_canonical(fs::temp_directory_path() / - fs::unique_path("inotify-trigger.%%%%.%%%%")) - .string(); - // Create a similar directory for embedded paths and directories. - real_test_dir = - fs::weakly_canonical(fs::temp_directory_path() / - fs::unique_path("inotify-trigger.%%%%.%%%%")) - .string(); - - // Create the embedded paths. - real_test_dir_path = real_test_dir + "/1"; - real_test_sub_dir = real_test_dir + "/2"; - real_test_sub_dir_path = real_test_sub_dir + "/1"; - } - - void TearDown() override { - // End the event loops, and join on the threads. - removePath(real_test_dir); - removePath(real_test_path); - } - - void StartEventLoop() { - event_pub_ = std::make_shared(true); - auto status = EventFactory::registerEventPublisher(event_pub_); - FILE* fd = fopen(real_test_path.c_str(), "w"); - fclose(fd); - temp_thread_ = std::thread(EventFactory::run, "inotify"); - } - - void StopEventLoop() { - while (!event_pub_->hasStarted()) { - ::usleep(20); - } - - EventFactory::end(true); - temp_thread_.join(); - } - - void SubscriptionAction(const std::string& path, - uint32_t mask = IN_ALL_EVENTS, - EventCallback ec = nullptr) { - auto sc = std::make_shared(); - sc->path = path; - sc->mask = mask; - - EventFactory::addSubscription("inotify", "TestSubscriber", sc, ec); - event_pub_->configure(); - } - - bool WaitForEvents(size_t max, size_t num_events = 0) { - size_t delay = 0; - while (delay <= max * 1000) { - if (num_events > 0 && event_pub_->numEvents() >= num_events) { - return true; - } else if (num_events == 0 && event_pub_->numEvents() > 0) { - return true; - } - delay += 50; - ::usleep(50); - } - return false; - } - - void TriggerEvent(const std::string& path) { - FILE* fd = fopen(path.c_str(), "w"); - fputs("inotify", fd); - fclose(fd); - } - - void addMonitor(const std::string& path, - uint32_t mask, - bool recursive, - bool add_watch) { - auto sc = event_pub_->createSubscriptionContext(); - event_pub_->addMonitor(path, sc, mask, recursive, add_watch); - } - - void RemoveAll(std::shared_ptr& pub) { - pub->subscriptions_.clear(); - // Reset monitors. - std::vector wds; - for (const auto& path : pub->descriptor_inosubctx_) { - wds.push_back(path.first); - } - for (const auto& wd : wds) { - pub->removeMonitor(wd, true); - } - } - - protected: - /// Internal state managers: publisher reference. - std::shared_ptr event_pub_{nullptr}; - - /// Internal state managers: event publisher thread. - std::thread temp_thread_; - - /// Transient paths ./inotify-trigger. - std::string real_test_path; - - /// Transient paths ./inotify-triggers/. - std::string real_test_dir; - - /// Transient paths ./inotify-triggers/1. - std::string real_test_dir_path; - - /// Transient paths ./inotify-triggers/2/. - std::string real_test_sub_dir; - - /// Transient paths ./inotify-triggers/2/1. - std::string real_test_sub_dir_path; -}; - -TEST_F(INotifyTests, test_register_event_pub) { - auto pub = std::make_shared(true); - auto status = EventFactory::registerEventPublisher(pub); - EXPECT_TRUE(status.ok()); - - // Make sure only one event type exists - EXPECT_EQ(EventFactory::numEventPublishers(), 1U); - // And deregister - status = EventFactory::deregisterEventPublisher("inotify"); - EXPECT_TRUE(status.ok()); -} - -TEST_F(INotifyTests, test_inotify_init) { - // Handle should not be initialized during ctor. - auto event_pub = std::make_shared(true); - EXPECT_FALSE(event_pub->isHandleOpen()); - - // Registering the event type initializes inotify. - auto status = EventFactory::registerEventPublisher(event_pub); - EXPECT_TRUE(status.ok()); - EXPECT_TRUE(event_pub->isHandleOpen()); - - // Similarly deregistering closes the handle. - EventFactory::deregisterEventPublisher("inotify"); - EXPECT_FALSE(event_pub->isHandleOpen()); -} - -TEST_F(INotifyTests, test_inotify_add_subscription_missing_path) { - auto pub = std::make_shared(true); - EventFactory::registerEventPublisher(pub); - - // This subscription path is fake, and will succeed. - auto mc = std::make_shared(); - mc->path = "/this/path/is/fake"; - - auto subscription = Subscription::create("TestSubscriber", mc); - auto status = EventFactory::addSubscription("inotify", subscription); - EXPECT_TRUE(status.ok()); - EventFactory::deregisterEventPublisher("inotify"); -} - -TEST_F(INotifyTests, test_inotify_add_subscription_success) { - auto pub = std::make_shared(true); - EventFactory::registerEventPublisher(pub); - - // This subscription path *should* be real. - auto mc = std::make_shared(); - mc->path = "/"; - mc->mask = IN_ALL_EVENTS; - - auto subscription = Subscription::create("TestSubscriber", mc); - auto status = EventFactory::addSubscription("inotify", subscription); - EXPECT_TRUE(status.ok()); - EventFactory::deregisterEventPublisher("inotify"); -} - -TEST_F(INotifyTests, test_inotify_match_subscription) { - event_pub_ = std::make_shared(true); - addMonitor("/etc", IN_ALL_EVENTS, false, false); - EXPECT_EQ(event_pub_->path_descriptors_.count("/etc"), 1U); - // This will fail because there is no trailing "/" at the end. - // The configure component should take care of these paths. - EXPECT_FALSE(event_pub_->isPathMonitored("/etc/passwd")); - event_pub_->path_descriptors_.clear(); - - // Calling addMonitor the correct way. - addMonitor("/etc/", IN_ALL_EVENTS, false, false); - EXPECT_TRUE(event_pub_->isPathMonitored("/etc/passwd")); - event_pub_->path_descriptors_.clear(); - - // Test the matching capability. - { - auto sc = event_pub_->createSubscriptionContext(); - sc->path = "/etc"; - event_pub_->monitorSubscription(sc, false); - EXPECT_EQ(sc->path, "/etc/"); - EXPECT_TRUE(event_pub_->isPathMonitored("/etc/")); - EXPECT_TRUE(event_pub_->isPathMonitored("/etc/passwd")); - } - - std::vector valid_dirs = {"/etc", "/etc/", "/etc/*"}; - for (const auto& dir : valid_dirs) { - event_pub_->path_descriptors_.clear(); - auto sc = event_pub_->createSubscriptionContext(); - sc->path = dir; - event_pub_->monitorSubscription(sc, false); - auto ec = event_pub_->createEventContext(); - ec->isub_ctx = sc; - ec->path = "/etc/"; - EXPECT_TRUE(event_pub_->shouldFire(sc, ec)); - ec->path = "/etc/passwd"; - EXPECT_TRUE(event_pub_->shouldFire(sc, ec)); - } - - std::vector exclude_paths = { - "/etc/ssh/%%", "/etc/", "/etc/ssl/openssl.cnf", "/"}; - for (const auto& path : exclude_paths) { - event_pub_->exclude_paths_.insert(path); - } - - { - event_pub_->path_descriptors_.clear(); - auto sc = event_pub_->createSubscriptionContext(); - sc->path = "/etc/%%"; - auto ec = event_pub_->createEventContext(); - ec->isub_ctx = sc; - ec->path = "/etc/ssh/ssh_config"; - EXPECT_FALSE(event_pub_->shouldFire(sc, ec)); - ec->path = "/etc/passwd"; - EXPECT_FALSE(event_pub_->shouldFire(sc, ec)); - ec->path = "/etc/group"; - EXPECT_FALSE(event_pub_->shouldFire(sc, ec)); - ec->path = "/etc/ssl/openssl.cnf"; - EXPECT_FALSE(event_pub_->shouldFire(sc, ec)); - ec->path = "/etc/ssl/certs/"; - EXPECT_TRUE(event_pub_->shouldFire(sc, ec)); - } -} - -class TestINotifyEventSubscriber - : public EventSubscriber { - public: - TestINotifyEventSubscriber() { - setName("TestINotifyEventSubscriber"); - } - - Status init() override { - callback_count_ = 0; - return Status::success(); - } - - Status SimpleCallback(const ECRef& ec, const SCRef& sc) { - callback_count_ += 1; - return Status::success(); - } - - Status Callback(const ECRef& ec, const SCRef& sc) { - // The following comments are an example Callback routine. - // Row r; - // r["action"] = ec->action; - // r["path"] = ec->path; - - // Normally would call Add here. - callback_count_++; - - WriteLock lock(actions_lock_); - actions_.push_back(ec->action); - return Status::success(); - } - - SCRef GetSubscription(const std::string& path, - uint32_t mask = IN_ALL_EVENTS) { - auto mc = createSubscriptionContext(); - mc->path = path; - mc->mask = mask; - return mc; - } - - void WaitForEvents(int max, int num_events = 1) { - int delay = 0; - while (delay < max * 1000) { - if (callback_count_ >= num_events) { - return; - } - ::usleep(50); - delay += 50; - } - } - - std::vector actions() { - WriteLock lock(actions_lock_); - return actions_; - } - - int count() { - return callback_count_; - } - - public: - std::atomic callback_count_{0}; - std::vector actions_; - - private: - Mutex actions_lock_; - - private: - FRIEND_TEST(INotifyTests, test_inotify_fire_event); - FRIEND_TEST(INotifyTests, test_inotify_event_action); - FRIEND_TEST(INotifyTests, test_inotify_optimization); - FRIEND_TEST(INotifyTests, test_inotify_directory_watch); - FRIEND_TEST(INotifyTests, DISABLED_test_inotify_recursion); - FRIEND_TEST(INotifyTests, test_inotify_embedded_wildcards); -}; - -TEST_F(INotifyTests, test_inotify_run) { - // Assume event type is registered. - event_pub_ = std::make_shared(true); - auto status = EventFactory::registerEventPublisher(event_pub_); - EXPECT_TRUE(status.ok()); - - // Create a temporary file to watch, open writeable - FILE* fd = fopen(real_test_path.c_str(), "w"); - - // Create a subscriber. - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - // Create a subscription context - auto mc = std::make_shared(); - mc->path = real_test_path; - mc->mask = IN_ALL_EVENTS; - status = EventFactory::addSubscription( - "inotify", Subscription::create("TestINotifyEventSubscriber", mc)); - EXPECT_TRUE(status.ok()); - event_pub_->configure(); - - // Create an event loop thread (similar to main) - std::thread temp_thread(EventFactory::run, "inotify"); - EXPECT_TRUE(event_pub_->numEvents() == 0); - - // Cause an inotify event by writing to the watched path. - fputs("inotify", fd); - fclose(fd); - - // Wait for the thread's run loop to select. - WaitForEvents(kMaxEventLatency); - EXPECT_TRUE(event_pub_->numEvents() > 0); - EventFactory::end(); - temp_thread.join(); -} - -TEST_F(INotifyTests, test_inotify_fire_event) { - // Assume event type is registered. - StartEventLoop(); - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - // Create a subscriptioning context, note the added Event to the symbol - auto sc = sub->GetSubscription(real_test_path, 0); - sub->subscribe(&TestINotifyEventSubscriber::SimpleCallback, sc); - event_pub_->configure(); - - TriggerEvent(real_test_path); - sub->WaitForEvents(kMaxEventLatency); - - // Make sure our expected event fired (aka subscription callback was called). - EXPECT_TRUE(sub->count() > 0); - StopEventLoop(); -} - -TEST_F(INotifyTests, test_inotify_event_action) { - // Assume event type is registered. - StartEventLoop(); - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - auto sc = sub->GetSubscription(real_test_path, IN_ALL_EVENTS); - sub->subscribe(&TestINotifyEventSubscriber::Callback, sc); - event_pub_->configure(); - - TriggerEvent(real_test_path); - sub->WaitForEvents(kMaxEventLatency, 2); - - // Make sure the inotify action was expected. - EXPECT_GT(sub->actions().size(), 0U); - if (sub->actions().size() >= 2) { - EXPECT_EQ(sub->actions()[0], "UPDATED"); - } - - StopEventLoop(); -} - -TEST_F(INotifyTests, test_inotify_optimization) { - // Assume event type is registered. - StartEventLoop(); - fs::create_directory(real_test_dir); - - // Adding a descriptor to a directory will monitor files within. - SubscriptionAction(real_test_dir); - EXPECT_TRUE(event_pub_->isPathMonitored(real_test_dir_path)); - - // Adding a subscription to a file within a monitored directory is fine - // but this will NOT cause an additional INotify watch. - SubscriptionAction(real_test_dir_path); - EXPECT_EQ(event_pub_->numDescriptors(), 1U); - StopEventLoop(); -} - -TEST_F(INotifyTests, test_inotify_directory_watch) { - StartEventLoop(); - - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - fs::create_directory(real_test_dir); - fs::create_directory(real_test_sub_dir); - - // Subscribe to the directory inode - auto mc = sub->createSubscriptionContext(); - mc->path = real_test_dir; - mc->recursive = true; - sub->subscribe(&TestINotifyEventSubscriber::Callback, mc); - event_pub_->configure(); - - // Trigger on a subdirectory's file. - TriggerEvent(real_test_sub_dir_path); - - sub->WaitForEvents(kMaxEventLatency, 1); - EXPECT_TRUE(sub->count() > 0); - StopEventLoop(); -} - -TEST_F(INotifyTests, DISABLED_test_inotify_recursion) { - // Create a non-registered publisher and subscriber. - auto pub = std::make_shared(true); - EventFactory::registerEventPublisher(pub); - auto sub = std::make_shared(); - - // Create a mock directory structure. - fs::create_directory(real_test_dir); - - // Create and test several subscriptions. - auto sc = sub->createSubscriptionContext(); - - sc->path = real_test_dir + "/*"; - sub->subscribe(&TestINotifyEventSubscriber::Callback, sc); - // Trigger a configure step manually. - pub->configure(); - - // Expect a single monitor on the root of the fake tree. - EXPECT_EQ(pub->path_descriptors_.size(), 1U); - EXPECT_EQ(pub->path_descriptors_.count(real_test_dir + "/"), 1U); - RemoveAll(pub); - - // Make sure monitors are empty. - EXPECT_EQ(pub->numDescriptors(), 0U); - - auto sc2 = sub->createSubscriptionContext(); - sc2->path = real_test_dir + "/**"; - sub->subscribe(&TestINotifyEventSubscriber::Callback, sc2); - pub->configure(); - - // Expect only the directories to be monitored. - // TODO test fails in the following assert. - EXPECT_EQ(pub->path_descriptors_.size(), 11U); - RemoveAll(pub); - - // Use a directory structure that includes a loop. - boost::system::error_code ec; - fs::create_symlink(real_test_dir, real_test_dir + "/link", ec); - - auto sc3 = sub->createSubscriptionContext(); - sc3->path = real_test_dir + "/**"; - sub->subscribe(&TestINotifyEventSubscriber::Callback, sc3); - pub->configure(); - - // Also expect canonicalized resolution (to prevent loops). - EXPECT_EQ(pub->path_descriptors_.size(), 9U); - RemoveAll(pub); - - EventFactory::deregisterEventPublisher("inotify"); -} - -TEST_F(INotifyTests, test_inotify_embedded_wildcards) { - // Assume event type is not registered. - event_pub_ = std::make_shared(true); - EventFactory::registerEventPublisher(event_pub_); - - auto sub = std::make_shared(); - EventFactory::registerEventSubscriber(sub); - - // Create ./inotify-triggers/2/1/. - fs::create_directories(real_test_dir + "/2/1"); - - // Create a subscription to match an embedded wildcard: "*" - // The assumption is a watch will be created on the 'most-specific' directory - // before the wildcard request. - auto mc = sub->createSubscriptionContext(); - mc->path = real_test_dir + "/*/1"; - mc->recursive = true; - sub->subscribe(&TestINotifyEventSubscriber::Callback, mc); - - // Now the publisher must be configured. - event_pub_->configure(); - - // Assume there is one watched path: real_test_dir. - ASSERT_EQ(event_pub_->numDescriptors(), 1U); - EXPECT_EQ(event_pub_->path_descriptors_.count(real_test_dir + "/2/1/"), 1U); -} -} diff --git a/src/osquery/events/tests/linux/process_file_events_tests.cpp b/src/osquery/events/tests/linux/process_file_events_tests.cpp deleted file mode 100644 index 9005bfa..0000000 --- a/src/osquery/events/tests/linux/process_file_events_tests.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace osquery { -extern std::vector> complete_event_list; -extern StringList included_file_paths; -extern std::string generateAuditId(std::uint32_t event_id) noexcept; - -class AuditdFimTests : public testing::Test { - protected: - void SetUp() override { - Row().swap(row_); - } - - protected: - Row row_; -}; - -void DumpRow(Row r) { - std::cout << " " << r["operation"] << " " << r["path1"]; - if (r.find("path2") != r.end()) { - std::cout << " " << r["path2"]; - } - - std::cout << "\n"; -} - -void DumpRowList(const std::vector& row_list) { - for (const auto& r : row_list) { - DumpRow(r); - } -} - -TEST_F(AuditdFimTests, row_emission) { - std::vector event_record_list; - - // Parse the raw messages and make sure we get the right amount - // of records - for (const auto& record_descriptor : complete_event_list) { - std::string audit_message_copy = record_descriptor.second; - - audit_reply reply = {}; - reply.type = record_descriptor.first; - reply.len = audit_message_copy.size(); - reply.message = &audit_message_copy[0]; - - AuditEventRecord audit_event_record = {}; - - bool parser_status = - AuditdNetlinkParser::ParseAuditReply(reply, audit_event_record); - EXPECT_EQ(parser_status, true); - - event_record_list.push_back(audit_event_record); - } - - EXPECT_EQ(event_record_list.size(), 243U); - - // Assemble the audit records into audit events, and make sure - // we get the correct amount of objects - auto event_context = std::make_shared(); - AuditTraceContext audit_trace_context; - - AuditEventPublisher::ProcessEvents( - event_context, event_record_list, audit_trace_context); - - EXPECT_EQ(audit_trace_context.size(), 0U); - EXPECT_EQ(event_context->audit_events.size(), 71U); - - // Configure what we want to log and what we want to ignore - AuditdFimContext fim_context; - fim_context.included_path_list = included_file_paths; - - // Emit the rows, showing only writes - std::vector emitted_row_list; - Status status = ProcessFileEventSubscriber::ProcessEvents( - emitted_row_list, fim_context, event_context->audit_events); - - EXPECT_EQ(status.ok(), true); - // @TODO fix failing test - // EXPECT_EQ(emitted_row_list.size(), 15U); -} - -// clang-format off -StringList included_file_paths = { - "/etc/ld.so.cache", - "/home/alessandro/test_file", - "/lib64/libc.so.6", - "/lib64/libgcc_s.so.1", - "/lib64/libm.so.6", - "/lib64/libstdc++.so.6", - "/home/alessandro/test_file", - "/home/alessandro/test_file1", - "/home/alessandro/test_file2", - "/home/alessandro/test_file3", - "/home/alessandro/test_file4", - "/home/alessandro/test_file5", - "/home/alessandro/test_file7", - "/home/alessandro/test_file_rename", - "/home/alessandro/test_file_renameat" -}; - -std::vector> complete_event_list = { - {1300, "audit(1502573850.697:38395): arch=c000003e syscall=9 success=yes exit=140095431475200 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38395): "}, - {1300, "audit(1502573850.697:38396): arch=c000003e syscall=2 success=yes exit=3 a0=7f6a824d4df5 a1=80000 a2=1 a3=7f6a826db4f8 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.697:38396): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.697:38396): item=0 name=\"/etc/ld.so.cache\" inode=67842177 dev=fd:00 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:ld_so_cache_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.697:38396): "}, - {1300, "audit(1502573850.697:38397): arch=c000003e syscall=9 success=yes exit=140095431385088 a0=0 a1=15e5b a2=1 a3=2 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38397): fd=3 flags=0x2"}, - {1320, "audit(1502573850.697:38397): "}, - {1300, "audit(1502573850.697:38398): arch=c000003e syscall=3 success=yes exit=0 a0=3 a1=15e5b a2=1 a3=2 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38398): "}, - {1300, "audit(1502573850.697:38399): arch=c000003e syscall=2 success=yes exit=3 a0=7f6a826d8640 a1=80000 a2=7f6a826db150 a3=7f6a826d8640 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.697:38399): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.697:38399): item=0 name=\"/lib64/libstdc++.so.6\" inode=33604382 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:lib_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.697:38399): "}, - {1300, "audit(1502573850.697:38400): arch=c000003e syscall=0 success=yes exit=832 a0=3 a1=7fff15c09350 a2=340 a3=7f6a826d8640 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38400): "}, - {1300, "audit(1502573850.697:38401): arch=c000003e syscall=9 success=yes exit=140095426068480 a0=0 a1=308420 a2=5 a3=802 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38401): fd=3 flags=0x802"}, - {1320, "audit(1502573850.697:38401): "}, - {1300, "audit(1502573850.697:38402): arch=c000003e syscall=9 success=yes exit=140095429120000 a0=7f6a82499000 a1=b000 a2=3 a3=812 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38402): fd=3 flags=0x812"}, - {1320, "audit(1502573850.697:38402): "}, - {1300, "audit(1502573850.697:38403): arch=c000003e syscall=9 success=yes exit=140095429165056 a0=7f6a824a4000 a1=14420 a2=3 a3=32 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38403): "}, - {1300, "audit(1502573850.697:38404): arch=c000003e syscall=3 success=yes exit=0 a0=3 a1=7f6a826d8698 a2=0 a3=31 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38404): "}, - {1300, "audit(1502573850.697:38405): arch=c000003e syscall=2 success=yes exit=3 a0=7f6a826d8b08 a1=80000 a2=7f6a826db150 a3=7f6a826d8b08 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.697:38405): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.697:38405): item=0 name=\"/lib64/libm.so.6\" inode=33604048 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:lib_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.697:38405): "}, - {1300, "audit(1502573850.697:38406): arch=c000003e syscall=0 success=yes exit=832 a0=3 a1=7fff15c09320 a2=340 a3=7f6a826d8b08 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38406): "}, - {1300, "audit(1502573850.697:38407): arch=c000003e syscall=9 success=yes exit=140095422914560 a0=0 a1=301148 a2=5 a3=802 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38407): fd=3 flags=0x802"}, - {1320, "audit(1502573850.697:38407): "}, - {1300, "audit(1502573850.697:38408): arch=c000003e syscall=9 success=yes exit=140095426060288 a0=7f6a821ae000 a1=2000 a2=3 a3=812 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38408): fd=3 flags=0x812"}, - {1320, "audit(1502573850.697:38408): "}, - {1300, "audit(1502573850.697:38409): arch=c000003e syscall=3 success=yes exit=0 a0=3 a1=7f6a826d8b60 a2=0 a3=31 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38409): "}, - {1300, "audit(1502573850.697:38410): arch=c000003e syscall=2 success=yes exit=3 a0=7f6a826d8fd0 a1=80000 a2=7f6a826db150 a3=7f6a826d8fd0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.697:38410): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.697:38410): item=0 name=\"/lib64/libgcc_s.so.1\" inode=33554508 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:lib_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.697:38410): "}, - {1300, "audit(1502573850.697:38411): arch=c000003e syscall=0 success=yes exit=832 a0=3 a1=7fff15c092f0 a2=340 a3=7f6a826d8fd0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38411): "}, - {1300, "audit(1502573850.697:38412): arch=c000003e syscall=9 success=yes exit=140095431380992 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38412): "}, - {1300, "audit(1502573850.697:38413): arch=c000003e syscall=9 success=yes exit=140095420727296 a0=0 a1=215400 a2=5 a3=802 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38413): fd=3 flags=0x802"}, - {1320, "audit(1502573850.697:38413): "}, - {1300, "audit(1502573850.697:38414): arch=c000003e syscall=9 success=yes exit=140095422906368 a0=7f6a81eac000 a1=2000 a2=3 a3=812 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.697:38414): fd=3 flags=0x812"}, - {1320, "audit(1502573850.697:38414): "}, - {1300, "audit(1502573850.697:38415): arch=c000003e syscall=3 success=yes exit=0 a0=3 a1=7f6a826c1040 a2=0 a3=31 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.697:38415): "}, - {1300, "audit(1502573850.698:38416): arch=c000003e syscall=2 success=yes exit=3 a0=7f6a826c14b0 a1=80000 a2=7f6a826db150 a3=7f6a826c14b0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.698:38416): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.698:38416): item=0 name=\"/lib64/libc.so.6\" inode=33604039 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:lib_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.698:38416): "}, - {1300, "audit(1502573850.698:38417): arch=c000003e syscall=0 success=yes exit=832 a0=3 a1=7fff15c092c0 a2=340 a3=7f6a826c14b0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38417): "}, - {1300, "audit(1502573850.698:38418): arch=c000003e syscall=9 success=yes exit=140095416791040 a0=0 a1=3c0200 a2=5 a3=802 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.698:38418): fd=3 flags=0x802"}, - {1320, "audit(1502573850.698:38418): "}, - {1300, "audit(1502573850.698:38419): arch=c000003e syscall=9 success=yes exit=140095420682240 a0=7f6a81c8d000 a1=6000 a2=3 a3=812 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573850.698:38419): fd=3 flags=0x812"}, - {1320, "audit(1502573850.698:38419): "}, - {1300, "audit(1502573850.698:38420): arch=c000003e syscall=9 success=yes exit=140095420706816 a0=7f6a81c93000 a1=4200 a2=3 a3=32 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38420): "}, - {1300, "audit(1502573850.698:38421): arch=c000003e syscall=3 success=yes exit=0 a0=3 a1=7f6a826c1508 a2=0 a3=31 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38421): "}, - {1300, "audit(1502573850.698:38422): arch=c000003e syscall=9 success=yes exit=140095431376896 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38422): "}, - {1300, "audit(1502573850.698:38423): arch=c000003e syscall=9 success=yes exit=140095431368704 a0=0 a1=2000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38423): "}, - {1300, "audit(1502573850.698:38424): arch=c000003e syscall=9 success=yes exit=140095431364608 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.698:38424): "}, - {1300, "audit(1502573850.698:38425): arch=c000003e syscall=87 success=yes exit=0 a0=40219c a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.698:38425): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.698:38425): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.698:38425): item=1 name=\"test_file\" inode=724389 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.698:38425): "}, - {1300, "audit(1502573850.699:38428): arch=c000003e syscall=87 success=yes exit=0 a0=4021ff a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.699:38428): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.699:38428): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.699:38428): item=1 name=\"test_file3\" inode=724389 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.699:38428): "}, - {1300, "audit(1502573850.699:38429): arch=c000003e syscall=87 success=yes exit=0 a0=40220a a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.699:38429): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.699:38429): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.699:38429): item=1 name=\"test_file4\" inode=724416 dev=fd:02 mode=0120777 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.699:38429): "}, - {1300, "audit(1502573850.699:38430): arch=c000003e syscall=87 success=yes exit=0 a0=40242d a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.699:38430): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.699:38430): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.699:38430): item=1 name=\"test_file5\" inode=724406 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.699:38430): "}, - {1300, "audit(1502573850.699:38431): arch=c000003e syscall=87 success=yes exit=0 a0=402451 a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.699:38431): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.699:38431): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.699:38431): item=1 name=\"test_file6\" inode=724418 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.699:38431): "}, - {1300, "audit(1502573850.699:38432): arch=c000003e syscall=87 success=yes exit=0 a0=402477 a1=7fff15c0ab48 a2=7fff15c0ab58 a3=7fff15c0a7d0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.699:38432): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.699:38432): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573850.699:38432): item=1 name=\"test_file7\" inode=724419 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573850.699:38432): "}, - {1300, "audit(1502573850.725:38494): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=40259e a2=90800 a3=0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573850.725:38494): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573850.725:38494): item=0 name=\".\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573850.725:38494): "}, - {1300, "audit(1502573850.725:38495): arch=c000003e syscall=9 success=yes exit=140095431471104 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.725:38495): "}, - {1300, "audit(1502573850.725:38496): arch=c000003e syscall=1 success=yes exit=18 a0=1 a1=7f6a826d7000 a2=12 a3=0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.725:38496): "}, - {1300, "audit(1502573850.725:38497): arch=c000003e syscall=9 success=yes exit=140095431467008 a0=0 a1=1000 a2=3 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.725:38497): "}, - {1300, "audit(1502573850.726:38498): arch=c000003e syscall=1 success=yes exit=31 a0=1 a1=7f6a826d7000 a2=1f a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.726:38498): "}, - {1300, "audit(1502573850.726:46799): arch=c000003e syscall=0 success=yes exit=1 a0=0 a1=7f6a826d6000 a2=400 a3=22 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573850.726:46799): "}, - {1300, "audit(1502573858.178:46800): arch=c000003e syscall=76 success=yes exit=0 a0=40219c a1=c a2=a a3=7fff15c0a7c0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46800): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46800): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46800): "}, - {1300, "audit(1502573858.178:46801): arch=c000003e syscall=86 success=yes exit=0 a0=40219c a1=402191 a2=a a3=7fff15c0a7c0 items=3 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46801): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46801): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1302, "audit(1502573858.178:46801): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46801): item=2 name=\"test_file1\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46801): "}, - {1300, "audit(1502573858.178:46802): arch=c000003e syscall=88 success=yes exit=0 a0=40219c a1=4021cc a2=a a3=7fff15c0a7c0 items=3 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46802): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46802): item=0 name=\"test_file\" objtype=UNKNOWN"}, - {1302, "audit(1502573858.178:46802): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46802): item=2 name=\"test_file2\" inode=724389 dev=fd:02 mode=0120777 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46802): "}, - {1300, "audit(1502573858.178:46803): arch=c000003e syscall=265 success=yes exit=0 a0=3 a1=40219c a2=3 a3=4021ff items=3 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46803): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46803): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1302, "audit(1502573858.178:46803): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46803): item=2 name=\"test_file3\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46803): "}, - {1300, "audit(1502573858.178:46804): arch=c000003e syscall=266 success=yes exit=0 a0=40219c a1=3 a2=40220a a3=7fff15c0a7c0 items=3 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46804): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46804): item=0 name=\"test_file\" objtype=UNKNOWN"}, - {1302, "audit(1502573858.178:46804): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46804): item=2 name=\"test_file4\" inode=724406 dev=fd:02 mode=0120777 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46804): "}, - {1300, "audit(1502573858.178:46805): arch=c000003e syscall=82 success=yes exit=0 a0=40219c a1=402215 a2=40220a a3=7fff15c0a7c0 items=4 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46805): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46805): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46805): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46805): item=2 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1302, "audit(1502573858.178:46805): item=3 name=\"test_file_rename\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46805): "}, - {1300, "audit(1502573858.178:46806): arch=c000003e syscall=264 success=yes exit=0 a0=3 a1=402215 a2=3 a3=40224e items=4 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46806): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46806): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46806): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46806): item=2 name=\"test_file_rename\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1302, "audit(1502573858.178:46806): item=3 name=\"test_file_renameat\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46806): "}, - {1300, "audit(1502573858.178:46807): arch=c000003e syscall=316 success=yes exit=0 a0=3 a1=40224e a2=3 a3=40219c items=4 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46807): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46807): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46807): item=1 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46807): item=2 name=\"test_file_renameat\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1302, "audit(1502573858.178:46807): item=3 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46807): "}, - {1300, "audit(1502573858.178:46808): arch=c000003e syscall=87 success=yes exit=0 a0=402191 a1=40224e a2=3 a3=40219c items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46808): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46808): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46808): item=1 name=\"test_file1\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573858.178:46808): "}, - {1300, "audit(1502573858.178:46809): arch=c000003e syscall=263 success=yes exit=0 a0=3 a1=4021cc a2=0 a3=7fff15c0a7b0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46809): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46809): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46809): item=1 name=\"test_file2\" inode=724389 dev=fd:02 mode=0120777 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=DELETE"}, - {1320, "audit(1502573858.178:46809): "}, - {1300, "audit(1502573858.178:46810): arch=c000003e syscall=2 success=yes exit=4 a0=4022c6 a1=42 a2=0 a3=7fff15c0a3a0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46810): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46810): item=0 name=\"/home/alessandro/\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46810): item=1 name=\"/home/alessandro/test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46810): "}, - {1300, "audit(1502573858.178:46811): arch=c000003e syscall=32 success=yes exit=5 a0=4 a1=42 a2=0 a3=7fff15c0a3a0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.178:46811): "}, - {1300, "audit(1502573858.178:46812): arch=c000003e syscall=33 success=yes exit=10 a0=4 a1=a a2=0 a3=7fff15c0a3a0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.178:46812): "}, - {1300, "audit(1502573858.178:46813): arch=c000003e syscall=292 success=yes exit=11 a0=4 a1=b a2=0 a3=7fff15c0a3a0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.178:46813): "}, - {1300, "audit(1502573858.178:46814): arch=c000003e syscall=3 success=yes exit=0 a0=b a1=b a2=0 a3=7fff15c0a3a0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.178:46814): "}, - {1300, "audit(1502573858.178:46815): arch=c000003e syscall=257 success=yes exit=6 a0=3 a1=40219c a2=0 a3=0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46815): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46815): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46815): "}, - {1300, "audit(1502573858.178:46816): arch=c000003e syscall=303 success=yes exit=0 a0=ffffff9c a1=40219c a2=7fff15c0a620 a3=7fff15c0aa2c items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46816): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46816): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46816): "}, - {1300, "audit(1502573858.178:46817): arch=c000003e syscall=304 success=yes exit=7 a0=ffffff9c a1=7fff15c0a620 a2=2 a3=7fff15c0a3a0 items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46817): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46817): item=0 name="" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46817): "}, - {1300, "audit(1502573858.178:46818): arch=c000003e syscall=303 success=yes exit=0 a0=3 a1=40219c a2=7fff15c0a620 a3=7fff15c0aa2c items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46818): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46818): item=0 name=\"test_file\" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46818): "}, - {1300, "audit(1502573858.178:46819): arch=c000003e syscall=304 success=yes exit=8 a0=3 a1=7fff15c0a620 a2=2 a3=7fff15c0aa2c items=1 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46819): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46819): item=0 name="" inode=98362 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=NORMAL"}, - {1320, "audit(1502573858.178:46819): "}, - {1300, "audit(1502573858.178:46820): arch=c000003e syscall=133 success=yes exit=0 a0=40242d a1=81a4 a2=0 a3=7fff15c0a380 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46820): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46820): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46820): item=1 name=\"test_file5\" inode=560977 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46820): "}, - {1300, "audit(1502573858.178:46821): arch=c000003e syscall=259 success=yes exit=0 a0=3 a1=402451 a2=81a4 a3=0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46821): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46821): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46821): item=1 name=\"test_file6\" inode=560986 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46821): "}, - {1300, "audit(1502573858.178:46822): arch=c000003e syscall=85 success=yes exit=9 a0=402477 a1=81a4 a2=81a4 a3=7fff15c0a3a0 items=2 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1307, "audit(1502573858.178:46822): cwd=\"/home/alessandro\""}, - {1302, "audit(1502573858.178:46822): item=0 name=\"/home/alessandro\" inode=67 dev=fd:02 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 objtype=PARENT"}, - {1302, "audit(1502573858.178:46822): item=1 name=\"test_file7\" inode=560990 dev=fd:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 objtype=CREATE"}, - {1320, "audit(1502573858.178:46822): "}, - {1300, "audit(1502573858.179:46823): arch=c000003e syscall=0 success=yes exit=10 a0=4 a1=7fff15c0a640 a2=a a3=7fff15c0a3c0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.179:46823): "}, - {1300, "audit(1502573858.179:46824): arch=c000003e syscall=1 success=yes exit=1024 a0=4 a1=7fff15c0a640 a2=400 a3=7fff15c0a3c0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.179:46824): "}, - {1300, "audit(1502573858.179:46825): arch=c000003e syscall=17 success=yes exit=10 a0=4 a1=7fff15c0a640 a2=a a3=1 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.179:46825): "}, - {1300, "audit(1502573858.179:46826): arch=c000003e syscall=18 success=yes exit=1024 a0=4 a1=7fff15c0a640 a2=400 a3=1 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.179:46826): "}, - {1300, "audit(1502573858.179:46827): arch=c000003e syscall=77 success=yes exit=0 a0=4 a1=b a2=400 a3=7fff15c0a7c0 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1320, "audit(1502573858.179:46827): "}, - {1300, "audit(1502573858.179:46828): arch=c000003e syscall=9 success=yes exit=140095431462912 a0=0 a1=a a2=7 a3=1 items=0 ppid=4316 pid=5581 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm=\"mytest\" exe=\"/home/alessandro/mytest\" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)"}, - {1323, "audit(1502573858.179:46828): fd=4 flags=0x1"}, - {1320, "audit(1502573858.179:46828): "} -}; -// clang-format on -} // namespace osquery diff --git a/src/osquery/events/tests/linux/syslog_tests.cpp b/src/osquery/events/tests/linux/syslog_tests.cpp deleted file mode 100644 index 25e6720..0000000 --- a/src/osquery/events/tests/linux/syslog_tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include - -#include - -#include "osquery/events/linux/syslog.h" -#include "osquery/tests/test_util.h" - -namespace osquery { - -class SyslogTests : public testing::Test { - public: - std::vector splitCsv(std::string line) { - boost::tokenizer tokenizer(line); - std::vector result(tokenizer.begin(), tokenizer.end()); - return result; - } -}; - -TEST_F(SyslogTests, test_populate_event_context) { - std::string line = - R"|("2016-03-22T21:17:01.701882+00:00","vagrant-ubuntu-trusty-64","6","cron","CRON[16538]:"," (root) CMD ( cd / && run-parts --report /etc/cron.hourly)")|"; - SyslogEventPublisher pub; - auto ec = pub.createEventContext(); - Status status = pub.populateEventContext(line, ec); - - ASSERT_TRUE(status.ok()); - // Note: the time-parsing was removed to allow events to auto-assign. - ASSERT_EQ(0U, ec->time); - ASSERT_EQ("2016-03-22T21:17:01.701882+00:00", ec->fields.at("datetime")); - ASSERT_EQ("vagrant-ubuntu-trusty-64", ec->fields.at("host")); - ASSERT_EQ("6", ec->fields.at("severity")); - ASSERT_EQ("cron", ec->fields.at("facility")); - ASSERT_EQ("CRON[16538]", ec->fields.at("tag")); - ASSERT_EQ("(root) CMD ( cd / && run-parts --report /etc/cron.hourly)", - ec->fields.at("message")); - - // Too few fields - - std::string bad_line = - R"("2016-03-22T21:17:01.701882+00:00","vagrant-ubuntu-trusty-64","6","cron",)"; - ec = pub.createEventContext(); - status = pub.populateEventContext(bad_line, ec); - ASSERT_FALSE(status.ok()); - ASSERT_NE(std::string::npos, status.getMessage().find("fewer")); - - // Too many fields - bad_line = R"("2016-03-22T21:17:01.701882+00:00","","6","","","","")"; - ec = pub.createEventContext(); - status = pub.populateEventContext(bad_line, ec); - ASSERT_FALSE(status.ok()); - ASSERT_NE(std::string::npos, status.getMessage().find("more")); -} - -TEST_F(SyslogTests, test_csv_separator) { - ASSERT_EQ(std::vector({"", "", "", "", ""}), splitCsv(",,,,")); - ASSERT_EQ(std::vector({" ", " ", " ", " ", " "}), - splitCsv(" , , , , ")); - ASSERT_EQ(std::vector({"foo", "bar", "baz"}), - splitCsv("foo,bar,baz")); - ASSERT_EQ(std::vector({"foo", "bar", "baz"}), - splitCsv("\"foo\",\"bar\",\"baz\"")); - ASSERT_EQ(std::vector({",foo,", ",bar", "baz,"}), - splitCsv("\",foo,\",\",bar\",\"baz,\"")); - ASSERT_EQ(std::vector({",f\\oo,", ",ba\\'r", "baz\\,"}), - splitCsv("\",f\\oo,\",\",ba\\'r\",\"baz\\,\"")); - ASSERT_EQ(std::vector({"\",f\\o\"o,", "\",ba\\'r", "baz\\,\""}), - splitCsv("\"\"\",f\\o\"\"o,\",\"\"\",ba\\'r\",\"baz\\,\"\"\"")); - ASSERT_EQ(std::vector({"\",f\\ø\"o,", "\",bá\\'r", "baz\\,\""}), - splitCsv("\"\"\",f\\ø\"\"o,\",\"\"\",bá\\'r\",\"baz\\,\"\"\"")); -} -} diff --git a/src/osquery/include/osquery/events.h b/src/osquery/include/osquery/events.h deleted file mode 100644 index 862a70b..0000000 --- a/src/osquery/include/osquery/events.h +++ /dev/null @@ -1,1087 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace osquery { - -struct Subscription; -template -class EventPublisher; -template -class EventSubscriber; -class EventFactory; - -using EventID = const std::string; -using EventContextID = uint64_t; -using EventTime = uint64_t; -using EventRecord = std::pair; - -/** - * @brief An EventPublisher will define a SubscriptionContext for - * EventSubscriber%s to use. - * - * Most EventPublisher%s will require specific information for interacting with - * an OS to receive events. The SubscriptionContext contains information the - * EventPublisher will use to register OS API callbacks, create - * subscriptioning/listening handles, etc. - * - * Linux `inotify` should implement a SubscriptionContext that subscribes - * filesystem events based on a filesystem path. `libpcap` will subscribe on - * networking protocols at various stacks. Process creation may subscribe on - * process name, parent pid, etc. - */ -struct SubscriptionContext : private boost::noncopyable {}; - -/** - * @brief An EventSubscriber EventCallback method will receive an EventContext. - * - * The EventContext contains the event-related data supplied by an - * EventPublisher when the event occurs. If a subscribing EventSubscriber - * would be called for the event, the EventSubscriber%'s EventCallback is - * passed an EventContext. - */ -struct EventContext : private boost::noncopyable { - /// An unique counting ID specific to the EventPublisher%'s fired events. - EventContextID id{0}; - - /// The time the event occurred, as determined by the publisher. - EventTime time{0}; -}; - -using SubscriptionRef = std::shared_ptr; -using BaseEventPublisher = EventPublisher; -using EventPublisherRef = std::shared_ptr; -using SubscriptionContextRef = std::shared_ptr; -using EventContextRef = std::shared_ptr; -using BaseEventSubscriber = EventSubscriber; -using EventSubscriberRef = std::shared_ptr>; - -/** - * @brief EventSubscriber%s and Publishers may exist in various states. - * - * The class will move through states when osquery is initializing the - * registry, starting event publisher loops, and requesting initialization of - * each subscriber and the optional set of subscriptions it creates. If this - * initialization fails the publishers or EventFactory may eject, warn, or - * otherwise not use the subscriber's subscriptions. - * - * The supported states are: - * - None: The default state, uninitialized. - * - Setup: The Subscriber is attached and has run setup. - * - Running: Subscriber is ready for events. - * - Paused: Subscriber was initialized but is not currently accepting events. - * - Failed: Subscriber failed to initialize or is otherwise offline. - */ -enum class EventState { - EVENT_NONE = 0, - EVENT_SETUP, - EVENT_RUNNING, - EVENT_PAUSED, - EVENT_FAILED, -}; - -/// Use a single placeholder for the EventContextRef passed to EventCallback. -using EventCallback = std::function; - -/// An EventPublisher must track every subscription added. -using SubscriptionVector = std::vector; - -/// The set of search-time binned lookup tables. -extern const std::vector kEventTimeLists; - -/** - * @brief Details for each subscriber as it relates to the schedule. - * - * This is populated for each configuration update by scanning the schedule. - */ -struct SubscriberExpirationDetails { - public: - /// The max internal is the minimum wait time for expiring subscriber data. - size_t max_interval{0}; - - /// The number of queries that should run between intervals. - size_t query_count{0}; -}; - -/** - * @brief DECLARE_PUBLISHER supplies needed boilerplate code that applies a - * string-type EventPublisherID to identify the publisher declaration. - */ -#define DECLARE_PUBLISHER(TYPE) \ - public: \ - const std::string type() const override final { \ - return TYPE; \ - } - -/** - * @brief A Subscription is used to configure an EventPublisher and bind a - * callback to a SubscriptionContext. - * - * A Subscription is the input to an EventPublisher when the EventPublisher - * decides on the scope and details of the events it watches/generates. - * An example includes a filesystem change event. A subscription would include - * a path with optional recursion and attribute selectors as well as a callback - * function to fire when an event for that path and selector occurs. - * - * A Subscription also functions to greatly scope an EventPublisher%'s work. - * Using the same filesystem example and the Linux inotify subsystem a - * Subscription limits the number of inode watches to only those requested by - * appropriate EventSubscriber%s. - * Note: EventSubscriber%s and Subscriptions can be configured by the osquery - * user. - * - * Subscriptions are usually created with EventFactory members: - * - * @code{.cpp} - * EventFactory::addSubscription("MyEventPublisher", my_subscription_context); - * @endcode - */ -struct Subscription : private boost::noncopyable { - public: - // EventSubscriber name. - std::string subscriber_name; - - /// An EventPublisher%-specific SubscriptionContext. - SubscriptionContextRef context; - - /// An EventSubscription member EventCallback method. - EventCallback callback; - - explicit Subscription(std::string name) : subscriber_name(std::move(name)){}; - - static SubscriptionRef create(const std::string& name) { - return std::make_shared(name); - } - - static SubscriptionRef create(const std::string& name, - const SubscriptionContextRef& mc, - EventCallback ec = nullptr) { - auto subscription = std::make_shared(name); - subscription->context = mc; - subscription->callback = std::move(ec); - return subscription; - } - - public: - Subscription() = delete; -}; - -class Eventer { - public: - /** - * @brief Request the subscriber's initialization state. - * - * When event subscribers are created (initialized) they are expected to emit - * a set of subscriptions to their publisher "type". If the subscriber fails - * to initialize then the publisher may remove any intermediate subscriptions. - */ - EventState state() const { - return state_; - } - - protected: - /// Set the subscriber state. - void state(EventState state) { - state_ = state; - } - - private: - /// The event subscriber's run state. - EventState state_{EventState::EVENT_NONE}; - - friend class EventFactory; -}; - -class EventPublisherPlugin : public Plugin, - public Eventer { - public: - /** - * @brief A new Subscription was added, potentially change state based on all - * subscriptions for this EventPublisher. - * - * `configure` allows the EventPublisher to optimize on the state of all - * subscriptions. An example is Linux `inotify` where multiple - * EventSubscription%s will subscription identical paths, e.g., /etc for - * config changes. Since Linux `inotify` has a subscription limit, `configure` - * can dedup paths. - */ - void configure() override{}; - - /** - * @brief Perform handle opening, OS API callback registration. - * - * `setUp` is the event framework's EventPublisher constructor equivalent. - * This is called in the main thread before the publisher's run loop has - * started, immediately following registration. - */ - Status setUp() override { - return Status::success(); - } - - /** - * @brief Perform handle closing, resource cleanup. - * - * osquery is about to end, the EventPublisher should close handle descriptors - * unblock resources, and prepare to exit. This will be called from the main - * thread after the run loop thread has exited. - */ - void tearDown() override {} - - /** - * @brief Implement a "step" of an optional run loop. - * - * @return A SUCCESS status will immediately call `run` again. A FAILED status - * will exit the run loop and the thread. - */ - virtual Status run() { - return Status(1, "No run loop required"); - } - - /// This is a plugin type and must implement a call method. - Status call(const PluginRequest& /*request*/, - PluginResponse& /*response*/) override { - return Status(0); - } - - /** - * @brief A new EventSubscriber is subscribing events of this publisher type. - * - * @param subscription The Subscription context information and optional - * EventCallback. - * - * @return If the Subscription is not appropriate (mismatched type) fail. - */ - virtual Status addSubscription(const SubscriptionRef& subscription); - - /// Remove all subscriptions from a named subscriber. - virtual void removeSubscriptions(const std::string& subscriber); - - public: - /// Overriding the EventPublisher constructor is not recommended. - EventPublisherPlugin() = default; - ~EventPublisherPlugin() override = default; - - /// Return a string identifier associated with this EventPublisher. - virtual const std::string type() const { - return getName(); - } - - public: - /// Number of Subscription%s watching this EventPublisher. - size_t numSubscriptions(); - - /** - * @brief The number of events fired by this EventPublisher. - * - * @return The number of events. - */ - EventContextID numEvents() const; - - /// Check if the EventFactory is ending all publisher threads. - bool isEnding() const { - return ending_; - } - - /// Set the ending status for this publisher. - void isEnding(bool ending) { - ending_ = ending; - } - - /// Check if the publisher's run loop has started. - bool hasStarted() const { - return started_; - } - - /// Set the run or started status for this publisher. - void hasStarted(bool started) { - started_ = started; - } - - /// Get the number of publisher restarts. - size_t restartCount() const { - return restart_count_; - } - - public: - explicit EventPublisherPlugin(EventPublisherPlugin const&) = delete; - EventPublisherPlugin& operator=(EventPublisherPlugin const&) = delete; - - protected: - /** - * @brief The generic check loop to call SubscriptionContext callback methods. - * - * It is NOT recommended to override `fire`. The simple logic of enumerating - * the Subscription%s and using `shouldFire` is more appropriate. - * - * @param ec The EventContext created and fired by the EventPublisher. - * @param time The most accurate time associated with the event. - */ - void fire(const EventContextRef& ec, EventTime time = 0); - - /// The internal fire method used by the typed EventPublisher. - virtual void fireCallback(const SubscriptionRef& sub, - const EventContextRef& ec) const = 0; - - /// A lock for subscription manipulation. - mutable Mutex subscription_lock_; - - /// The EventPublisher will keep track of Subscription%s that contain callins. - SubscriptionVector subscriptions_; - - /// An Event ID is assigned by the EventPublisher within the EventContext. - /// This is not used to store event date in the backing store. - std::atomic next_ec_id_{0}; - - private: - /// Set ending to True to cause event type run loops to finish. - std::atomic ending_{false}; - - /// Set to indicate whether the event run loop ever started. - std::atomic started_{false}; - - /// A helper count of event publisher runloop iterations. - std::atomic restart_count_{0}; - - private: - /// Enable event factory "callins" through static publisher callbacks. - friend class EventFactory; - - private: - FRIEND_TEST(EventsTests, test_event_publisher); - FRIEND_TEST(EventsTests, test_fire_event); -}; - -class EventSubscriberPlugin : public Plugin, public Eventer { - public: - /** - * @brief Add Subscription%s to the EventPublisher this module will act on. - * - * When the EventSubscriber%'s `init` method is called you are assured the - * EventPublisher has `setUp` and is ready to subscription for events. - */ - virtual Status init() { - return Status(0); - } - - /// This is a plugin type and must implement a call method. - Status call(const PluginRequest& /*request*/, - PluginResponse& /*response*/) override { - return Status(0); - } - - protected: - /** - * @brief Store parsed event data from an EventCallback in a backing store. - * - * This method stores a single event - * - * @param r The row to add - * - * @return Was the element added to the backing store. - */ - Status add(const Row& r); - - /** - * @brief Store parsed event data from an EventCallback in a backing store. - * - * Within a EventCallback the EventSubscriber has an opportunity to create - * an osquery Row element, add the relevant table data for the EventSubscriber - * and store that element in the osquery backing store. At query-time - * the added data will apply selection criteria and return these elements. - * The backing store data retrieval is optimized by time-based indexes. It - * is important to added EventTime as it relates to "when the event occurred". - * - * @param row_list A (writable) vector of osquery Row elements. - * - * @return Was the element added to the backing store. - */ - Status addBatch(std::vector& row_list); - - private: - /// Overload add for tests and allow them to override the event time. - virtual Status addBatch(std::vector& row_list, - EventTime custom_event_time) final; - - private: - /* - * @brief When `get`ing event results, return EventID%s from time indexes. - * - * Used by EventSubscriber::get to retrieve EventID, EventTime indexes. This - * applies the lookup-efficiency checks for time list appropriate bins. - * If the time range in 24 hours and there is a 24-hour list bin it will - * be queried using a single backing store `Get` followed by two `Get`s of - * the most-specific boundary lists. - * - * @param index the set of index to scan. - * @param optimize if true apply optimization checks. - * - * @return List of EventID, EventTime%s - */ - std::vector getRecords(const std::vector& indexes, - bool optimize = true); - - /** - * @brief Get a unique storage-related EventID. - * - * An EventID is an index/element-identifier for the backing store. - * Each EventPublisher maintains a fired EventContextID to identify the many - * events that may or may not be fired based on subscription criteria for this - * EventSubscriber. This EventContextID is NOT the same as an EventID. - * EventSubscriber development should not require use of EventID%s. If this - * indexing is required within-EventCallback consider an - * EventSubscriber%-unique indexing, counting mechanic. - * - * @return A unique ID for backing storage. - */ - const std::string getEventID(); - - /** - * @brief Plan the best set of indexes for event record access. - * - * @param start an inclusive time to begin searching. - * @param stop an inclusive time to end searching. - * @param sort if true the indexes will be sorted. - * - * @return List of 'index.step' index strings. - */ - std::vector getIndexes(EventTime start, - EventTime stop, - bool sort = true); - - /** - * @brief Expire indexes and eventually records. - * - * @param list_type the string representation of list binning type. - * @param indexes complete set of 'index.step' indexes for the list_type. - * @param expirations of the indexes, the set to expire. - */ - void expireIndexes(const std::string& list_type, - const std::vector& indexes, - const std::vector& expirations); - - /// Expire all datums within a bin. - void expireRecords(const std::string& list_type, - const std::string& index, - bool all); - - /** - * @brief Inspect the number of events, expire those overflowing events_max. - * - * When the event manager starts, or after a checkpoint number of events, - * the EventFactory will call expireCheck for each subscriber. - * - * The subscriber must count the number of buffered records and check if - * that count exceeds the configured `events_max` limit. If an overflow - * occurs the subscriber will expire N-events_max from the end of the queue. - */ - void expireCheck(); - - /** - * @brief Add an EventID, EventTime pair to all matching list types. - * - * The list types are defined by time size. Based on the EventTime this pair - * is added to the list bin for each list type. If there are two list types: - * 60 seconds and 3600 seconds and `time` is 92, this pair will be added to - * list type 1 bin 4 and list type 2 bin 1. - * - * @param event_id_list A vector of (unique) EventIDs - * @param event_time The event time for this batch - * - * @return Were the indexes recorded. - */ - - Status recordEvents(const std::vector& event_id_list, - EventTime event_time); - - /** - * @brief Get the expiration timeout for this event type - * - * The default implementation retrieves this value from FLAGS_events_expiry. - * This method can be overridden to allow custom event expiration timeouts in - * subclasses of EventSubscriberPlugin. - * - * @return The events expiration timeout for this event type - */ - virtual size_t getEventsExpiry(); - - /** - * @brief Get the max number of events for this event type - * - * The default implementation retrieves this value from FLAGS_events_max. - * This method can be overridden to allow custom max event numbers in - * subclasses of EventSubscriberPlugin. - * - * @return The max number of events for this event type - */ - virtual size_t getEventsMax(); - - public: - /** - * @brief A single instance requirement for static callback facilities. - * - * The EventSubscriber constructor is NOT responsible for adding - * Subscription%s. Please use `init` for adding Subscription%s as all - * EventPublisher instances will have run `setUp` and initialized their run - * loops. - */ - EventSubscriberPlugin() - : expire_events_(true), expire_time_(0), optimize_time_(0) {} - ~EventSubscriberPlugin() override = default; - - /// Number of Subscription%s this EventSubscriber has used. - size_t numSubscriptions() const { - return subscription_count_; - } - - /// The number of events this EventSubscriber has received. - EventContextID numEvents() const { - return event_count_; - } - - /// Compare the number of queries run against the queries configured. - bool executedAllQueries() const; - - public: - explicit EventSubscriberPlugin(EventSubscriberPlugin const&) = delete; - EventSubscriberPlugin& operator=(EventSubscriberPlugin const&) = delete; - - protected: - /** - * @brief Backing storage indexing namespace. - * - * The backing storage will accumulate events for this subscriber. A namespace - * is provided to prevent event indexing collisions between subscribers and - * publishers. The namespace is a combination of the publisher and subscriber - * registry plugin names. - */ - /// See getType for lookup rational. - virtual const std::string dbNamespace() const { - return getType() + '.' + getName(); - } - - /// Disable event expiration for this subscriber. - void doNotExpire() { - expire_events_ = false; - } - - /// Trampoline into the EventFactory and lookup the name of the publisher. - virtual const std::string& getType() const = 0; - - /// Get a handle to the EventPublisher. - EventPublisherRef getPublisher() const; - - /// Remove all subscriptions from this subscriber. - void removeSubscriptions(); - - protected: - /// A helper value counting the number of fired events tracked by publishers. - EventContextID event_count_{0}; - - /// A helper value counting the number of subscriptions created. - size_t subscription_count_{0}; - - private: - Status setUp() override { - return Status::success(); - } - - private: - /// Do not respond to periodic/scheduled/triggered event expiration requests. - bool expire_events_{false}; - - /// Events before the expire_time_ are invalid and will be purged. - EventTime expire_time_{0}; - - /// Cached value of last generated EventID. - size_t last_eid_{0}; - - /** - * @brief Optimize subscriber selects by tracking the last select time. - * - * Event subscribers may optimize selects when used in a daemon schedule by - * requiring an event 'time' constraint and otherwise applying a minimum time - * as the last time the scheduled query ran. - */ - EventTime optimize_time_{0}; - - /** - * @brief Last event ID returned while using events-optimization. - * - * A time with second precision is not sufficient, but it works for index - * retrieval. While sorting using the time optimization, discard events - * before or equal to the optimization ID. - */ - size_t optimize_eid_{0}; - - /// The minimum acceptable expiration, based on the query schedule. - std::atomic min_expiration_{0}; - - /// The number of scheduled queries using this subscriber. - std::atomic query_count_{0}; - - /// Set of queries that have used this subscriber table. - std::set queries_; - - /// Lock used when incrementing the EventID database index. - Mutex event_id_lock_; - - /// Lock used when recording an EventID and time into search bins. - Mutex event_record_lock_; - - /// Lock used when recording queries executing against this subscriber. - mutable Mutex event_query_record_; - - private: - friend class EventFactory; - friend class EventPublisherPlugin; - - private: - FRIEND_TEST(EventsDatabaseTests, test_event_module_id); - FRIEND_TEST(EventsDatabaseTests, test_record_indexing); - FRIEND_TEST(EventsDatabaseTests, test_record_range); - FRIEND_TEST(EventsDatabaseTests, test_record_expiration); - FRIEND_TEST(EventsDatabaseTests, test_gentable); - FRIEND_TEST(EventsDatabaseTests, test_expire_check); - FRIEND_TEST(EventsDatabaseTests, test_optimize); - FRIEND_TEST(EventsDatabaseTests, test_record_corruption); - FRIEND_TEST(EventsTests, test_event_subscriber_configure); - friend class DBFakeEventSubscriber; - friend class BenchmarkEventSubscriber; -}; - -/** - * @brief A factory for associating event generators to EventPublisherID%s. - * - * This factory both registers new event types and the subscriptions that use - * them. An EventPublisher is also a factory, the single event factory - * arbitrates Subscription creation and management for each associated - * EventPublisher. - * - * Since event types may be plugins, they are created using the factory. - * Since subscriptions may be configured/disabled they are also factory-managed. - */ -class EventFactory : private boost::noncopyable { - public: - /// Access to the EventFactory instance. - static EventFactory& getInstance(); - - /** - * @brief Add an EventPublisher to the factory. - * - * The registration is mostly abstracted using osquery's registry. - * - * @param pub If for some reason the caller needs access to the - * EventPublisher instance they can register-by-instance. - * - * Access to the EventPublisher instance is not discouraged, but using the - * EventFactory `getEventPublisher` accessor is encouraged. - */ - static Status registerEventPublisher(const PluginRef& pub); - - /** - * @brief Add an EventSubscriber to the factory. - * - * The registration is mostly abstracted using osquery's registry. - */ - template - static Status registerEventSubscriber() { - auto sub = std::make_shared(); - return registerEventSubscriber(sub); - }; - - /** - * @brief Add an EventSubscriber to the factory. - * - * The registration is mostly abstracted using osquery's registry. - * - * @param sub If the caller must access the EventSubscriber instance - * control may be passed to the registry. - * - * Access to the EventSubscriber instance outside of the within-instance - * table generation method and set of EventCallback%s is discouraged. - */ - static Status registerEventSubscriber(const PluginRef& sub); - - /** - * @brief Add a SubscriptionContext and EventCallback Subscription to an - * EventPublisher. - * - * Create a Subscription from a given SubscriptionContext and EventCallback - * and add that Subscription to the EventPublisher associated identifier. - * - * @param type_id ID string for an EventPublisher receiving the Subscription. - * @param name_id ID string for the EventSubscriber. - * @param sc A SubscriptionContext related to the EventPublisher. - * @param cb When the EventPublisher fires an event the SubscriptionContext - * will be evaluated, if the event matches optional specifics in the context - * this callback function will be called. It should belong to an - * EventSubscription. - * - * @return Was the SubscriptionContext appropriate for the EventPublisher. - */ - static Status addSubscription(const std::string& type_id, - const std::string& name_id, - const SubscriptionContextRef& sc, - EventCallback cb = nullptr); - - /// Add a Subscription using a caller Subscription instance. - static Status addSubscription(const std::string& type_id, - const SubscriptionRef& subscription); - - /// Get the total number of Subscription%s across ALL EventPublisher%s. - static size_t numSubscriptions(const std::string& type_id); - - /// Get the number of EventPublishers. - static size_t numEventPublishers() { - return EventFactory::getInstance().event_pubs_.size(); - } - - /** - * @brief Halt the EventPublisher run loop. - * - * Any EventSubscriber%s with Subscription%s for this EventPublisher will - * become useless. osquery callers MUST deregister events. - * EventPublisher%s assume they can hook/trampoline, which requires cleanup. - * This will tear down and remove the publisher if the run loop did not start. - * Otherwise it will call end on the publisher and assume the run loop will - * tear down and remove. - * - * @param pub The string label for the EventPublisher. - * - * @return Did the EventPublisher deregister cleanly. - */ - static Status deregisterEventPublisher(const EventPublisherRef& pub); - - /// Deregister an EventPublisher by publisher name. - static Status deregisterEventPublisher(const std::string& type_id); - - /// Deregister an EventSubscriber by the subscriber name. - static Status deregisterEventSubscriber(const std::string& sub); - - /// Return an instance to a registered EventPublisher. - static EventPublisherRef getEventPublisher(const std::string& pub); - - /// Return an instance to a registered EventSubscriber. - static EventSubscriberRef getEventSubscriber(const std::string& sub); - - /// Check if an event subscriber exists. - static bool exists(const std::string& sub); - - /// Return a list of publisher types, these are their registry names. - static std::vector publisherTypes(); - - /// Return a list of subscriber registry names, - static std::vector subscriberNames(); - - /// Set log forwarding by adding a logger receiver. - static void addForwarder(const std::string& logger); - - /// Optionally forward events to loggers. - static void forwardEvent(const std::string& event); - - /** - * @brief The event factory, subscribers, and publishers respond to updates. - * - * This should be called by the Config instance when configuration data is - * updated. It is separate from the config parser that takes configuration - * information specific to events and acts. This allows the event factory - * to make changes relative to the schedule or packs. - */ - static void configUpdate(); - - public: - /// The dispatched event thread's entry-point (if needed). - static Status run(const std::string& type_id); - - /// An initializer's entry-point for spawning all event type run loops. - static void delay(); - - /// If a static EventPublisher callback wants to fire - template - static void fire(const EventContextRef& ec) { - auto event_pub = getEventPublisher(getType()); - event_pub->fire(ec); - } - - /** - * @brief Return the publisher registry name given a type. - * - * Subscriber initialization and runtime static callbacks can lookup the - * publisher type name, which is the registry plugin name. This allows static - * callbacks to fire into subscribers. - */ - template - static const std::string getType() { - auto pub = std::make_shared(); - return pub->type(); - } - - /** - * @brief End all EventPublisher run loops and deregister. - * - * End is NOT the same as deregistration. End will call deregister on all - * publishers then either join or detach their run loop threads. - * See EventFactory::deregisterEventPublisher for actions taken during - * deregistration. - * - * @param join if true, threads will be joined - */ - static void end(bool join = false); - - public: - EventFactory(EventFactory const&) = delete; - EventFactory& operator=(EventFactory const&) = delete; - - private: - /// An EventFactory will exist for the lifetime of the application. - EventFactory() = default; - ~EventFactory() = default; - - private: - /// Set of registered EventPublisher instances. - std::map event_pubs_; - - /// Set of instantiated EventSubscriber subscriptions. - std::map event_subs_; - - /// Set of running EventPublisher run loop threads. - std::vector> threads_; - - /// Set of logger plugins to forward events. - std::vector loggers_; - - /// Factory publisher state manipulation. - Mutex factory_lock_; -}; - -/** - * @brief Generate OS events of a type (FS, Network, Syscall, ioctl). - * - * A 'class' of OS events is abstracted into an EventPublisher responsible for - * remaining as agile as possible given a known-set of subscriptions. - * - * The life cycle of an EventPublisher may include, `setUp`, `configure`, `run`, - * `tearDown`, and `fire`. `setUp` and `tearDown` happen when osquery starts and - * stops either as a daemon or interactive shell. `configure` is a pseudo-start - * called every time a Subscription is added. EventPublisher%s can adjust their - * scope/agility specific to each added subscription by overriding - *`addSubscription`, and/or globally in `configure`. - * - * Not all EventPublisher%s leverage pure async OS APIs, and most will require a - * run loop either polling with a timeout on a descriptor or for a change. When - * osquery initializes the EventFactory will optionally create a thread for each - * EventPublisher using `run` as the thread's entrypoint. `run` is called in a - * within-thread loop where returning a FAILED status ends the run loop and - * shuts down the thread. - * - * To opt-out of polling in a thread, consider the following run implementation: - * - * @code{.cpp} - * Status run() { return Status(1, "Not Implemented"); } - * @endcode - * - * The final life cycle component, `fire` will iterate over the EventPublisher - * Subscription%s and call `shouldFire` for each, using the EventContext fired. - * The `shouldFire` method should check the subscription-specific selectors and - * only call the Subscription%'s callback function if the EventContext - * (thus event) matches. - */ -template -class EventPublisher : public EventPublisherPlugin { - public: - /// A nested helper typename for the templated SubscriptionContextRef. - using SCRef = typename std::shared_ptr; - /// A nested helper typename for the templated EventContextRef. - using ECRef = typename std::shared_ptr; - - public: - EventPublisher() = default; - ~EventPublisher() override = default; - - /// Up-cast a base EventContext reference to the templated ECRef. - static ECRef getEventContext(const EventContextRef& ec) { - return std::static_pointer_cast(ec); - }; - - /// Up-cast a base SubscriptionContext reference to the templated SCRef. - static SCRef getSubscriptionContext(const SubscriptionContextRef& sc) { - return std::static_pointer_cast(sc); - } - - /// Create a EventContext based on the templated type. - static ECRef createEventContext() { - return std::make_shared(); - } - - /// Create a SubscriptionContext based on the templated type. - static SCRef createSubscriptionContext() { - return std::make_shared(); - } - - protected: - /** - * @brief The internal `fire` phase of publishing. - * - * This is a template-generated method that up-casts the generic fired - * event/subscription contexts, and calls the callback if the event should - * fire given a subscription. - * - * @param sub The SubscriptionContext and optional EventCallback. - * @param ec The event that was fired. - */ - void fireCallback(const SubscriptionRef& sub, - const EventContextRef& ec) const override { - auto pub_sc = getSubscriptionContext(sub->context); - auto pub_ec = getEventContext(ec); - if (shouldFire(pub_sc, pub_ec) && sub->callback != nullptr) { - sub->callback(pub_ec, pub_sc); - } - } - - protected: - /** - * @brief The generic `fire` will call `shouldFire` for each Subscription. - * - * @param sc A SubscriptionContext with optional specifications for events - * details. - * @param ec The event fired with event details. - * - * @return should the Subscription%'s EventCallback be called for this event. - */ - virtual bool shouldFire(const SCRef& sc, const ECRef& ec) const { - (void)sc; - (void)ec; - return true; - } - - private: - FRIEND_TEST(EventsTests, test_event_subscriber_subscribe); - FRIEND_TEST(EventsTests, test_event_subscriber_context); - FRIEND_TEST(EventsTests, test_fire_event); -}; - -/** - * @brief An interface binding Subscriptions, event response, and table - *generation. - * - * Use the EventSubscriber interface when adding event subscriptions and - * defining callin functions. The EventCallback is usually a member function - * for an EventSubscriber. The EventSubscriber interface includes a very - * important `add` method that abstracts the needed event to backing store - * interaction. - * - * Storing event data in the backing store must match a table spec for queries. - * Small overheads exist that help query-time indexing and lookups. - */ -template -class EventSubscriber : public EventSubscriberPlugin { - protected: - using SCRef = typename PUB::SCRef; - using ECRef = typename PUB::ECRef; - - public: - /** - * @brief The registry plugin name for the subscriber's publisher. - * - * During event factory initialization the subscribers 'peek' at the registry - * plugin name assigned to publishers. The corresponding publisher name is - * interpreted as the subscriber's event 'type'. - */ - const std::string& getType() const override { - static const std::string type = EventFactory::getType(); - return type; - }; - - protected: - /// Helper function to call the publisher's templated subscription generator. - SCRef createSubscriptionContext() const { - return PUB::createSubscriptionContext(); - } - - /** - * @brief Bind a registered EventSubscriber member function to a Subscription. - * - * @param entry A templated EventSubscriber member function. - * @param sc The subscription context. - */ - template - void subscribe(Status (T::*entry)(const std::shared_ptr&, const SCRef&), - const SCRef& sc) { - using std::placeholders::_1; - using std::placeholders::_2; - using CallbackFunc = - Status (T::*)(const EventContextRef&, const SubscriptionContextRef&); - - // Down-cast the pointer to the member function. - auto base_entry = reinterpret_cast(entry); - // Up-cast the EventSubscriber to the caller. - auto sub = dynamic_cast(this); - if (base_entry != nullptr && sub != nullptr) { - // Create a callable through the member function using the instance of the - // EventSubscriber and a single parameter placeholder (the EventContext). - auto cb = std::bind(base_entry, sub, _1, _2); - // Add a subscription using the callable and SubscriptionContext. - Status stat = - EventFactory::addSubscription(sub->getType(), sub->getName(), sc, cb); - if (stat.ok()) { - subscription_count_++; - } - } - } - - public: - explicit EventSubscriber(bool enabled = true) - : EventSubscriberPlugin(), disabled(!enabled) {} - ~EventSubscriber() override = default; - - protected: - /** - * @brief Allow subscriber implementations to default disable themselves. - * - * A subscriber may induce latency on a system within the callback routines. - * Before the initialization and set up is performed the EventFactory can - * choose to exclude a subscriber if it is not explicitly enabled within - * the config. - * - * EventSubscriber%s that should be default-disabled should set this flag - * in their constructor or worst case before EventSubsciber::init. - */ - bool disabled{false}; - - private: - friend class EventFactory; - - private: - FRIEND_TEST(EventsTests, test_event_sub); - FRIEND_TEST(EventsTests, test_event_sub_subscribe); - FRIEND_TEST(EventsTests, test_event_sub_context); - FRIEND_TEST(EventsTests, test_event_toggle_subscribers); -}; - -/// Iterate the event publisher registry and create run loops for each using -/// the event factory. -void attachEvents(); -} // namespace osquery diff --git a/src/osquery/logger/logger.cpp b/src/osquery/logger/logger.cpp index 55aa29e..c41e3c9 100644 --- a/src/osquery/logger/logger.cpp +++ b/src/osquery/logger/logger.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -43,15 +42,6 @@ FLAG(bool, disable_logging, false, "Disable ERROR/INFO logging"); FLAG(string, logger_plugin, "filesystem", "Logger plugin name"); -/// Log each added or removed line individually, as an "event". -FLAG(bool, logger_event_type, true, "Log scheduled results as events"); - -/// Log each row from a snapshot query individually, as an "event". -FLAG(bool, - logger_snapshot_event_type, - false, - "Log scheduled snapshot results as events"); - /// Alias for the minloglevel used internally by GLOG. FLAG(int32, logger_min_status, 0, "Minimum level for status log recording"); @@ -274,10 +264,6 @@ void initLogger(const std::string& name) { // return a success status after initialization. BufferedLogSink::get().addPlugin(logger); } - - if ((status.getCode() & LOGGER_FEATURE_LOGEVENT) > 0) { - EventFactory::addForwarder(logger); - } } if (forward) { @@ -408,13 +394,10 @@ Status logQueryLogItem(const QueryLogItem& results, std::vector json_items; Status status; - if (FLAGS_logger_event_type) { - status = serializeQueryLogItemAsEventsJSON(results, json_items); - } else { - std::string json; - status = serializeQueryLogItemJSON(results, json); - json_items.emplace_back(json); - } + std::string json; + status = serializeQueryLogItemJSON(results, json); + json_items.emplace_back(json); + if (!status.ok()) { return status; } @@ -432,13 +415,10 @@ Status logSnapshotQuery(const QueryLogItem& item) { std::vector json_items; Status status; - if (FLAGS_logger_snapshot_event_type) { - status = serializeQueryLogItemAsEventsJSON(item, json_items); - } else { - std::string json; - status = serializeQueryLogItemJSON(item, json); - json_items.emplace_back(json); - } + std::string json; + status = serializeQueryLogItemJSON(item, json); + json_items.emplace_back(json); + if (!status.ok()) { return status; } diff --git a/src/osquery/logger/tests/logger.cpp b/src/osquery/logger/tests/logger.cpp index df511bb..83b2c54 100644 --- a/src/osquery/logger/tests/logger.cpp +++ b/src/osquery/logger/tests/logger.cpp @@ -26,8 +26,6 @@ DECLARE_int32(logger_min_status); DECLARE_int32(logger_min_stderr); DECLARE_bool(logger_secondary_status_only); DECLARE_bool(logger_status_sync); -DECLARE_bool(logger_event_type); -DECLARE_bool(logger_snapshot_event_type); DECLARE_bool(disable_logging); DECLARE_bool(log_numerics_as_numbers); @@ -284,10 +282,8 @@ TEST_F(LoggerTests, test_logger_snapshots) { logSnapshotQuery(item); EXPECT_EQ(2U, LoggerTests::snapshot_rows_added); - FLAGS_logger_snapshot_event_type = true; logSnapshotQuery(item); EXPECT_EQ(4U, LoggerTests::snapshot_rows_added); - FLAGS_logger_snapshot_event_type = false; } class SecondTestLoggerPlugin : public LoggerPlugin { @@ -357,11 +353,9 @@ TEST_F(LoggerTests, test_logger_scheduled_query) { EXPECT_EQ(1U, LoggerTests::log_lines.size()); // The entire removed/added is one event when result events is false. - FLAGS_logger_event_type = false; item.results.removed.push_back({{"test_column", "test_new_value\n"}}); logQueryLogItem(item); EXPECT_EQ(2U, LoggerTests::log_lines.size()); - FLAGS_logger_event_type = true; // Now the two removed will be individual events. logQueryLogItem(item); diff --git a/src/osquery/main/main.cpp b/src/osquery/main/main.cpp index aa10f0e..1b954ba 100644 --- a/src/osquery/main/main.cpp +++ b/src/osquery/main/main.cpp @@ -91,7 +91,6 @@ int startShell(osquery::Initializer& runner, int argc, char* argv[]) { !osquery::FLAGS_A.empty() || !osquery::FLAGS_pack.empty() || osquery::FLAGS_L || osquery::FLAGS_profile > 0) { // A query was set as a positional argument, via stdin, or profiling is on. - osquery::FLAGS_disable_events = true; osquery::FLAGS_disable_caching = true; } diff --git a/src/osquery/sql/virtual_table.cpp b/src/osquery/sql/virtual_table.cpp index ebddd4c..592a69a 100644 --- a/src/osquery/sql/virtual_table.cpp +++ b/src/osquery/sql/virtual_table.cpp @@ -31,8 +31,6 @@ FLAG(uint64, SHELL_FLAG(bool, planner, false, "Enable osquery runtime planner output"); -DECLARE_bool(disable_events); - RecursiveMutex kAttachMutex; namespace tables { @@ -844,8 +842,7 @@ static int xFilter(sqlite3_vtab_cursor* pVtabCursor, // For event-based tables, help the caller if events are disabled. bool events_satisfied = - ((content->attributes & TableAttributes::EVENT_BASED) == 0 || - !FLAGS_disable_events); + ((content->attributes & TableAttributes::EVENT_BASED) == 0); std::map options; for (size_t i = 0; i < content->columns.size(); ++i) { diff --git a/src/osquery/tests/test_util.cpp b/src/osquery/tests/test_util.cpp index 2102794..0078732 100644 --- a/src/osquery/tests/test_util.cpp +++ b/src/osquery/tests/test_util.cpp @@ -130,12 +130,4 @@ ScheduledQuery getOsqueryScheduledQuery() { return sq; } -TableRows genRows(EventSubscriberPlugin* sub) { - auto vtc = std::make_shared(); - QueryContext context(vtc); - - TableRows results; - return results; -} - } // namespace osquery diff --git a/src/osquery/tests/test_util.h b/src/osquery/tests/test_util.h index 4de9428..8edb254 100644 --- a/src/osquery/tests/test_util.h +++ b/src/osquery/tests/test_util.h @@ -14,7 +14,6 @@ #include #include -#include #include namespace osquery { @@ -67,7 +66,4 @@ extern const size_t kExpectedExtensionArgsCount; ScheduledQuery getOsqueryScheduledQuery(); -// Helper function to generate all rows from a generator-based table. -TableRows genRows(EventSubscriberPlugin* sub); - } // namespace osquery diff --git a/tools/codegen/templates/amalgamation.cpp.in b/tools/codegen/templates/amalgamation.cpp.in index a0d2633..0ee9393 100644 --- a/tools/codegen/templates/amalgamation.cpp.in +++ b/tools/codegen/templates/amalgamation.cpp.in @@ -10,7 +10,6 @@ ** This file is generated. Do not modify it manually! */ -#include #include #include #include diff --git a/tools/codegen/templates/default.cpp.in b/tools/codegen/templates/default.cpp.in index 574ce0d..d5be51a 100644 --- a/tools/codegen/templates/default.cpp.in +++ b/tools/codegen/templates/default.cpp.in @@ -25,7 +25,6 @@ ** This file is generated. Do not modify it manually! */ -#include #include #include #include @@ -133,16 +132,7 @@ class {{table_name_cc}}TablePlugin : public TablePlugin { bool usesGenerator() const override { return true; } void generator(RowYield& yield, QueryContext& context) override { -{% if class_name != "" %}\ - if (EventFactory::exists(getName())) { - auto subscriber = EventFactory::getEventSubscriber(getName()); - return subscriber->{{function}}(yield, context); - } else { - LOG(ERROR) << "Subscriber table missing: " << getName(); - } -{% else %}\ tables::{{function}}(yield, context); -{% endif %}\ } {% else %}\ TableRows generate(QueryContext& context) override { diff --git a/tools/codegen/templates/foreign.cpp.in b/tools/codegen/templates/foreign.cpp.in index a9c4748..45ce8cd 100644 --- a/tools/codegen/templates/foreign.cpp.in +++ b/tools/codegen/templates/foreign.cpp.in @@ -10,7 +10,6 @@ ** This file is generated. Do not modify it manually! */ -#include #include #include #include -- 2.34.1