Files
falco/userspace/engine/ruleset.cpp
Mark Stemm 7fd350d49a Allow exact matches for rule names
Currently, when calling enable_rule, the provided rule name pattern is a
substring match, that is if the rules file has a rule "My fantastic
rule", and you call engine->enable_rule("fantastic", true), the rule
will be enabled.

This can cause problems if one rule name is a complete subset of another
rule name e.g. rules "My rule" and "My rule is great", and calling
engine->enable_rule("My rule", true).

To allow for this case, add an alternate method enable_rule_exact() in
both default ruleset and ruleset variants. In this case, the rule name
must be an exact match.

In the underlying ruleset code, add a "match_exact" option to
falco_ruleset::enable() that denotes whether the substring is an exact
or substring match.

This doesn't change the default behavior of falco in any way, as the
existing calls still use enable_rule().

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-11 14:15:42 +02:00

406 lines
7.7 KiB
C++

/*
Copyright (C) 2019 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 "ruleset.h"
#include "banned.h" // This raises a compilation error when certain functions are used
using namespace std;
falco_ruleset::falco_ruleset()
{
}
falco_ruleset::~falco_ruleset()
{
for(const auto &val : m_filters)
{
delete val.second->filter;
delete val.second;
}
for(auto &ruleset : m_rulesets)
{
delete ruleset;
}
m_filters.clear();
}
falco_ruleset::ruleset_filters::ruleset_filters():
m_num_filters(0)
{
}
falco_ruleset::ruleset_filters::~ruleset_filters()
{
for(uint32_t i = 0; i < m_filter_by_event_tag.size(); i++)
{
if(m_filter_by_event_tag[i])
{
delete m_filter_by_event_tag[i];
m_filter_by_event_tag[i] = NULL;
}
}
}
void falco_ruleset::ruleset_filters::add_filter(filter_wrapper *wrap)
{
bool added = false;
for(uint32_t etag = 0; etag < wrap->event_tags.size(); etag++)
{
if(wrap->event_tags[etag])
{
added = true;
if(m_filter_by_event_tag.size() <= etag)
{
m_filter_by_event_tag.resize(etag + 1);
}
if(!m_filter_by_event_tag[etag])
{
m_filter_by_event_tag[etag] = new list<filter_wrapper *>();
}
m_filter_by_event_tag[etag]->push_back(wrap);
}
}
if(added)
{
m_num_filters++;
}
}
void falco_ruleset::ruleset_filters::remove_filter(filter_wrapper *wrap)
{
bool removed = false;
for(uint32_t etag = 0; etag < wrap->event_tags.size(); etag++)
{
if(wrap->event_tags[etag])
{
if(etag < m_filter_by_event_tag.size())
{
list<filter_wrapper *> *l = m_filter_by_event_tag[etag];
if(l)
{
auto it = remove(l->begin(),
l->end(),
wrap);
if(it != l->end())
{
removed = true;
l->erase(it,
l->end());
if(l->size() == 0)
{
delete l;
m_filter_by_event_tag[etag] = NULL;
}
}
}
}
}
}
if(removed)
{
m_num_filters--;
}
}
uint64_t falco_ruleset::ruleset_filters::num_filters()
{
return m_num_filters;
}
bool falco_ruleset::ruleset_filters::run(gen_event *evt, uint32_t etag)
{
if(etag >= m_filter_by_event_tag.size())
{
return false;
}
list<filter_wrapper *> *filters = m_filter_by_event_tag[etag];
if(!filters)
{
return false;
}
for(auto &wrap : *filters)
{
if(wrap->filter->run(evt))
{
return true;
}
}
return false;
}
void falco_ruleset::ruleset_filters::event_tags_for_ruleset(vector<bool> &event_tags)
{
event_tags.assign(m_filter_by_event_tag.size(), false);
for(uint32_t etag = 0; etag < m_filter_by_event_tag.size(); etag++)
{
list<filter_wrapper *> *filters = m_filter_by_event_tag[etag];
if(filters)
{
event_tags[etag] = true;
}
}
}
void falco_ruleset::add(string &name,
set<string> &tags,
set<uint32_t> &event_tags,
gen_event_filter *filter)
{
filter_wrapper *wrap = new filter_wrapper();
wrap->filter = filter;
for(auto &etag : event_tags)
{
wrap->event_tags.resize(etag + 1);
wrap->event_tags[etag] = true;
}
m_filters.insert(pair<string, filter_wrapper *>(name, wrap));
for(const auto &tag : tags)
{
auto it = m_filter_by_event_tag.lower_bound(tag);
if(it == m_filter_by_event_tag.end() ||
it->first != tag)
{
it = m_filter_by_event_tag.emplace_hint(it,
make_pair(tag, list<filter_wrapper *>()));
}
it->second.push_back(wrap);
}
}
void falco_ruleset::enable(const string &substring, bool match_exact, bool enabled, uint16_t ruleset)
{
while(m_rulesets.size() < (size_t)ruleset + 1)
{
m_rulesets.push_back(new ruleset_filters());
}
for(const auto &val : m_filters)
{
bool matches;
if(match_exact)
{
size_t pos = val.first.find(substring);
matches = (substring == "" || (pos == 0 &&
substring.size() == val.first.size()));
}
else
{
matches = (substring == "" || (val.first.find(substring) != string::npos));
}
if(matches)
{
if(enabled)
{
m_rulesets[ruleset]->add_filter(val.second);
}
else
{
m_rulesets[ruleset]->remove_filter(val.second);
}
}
}
}
void falco_ruleset::enable_tags(const set<string> &tags, bool enabled, uint16_t ruleset)
{
while(m_rulesets.size() < (size_t)ruleset + 1)
{
m_rulesets.push_back(new ruleset_filters());
}
for(const auto &tag : tags)
{
for(const auto &wrap : m_filter_by_event_tag[tag])
{
if(enabled)
{
m_rulesets[ruleset]->add_filter(wrap);
}
else
{
m_rulesets[ruleset]->remove_filter(wrap);
}
}
}
}
uint64_t falco_ruleset::num_rules_for_ruleset(uint16_t ruleset)
{
while(m_rulesets.size() < (size_t)ruleset + 1)
{
m_rulesets.push_back(new ruleset_filters());
}
return m_rulesets[ruleset]->num_filters();
}
bool falco_ruleset::run(gen_event *evt, uint32_t etag, uint16_t ruleset)
{
if(m_rulesets.size() < (size_t)ruleset + 1)
{
return false;
}
return m_rulesets[ruleset]->run(evt, etag);
}
void falco_ruleset::event_tags_for_ruleset(vector<bool> &evttypes, uint16_t ruleset)
{
if(m_rulesets.size() < (size_t)ruleset + 1)
{
return;
}
return m_rulesets[ruleset]->event_tags_for_ruleset(evttypes);
}
falco_sinsp_ruleset::falco_sinsp_ruleset()
{
}
falco_sinsp_ruleset::~falco_sinsp_ruleset()
{
}
void falco_sinsp_ruleset::add(string &name,
set<uint32_t> &evttypes,
set<uint32_t> &syscalls,
set<string> &tags,
sinsp_filter *filter)
{
set<uint32_t> event_tags;
if(evttypes.size() + syscalls.size() == 0)
{
// If no evttypes or syscalls are specified, the filter is
// enabled for all evttypes/syscalls.
for(uint32_t i = 0; i < PPM_EVENT_MAX; i++)
{
evttypes.insert(i);
}
for(uint32_t i = 0; i < PPM_SC_MAX; i++)
{
syscalls.insert(i);
}
}
for(auto evttype : evttypes)
{
event_tags.insert(evttype_to_event_tag(evttype));
}
for(auto syscallid : syscalls)
{
event_tags.insert(syscall_to_event_tag(syscallid));
}
falco_ruleset::add(name, tags, event_tags, (gen_event_filter *)filter);
}
bool falco_sinsp_ruleset::run(sinsp_evt *evt, uint16_t ruleset)
{
uint32_t etag;
uint16_t etype = evt->get_type();
if(etype == PPME_GENERIC_E || etype == PPME_GENERIC_X)
{
sinsp_evt_param *parinfo = evt->get_param(0);
uint16_t syscallid = *(uint16_t *)parinfo->m_val;
etag = syscall_to_event_tag(syscallid);
}
else
{
etag = evttype_to_event_tag(etype);
}
return falco_ruleset::run((gen_event *)evt, etag, ruleset);
}
void falco_sinsp_ruleset::evttypes_for_ruleset(vector<bool> &evttypes, uint16_t ruleset)
{
vector<bool> event_tags;
event_tags_for_ruleset(event_tags, ruleset);
evttypes.assign(PPM_EVENT_MAX + 1, false);
for(uint32_t etype = 0; etype < PPM_EVENT_MAX; etype++)
{
uint32_t etag = evttype_to_event_tag(etype);
if(etag < event_tags.size() && event_tags[etag])
{
evttypes[etype] = true;
}
}
}
void falco_sinsp_ruleset::syscalls_for_ruleset(vector<bool> &syscalls, uint16_t ruleset)
{
vector<bool> event_tags;
event_tags_for_ruleset(event_tags, ruleset);
syscalls.assign(PPM_EVENT_MAX + 1, false);
for(uint32_t syscallid = 0; syscallid < PPM_SC_MAX; syscallid++)
{
uint32_t etag = evttype_to_event_tag(syscallid);
if(etag < event_tags.size() && event_tags[etag])
{
syscalls[syscallid] = true;
}
}
}
uint32_t falco_sinsp_ruleset::evttype_to_event_tag(uint32_t evttype)
{
return evttype;
}
uint32_t falco_sinsp_ruleset::syscall_to_event_tag(uint32_t syscallid)
{
return PPM_EVENT_MAX + 1 + syscallid;
}