From 73d8e0850561559fa42389e005c5745a2a95dd47 Mon Sep 17 00:00:00 2001 From: Tad Glines Date: Tue, 1 Sep 2020 12:11:41 -0700 Subject: [PATCH] Set cgroup defaults, add some audit multicast support --- CMakeLists.txt | 1 + CPULimits.cpp | 10 ++++----- CPULimits.h | 3 +++ Gate.h | 8 ++++++- KernelInfo.cpp | 2 ++ KernelInfo.h | 4 +++- Netlink.cpp | 30 ++++++++++++++++++++++++++- Netlink.h | 3 ++- auoms.cpp | 10 +++++++++ auomscollect.cpp | 10 +++++++++ auomsctl.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++--- 11 files changed, 122 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6d6b05..7dfbf47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,6 +229,7 @@ add_executable(auomsctl UnixDomainListener.cpp Event.cpp UserDB.cpp + KernelInfo.cpp ) # See https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html diff --git a/CPULimits.cpp b/CPULimits.cpp index f70726e..1014224 100644 --- a/CPULimits.cpp +++ b/CPULimits.cpp @@ -17,16 +17,14 @@ #include "CPULimits.h" #define CG_NAME_CONFIG_NAME "cpu_cgroup_name" -#define HARD_LIMIT_NAME "cpu_per_core_limit" -#define SOFT_LIMIT_NAME "cpu_soft_limit" std::shared_ptr CPULimits::CGFromConfig(const Config& config, const std::string& default_cg_name) { std::string cg_name = default_cg_name; double hard_limit = MAX_PCT; double soft_limit = MAX_PCT; - if (config.HasKey(HARD_LIMIT_NAME)) { - hard_limit = config.GetDouble(HARD_LIMIT_NAME); + if (config.HasKey(CPU_HARD_LIMIT_NAME)) { + hard_limit = config.GetDouble(CPU_HARD_LIMIT_NAME); } if (hard_limit > MAX_PCT) { @@ -35,8 +33,8 @@ std::shared_ptr CPULimits::CGFromConfig(const Config& config, const s hard_limit = MIN_PCT; } - if (config.HasKey(SOFT_LIMIT_NAME)) { - soft_limit = config.GetDouble(SOFT_LIMIT_NAME); + if (config.HasKey(CPU_SOFT_LIMIT_NAME)) { + soft_limit = config.GetDouble(CPU_SOFT_LIMIT_NAME); } if (soft_limit > MAX_PCT) { diff --git a/CPULimits.h b/CPULimits.h index 88911b2..3a6668a 100644 --- a/CPULimits.h +++ b/CPULimits.h @@ -20,6 +20,9 @@ #include "Config.h" #include "CGroups.h" +#define CPU_HARD_LIMIT_NAME "cpu_per_core_limit" +#define CPU_SOFT_LIMIT_NAME "cpu_soft_limit" + class CPULimits { public: static constexpr double MAX_PCT = 100.0; diff --git a/Gate.h b/Gate.h index 7cb2ad7..4d746f9 100644 --- a/Gate.h +++ b/Gate.h @@ -50,7 +50,13 @@ public: // Return true if desired state reached, false on timeout bool Wait(state_t state, int timeout) { std::unique_lock lock(_mutex); - return _cond.wait_for(lock, std::chrono::milliseconds(timeout), [this,state]() { return _state == state; }); + if (timeout < 0) { + _cond.wait(lock, [this, state]() { return _state == state; }); + return true; + } else { + return _cond.wait_for(lock, std::chrono::milliseconds(timeout), + [this, state]() { return _state == state; }); + } } private: diff --git a/KernelInfo.cpp b/KernelInfo.cpp index 4eceb95..d869d36 100644 --- a/KernelInfo.cpp +++ b/KernelInfo.cpp @@ -29,6 +29,7 @@ #define MINIMUM_INTERFIELD_COMPARE_VERSION "3.10" #define MINIMUM_EXE_FIELD_VERSION "4.4" #define MINIMUM_SESSIONID_FIELD_VERSION "4.10" +#define MINIMUM_AUDIT_MULTICAST_VERSION "3.16" static std::once_flag s_init_flag; @@ -59,6 +60,7 @@ void KernelInfo::load() noexcept { _compare = kver >= Version(MINIMUM_INTERFIELD_COMPARE_VERSION); _exe_field = kver >= Version(MINIMUM_EXE_FIELD_VERSION); _session_id_field = kver >= Version(MINIMUM_SESSIONID_FIELD_VERSION); + _audit_multicast = kver >= Version(MINIMUM_AUDIT_MULTICAST_VERSION); std::string config_path = "/boot/config-" + _kver; try { diff --git a/KernelInfo.h b/KernelInfo.h index 358e428..1858db9 100644 --- a/KernelInfo.h +++ b/KernelInfo.h @@ -33,9 +33,10 @@ public: static bool HasAuditInterfieldCompare() { return ptr()->_compare; }; static bool HasAuditExeField() { return ptr()->_exe_field; }; static bool HasAuditSessionIdField() { return ptr()->_session_id_field; }; + static bool HasAuditMulticast() { return ptr()->_audit_multicast; }; private: - KernelInfo(): _kver(), _is_64bit(false), _syscall(false), _compare(false), _exe_field(false), _session_id_field(false) {}; + KernelInfo(): _kver(), _is_64bit(false), _syscall(false), _compare(false), _exe_field(false), _session_id_field(false), _audit_multicast(false) {}; static void init(); static KernelInfo* ptr(); @@ -49,6 +50,7 @@ private: bool _compare; bool _exe_field; bool _session_id_field; + bool _audit_multicast; }; diff --git a/Netlink.cpp b/Netlink.cpp index 1288c0d..55213ea 100644 --- a/Netlink.cpp +++ b/Netlink.cpp @@ -30,7 +30,7 @@ #define SOL_NETLINK 270 #endif -int Netlink::Open(reply_fn_t&& default_msg_handler_fn) { +int Netlink::Open(reply_fn_t&& default_msg_handler_fn, bool multicast) { std::unique_lock _lock(_run_mutex); if (_start) { @@ -51,6 +51,33 @@ int Netlink::Open(reply_fn_t&& default_msg_handler_fn) { return -saved_errno; } + sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + if (multicast) { + addr.nl_groups = 1; // AUDIT_NLGRP_READLOG + } else { + addr.nl_groups = 0; + } + + if (bind(fd, reinterpret_cast(&addr), sizeof(addr)) != 0) { + auto saved_errno = errno; + Logger::Error("Failed to bind NETLINK socket: %s", std::strerror(errno)); + close(fd); + return -saved_errno; + } + + socklen_t addr_len = sizeof(addr); + if (getsockname(fd, reinterpret_cast(&addr), &addr_len) != 0) { + auto saved_errno = errno; + Logger::Error("Failed to get assigned NETLINK 'port': %s", std::strerror(errno)); + close(fd); + return -saved_errno; + } + + _pid = addr.nl_pid; + int on = 1; if (setsockopt(fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(on)) != 0) { Logger::Error("Cannot set NETLINK_NO_ENOBUFS option on audit NETLINK socket: %s", std::strerror(errno)); @@ -94,6 +121,7 @@ int Netlink::Send(uint16_t type, const void* data, size_t len, reply_fn_t&& repl } while (_replies.count(seq) > 0 || _known_seq.count(seq) > 0); nl->nlmsg_seq = seq; + nl->nlmsg_pid = _pid; if (data != nullptr && len > 0) { nl->nlmsg_len = static_cast(NLMSG_SPACE(len)); diff --git a/Netlink.h b/Netlink.h index 1885038..0390e25 100644 --- a/Netlink.h +++ b/Netlink.h @@ -44,7 +44,7 @@ public: * If request fails for another reason will return -errno */ - int Open(reply_fn_t&& default_msg_handler_fn); + int Open(reply_fn_t&& default_msg_handler_fn, bool multicast = false); void Close(); int Send(uint16_t type, const void* data, size_t len, reply_fn_t&& reply_fn); @@ -102,6 +102,7 @@ private: void handle_msg(uint16_t msg_type, uint16_t msg_flags, uint32_t msg_seq, const void* payload_data, size_t payload_len); int _fd; + uint32_t _pid; volatile uint32_t _sequence; reply_fn_t _default_msg_handler_fn; bool _quite; diff --git a/auoms.cpp b/auoms.cpp index 3c8bd87..1727f73 100644 --- a/auoms.cpp +++ b/auoms.cpp @@ -274,6 +274,16 @@ int main(int argc, char**argv) { Logger::OpenSyslog("auoms", LOG_DAEMON); } + // Set cgroup defaults + if (!config.HasKey(CPU_SOFT_LIMIT_NAME)) { + config.SetString(CPU_SOFT_LIMIT_NAME, "5"); + } + + if (!config.HasKey(CPU_HARD_LIMIT_NAME)) { + config.SetString(CPU_HARD_LIMIT_NAME, "25"); + } + + // Set EventPrioritizer defaults if (!config.HasKey("event_priority_by_syscall")) { config.SetString("event_priority_by_syscall", R"json({"execve":2,"execveat":2,"*":3})json"); } diff --git a/auomscollect.cpp b/auomscollect.cpp index e180508..d30eca9 100644 --- a/auomscollect.cpp +++ b/auomscollect.cpp @@ -457,6 +457,16 @@ int main(int argc, char**argv) { Logger::OpenSyslog("auomscollect", LOG_DAEMON); } + // Set cgroup defaults + if (!config.HasKey(CPU_SOFT_LIMIT_NAME)) { + config.SetString(CPU_SOFT_LIMIT_NAME, "3"); + } + + if (!config.HasKey(CPU_HARD_LIMIT_NAME)) { + config.SetString(CPU_HARD_LIMIT_NAME, "20"); + } + + // Set EventPrioritizer defaults if (!config.HasKey("event_priority_by_syscall")) { config.SetString("event_priority_by_syscall", R"json({"execve":2,"execveat":2,"*":3})json"); } diff --git a/auomsctl.cpp b/auomsctl.cpp index 8c6e001..2ec4479 100644 --- a/auomsctl.cpp +++ b/auomsctl.cpp @@ -39,6 +39,7 @@ #include #include "env_config.h" +#include "KernelInfo.h" #define AUOMS_SERVICE_NAME "auoms" #define AUDITD_SERVICE_NAME "auditd" @@ -1164,6 +1165,50 @@ int tap_audit() { return 0; } +/********************************************************************************************************************** + ** + *********************************************************************************************************************/ + +int tap_audit_multicast() { + if (!check_permissions()) { + return 1; + } + + try { + auto ki = KernelInfo::GetKernelInfo(); + if (!ki.HasAuditMulticast()) { + Logger::Error("Audit multicast not supported in kerenel version %s", ki.KernelVersion().c_str()); + return 1; + } + } catch (std::exception &ex) { + Logger::Error("Failed to determine if audit multicast is supported: %s", ex.what()); + } + + Netlink netlink; + Gate _stop_gate; + + std::function handler = [](uint16_t type, uint16_t flags, const void* data, size_t len) -> bool { + if (type >= AUDIT_FIRST_USER_MSG) { + std::cout << "type=" << RecordTypeToName(static_cast(type)) << " " << std::string_view(reinterpret_cast(data), len) << std::endl; + } + return false; + }; + + Logger::Info("Connecting to AUDIT NETLINK socket"); + auto ret = netlink.Open(std::move(handler), true); + if (ret != 0) { + Logger::Error("Failed to open AUDIT NETLINK connection: %s", std::strerror(-ret)); + return 1; + } + Defer _close_netlink([&netlink]() { netlink.Close(); }); + + Signals::SetExitHandler([&_stop_gate]() { _stop_gate.Open(); }); + + _stop_gate.Wait(Gate::OPEN, -1); + + return 0; +} + /********************************************************************************************************************** ** *********************************************************************************************************************/ @@ -1735,23 +1780,26 @@ int main(int argc, char**argv) { return disable_auoms(); } else if (strcmp(argv[1], "start") == 0) { bool all = false; - if (argc > 2 && strcmp(argv[1], "all") == 0) { + if (argc > 2 && strcmp(argv[2], "all") == 0) { all = true; } return start_auoms(all); } else if (strcmp(argv[1], "restart") == 0) { bool all = false; - if (argc > 2 && strcmp(argv[1], "all") == 0) { + if (argc > 2 && strcmp(argv[2], "all") == 0) { all = true; } return restart_auoms(all); } else if (strcmp(argv[1], "stop") == 0) { bool all = false; - if (argc > 2 && strcmp(argv[1], "all") == 0) { + if (argc > 2 && strcmp(argv[2], "all") == 0) { all = true; } return stop_auoms(all); } else if (strcmp(argv[1], "tap") == 0) { + if (argc > 2 && strcmp(argv[2], "multicast") == 0) { + return tap_audit_multicast(); + } return tap_audit(); } else if (strcmp(argv[1], "monitor") == 0) { return monitor_auoms_events();