// SPDX-License-Identifier: Apache-2.0 /* Copyright (C) 2024 The Falco Authors. 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. */ #include "indexable_ruleset.h" #include "falco_utils.h" #include void indexable_ruleset::clear() { for(size_t i = 0; i < m_rulesets.size(); i++) { m_rulesets[i] = std::make_shared(i); } m_filters.clear(); } uint64_t indexable_ruleset::enabled_count(uint16_t ruleset_id) { while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } return m_rulesets[ruleset_id]->num_filters(); } void indexable_ruleset::enabled_evttypes(std::set &evttypes, uint16_t ruleset_id) { evttypes.clear(); for(const auto &e : enabled_event_codes(ruleset_id)) { evttypes.insert((uint16_t)e); } } libsinsp::events::set indexable_ruleset::enabled_sc_codes(uint16_t ruleset) { if(m_rulesets.size() < (size_t)ruleset + 1) { return {}; } return m_rulesets[ruleset]->sc_codes(); } libsinsp::events::set indexable_ruleset::enabled_event_codes(uint16_t ruleset) { if(m_rulesets.size() < (size_t)ruleset + 1) { return {}; } return m_rulesets[ruleset]->event_codes(); } void indexable_ruleset::enable(const std::string &pattern, match_type match, uint16_t ruleset_id) { enable_disable(pattern, match, true, ruleset_id); } void indexable_ruleset::disable(const std::string &pattern, match_type match, uint16_t ruleset_id) { enable_disable(pattern, match, false, ruleset_id); } void indexable_ruleset::enable_disable(const std::string &pattern, match_type match, bool enabled, uint16_t ruleset_id) { while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } for(const auto &wrap : m_filters) { bool matches; std::string::size_type pos; switch(match) { case match_type::exact: pos = wrap->name().find(pattern); matches = (pattern == "" || (pos == 0 && pattern.size() == wrap->name().size())); break; case match_type::substring: matches = (pattern == "" || (wrap->name().find(pattern) != std::string::npos)); break; case match_type::wildcard: matches = falco::utils::matches_wildcard(pattern, wrap->name()); break; default: // should never happen matches = false; } if(matches) { if(enabled) { m_rulesets[ruleset_id]->add_filter(wrap); } else { m_rulesets[ruleset_id]->remove_filter(wrap); } } } } void indexable_ruleset::enable_tags(const std::set &tags, uint16_t ruleset_id) { enable_disable_tags(tags, true, ruleset_id); } void indexable_ruleset::disable_tags(const std::set &tags, uint16_t ruleset_id) { enable_disable_tags(tags, false, ruleset_id); } void indexable_ruleset::enable_disable_tags(const std::set &tags, bool enabled, uint16_t ruleset_id) { while(m_rulesets.size() < (size_t)ruleset_id + 1) { m_rulesets.emplace_back(std::make_shared(m_rulesets.size())); } for(const auto &wrap : m_filters) { std::set intersect; set_intersection(tags.begin(), tags.end(), wrap->tags().begin(), wrap->tags().end(), inserter(intersect, intersect.begin())); if(!intersect.empty()) { if(enabled) { m_rulesets[ruleset_id]->add_filter(wrap); } else { m_rulesets[ruleset_id]->remove_filter(wrap); } } } } bool indexable_ruleset::run(sinsp_evt *evt, falco_rule &match, uint16_t ruleset_id) { if(m_rulesets.size() < (size_t)ruleset_id + 1) { return false; } return m_rulesets[ruleset_id]->run(*this, evt, match); } bool indexable_ruleset::run(sinsp_evt *evt, std::vector &matches, uint16_t ruleset_id) { if(m_rulesets.size() < (size_t)ruleset_id + 1) { return false; } return m_rulesets[ruleset_id]->run(*this, evt, matches); } void indexable_ruleset::add_wrapper(std::shared_ptr wrap) { m_filters.insert(wrap); } uint64_t indexable_ruleset::iterate(filter_wrapper_func func) { uint64_t num_filters = 0; for(const auto &ruleset_ptr : m_rulesets) { if(ruleset_ptr) { for(const auto &wrap : ruleset_ptr->get_filters()) { num_filters++; func(wrap); } } } return num_filters; } void indexable_ruleset::ruleset_filters::add_wrapper_to_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) { // This is O(n) but it's also uncommon // (when loading rules only). auto pos = std::find(wrappers.begin(), wrappers.end(), wrap); if(pos == wrappers.end()) { wrappers.push_back(wrap); } } void indexable_ruleset::ruleset_filters::remove_wrapper_from_list(filter_wrapper_list &wrappers, std::shared_ptr wrap) { // This is O(n) but it's also uncommon // (when loading rules only). auto pos = std::find(wrappers.begin(), wrappers.end(), wrap); if(pos != wrappers.end()) { wrappers.erase(pos); } } void indexable_ruleset::ruleset_filters::add_filter(std::shared_ptr wrap) { if(wrap->event_codes().empty()) { // Should run for all event types add_wrapper_to_list(m_filter_all_event_types, wrap); } else { for(auto &etype : wrap->event_codes()) { if(m_filter_by_event_type.size() <= etype) { m_filter_by_event_type.resize(etype + 1); } add_wrapper_to_list(m_filter_by_event_type[etype], wrap); } } m_filters.insert(wrap); } void indexable_ruleset::ruleset_filters::remove_filter(std::shared_ptr wrap) { if(wrap->event_codes().empty()) { remove_wrapper_from_list(m_filter_all_event_types, wrap); } else { for(auto &etype : wrap->event_codes()) { if(etype < m_filter_by_event_type.size()) { remove_wrapper_from_list(m_filter_by_event_type[etype], wrap); } } } m_filters.erase(wrap); } uint64_t indexable_ruleset::ruleset_filters::num_filters() { return m_filters.size(); } bool indexable_ruleset::ruleset_filters::run(indexable_ruleset &ruleset, sinsp_evt *evt, falco_rule &match) { if(evt->get_type() < m_filter_by_event_type.size() && m_filter_by_event_type[evt->get_type()].size() > 0) { if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, match)) { return true; } } // Finally, try filters that are not specific to an event type. if(m_filter_all_event_types.size() > 0) { if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, match)) { return true; } } return false; } bool indexable_ruleset::ruleset_filters::run(indexable_ruleset &ruleset, sinsp_evt *evt, std::vector &matches) { if(evt->get_type() < m_filter_by_event_type.size() && m_filter_by_event_type[evt->get_type()].size() > 0) { if(ruleset.run_wrappers(evt, m_filter_by_event_type[evt->get_type()], m_ruleset_id, matches)) { return true; } } // Finally, try filters that are not specific to an event type. if(m_filter_all_event_types.size() > 0) { if(ruleset.run_wrappers(evt, m_filter_all_event_types, m_ruleset_id, matches)) { return true; } } return false; } libsinsp::events::set indexable_ruleset::ruleset_filters::sc_codes() { libsinsp::events::set res; for(const auto &wrap : m_filters) { res.insert(wrap->sc_codes().begin(), wrap->sc_codes().end()); } return res; } libsinsp::events::set indexable_ruleset::ruleset_filters::event_codes() { libsinsp::events::set res; for(const auto &wrap : m_filters) { res.insert(wrap->event_codes().begin(), wrap->event_codes().end()); } return res; }