mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-14 12:26:08 +00:00
Now that custom rules loading implementations (and related, custom rulesets) can be swapped into falco in a customizable way, there is some functionality in evttype_index_ruleset that could be used by other rulesets, specifically the part that segregates filters by ruleset and enables/disables filters based on name substring + tags. To allow for this, create a new base class indexable_ruleset that takes a generic filter_wrapper object that can return a name, tags, and sc/event codes, and segregates the filters by ruleset. It also optionally segregates filters by event type. The main interfaces are: - an implementation of filter_wrapper to provide a name/tags/event codes. - add_wrapper(), which provides a filter_wrapper to the indexable_ruleset. - run_wrappers(), which must be implemented by the derived class and is called for event processing. Most of the methods required by filter_ruleset are implemented by indexable_ruleset and do not need to be implemented by the derived class. Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
348 lines
8.0 KiB
C++
348 lines
8.0 KiB
C++
// 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 <algorithm>
|
|
|
|
void indexable_ruleset::clear()
|
|
{
|
|
for(size_t i = 0; i < m_rulesets.size(); i++)
|
|
{
|
|
m_rulesets[i] = std::make_shared<ruleset_filters>(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<ruleset_filters>(m_rulesets.size()));
|
|
}
|
|
|
|
return m_rulesets[ruleset_id]->num_filters();
|
|
}
|
|
|
|
void indexable_ruleset::enabled_evttypes(std::set<uint16_t> &evttypes, uint16_t ruleset_id)
|
|
{
|
|
evttypes.clear();
|
|
for(const auto &e : enabled_event_codes(ruleset_id))
|
|
{
|
|
evttypes.insert((uint16_t)e);
|
|
}
|
|
}
|
|
|
|
libsinsp::events::set<ppm_sc_code> 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<ppm_event_code> 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<ruleset_filters>(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<std::string> &tags, uint16_t ruleset_id)
|
|
{
|
|
enable_disable_tags(tags, true, ruleset_id);
|
|
}
|
|
|
|
void indexable_ruleset::disable_tags(const std::set<std::string> &tags, uint16_t ruleset_id)
|
|
{
|
|
enable_disable_tags(tags, false, ruleset_id);
|
|
}
|
|
|
|
void indexable_ruleset::enable_disable_tags(const std::set<std::string> &tags, bool enabled, uint16_t ruleset_id)
|
|
{
|
|
while(m_rulesets.size() < (size_t)ruleset_id + 1)
|
|
{
|
|
m_rulesets.emplace_back(std::make_shared<ruleset_filters>(m_rulesets.size()));
|
|
}
|
|
|
|
for(const auto &wrap : m_filters)
|
|
{
|
|
std::set<std::string> 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<falco_rule> &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<filter_wrapper> 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<filter_wrapper> 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<filter_wrapper> 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<filter_wrapper> 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<filter_wrapper> 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<falco_rule> &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<ppm_sc_code> indexable_ruleset::ruleset_filters::sc_codes()
|
|
{
|
|
libsinsp::events::set<ppm_sc_code> res;
|
|
for(const auto &wrap : m_filters)
|
|
{
|
|
res.insert(wrap->sc_codes().begin(), wrap->sc_codes().end());
|
|
}
|
|
return res;
|
|
}
|
|
|
|
libsinsp::events::set<ppm_event_code> indexable_ruleset::ruleset_filters::event_codes()
|
|
{
|
|
libsinsp::events::set<ppm_event_code> res;
|
|
for(const auto &wrap : m_filters)
|
|
{
|
|
res.insert(wrap->event_codes().begin(), wrap->event_codes().end());
|
|
}
|
|
return res;
|
|
}
|