diff --git a/userspace/engine/rule_loader.cpp b/userspace/engine/rule_loader.cpp index 92ca2347..b87825e9 100644 --- a/userspace/engine/rule_loader.cpp +++ b/userspace/engine/rule_loader.cpp @@ -21,12 +21,7 @@ limitations under the License. #include "filter_evttype_resolver.h" #include "filter_warning_resolver.h" #include - -#ifndef _WIN32 - #include -#else // _WIN32 - #include -#endif // _WIN32 +#include #define MAX_VISIBILITY ((uint32_t) -1) @@ -687,6 +682,77 @@ static void build_rule_exception_infos( } } +// todo(jasondellaluce): this breaks string escaping in lists +static bool resolve_list(string& cnd, const rule_loader::list_info& list) +{ + static string blanks = " \t\n\r"; + static string delims = blanks + "(),="; + string new_cnd; + size_t start, end; + bool used = false; + start = cnd.find(list.name); + while (start != string::npos) + { + // the characters surrounding the name must + // be delims of beginning/end of string + end = start + list.name.length(); + if ((start == 0 || delims.find(cnd[start - 1]) != string::npos) + && (end >= cnd.length() || delims.find(cnd[end]) != string::npos)) + { + // shift pointers to consume all whitespaces + while (start > 0 + && blanks.find(cnd[start - 1]) != string::npos) + { + start--; + } + while (end < cnd.length() + && blanks.find(cnd[end]) != string::npos) + { + end++; + } + // create substitution string by concatenating all values + string sub = ""; + for (auto &v : list.items) + { + if (!sub.empty()) + { + sub += ", "; + } + sub += v; + } + // if substituted list is empty, we need to + // remove a comma from the left or the right + if (sub.empty()) + { + if (start > 0 && cnd[start - 1] == ',') + { + start--; + } + else if (end < cnd.length() && cnd[end] == ',') + { + end++; + } + } + // compose new string with substitution + new_cnd = ""; + if (start > 0) + { + new_cnd += cnd.substr(0, start) + " "; + } + new_cnd += sub + " "; + if (end <= cnd.length()) + { + new_cnd += cnd.substr(end); + } + cnd = new_cnd; + start += sub.length() + 1; + used = true; + } + start = cnd.find(list.name, start + 1); + } + return used; +} + static void resolve_macros( indexed_vector& macros, shared_ptr& ast, @@ -716,185 +782,20 @@ static void resolve_macros( } } - -/* - * delim_chars - * helper class to look for delimiters - */ -struct delim_chars -{ - std::vector m_delims = std::vector(256, 0); - - explicit delim_chars(const std::string &char_array) - { - for (auto c : char_array) - { - m_delims[c] = 1; - } - } - - bool contains(char c) const - { - return m_delims[c]!=0; - } - - size_t find_in(const std::string& s) const - { - for (size_t i = 0, j = s.size(); i < j; ++i) - { - if (contains(s[i])) - { - return i; - } - } - return std::string::npos; - } -}; - -#define LIST_DELMS "\t\n\r ," - -/* - * list_inserter - */ -struct list_inserter -{ - using list_info_t = rule_loader::list_info; - using lists_map_t = indexed_vector; - - constexpr static const char* list_full = "\\([^\\(\\)]+\\)"; - constexpr static const char* list_sub = { "[^" LIST_DELMS "]+"}; - - const delim_chars delims{LIST_DELMS}; - - regex_t re_list{}; - regex_t re_sub{}; - - list_inserter() - { - if (regcomp(&re_list, list_full, REG_EXTENDED) != 0) - { - ASSERT(false); - } - - if (regcomp(&re_sub, list_sub, REG_EXTENDED) != 0) - { - ASSERT(false); - } - } - - ~list_inserter() - { - regfree(&re_list); - regfree(&re_sub); - } - - // split string found in insert_lists by delimiters - // concatenate lists expansion - void cat_lists(std::string& ret, const std::string& cond, lists_map_t &lists) const - { - regmatch_t re_match; - size_t start = 0; - bool first = true; - - while (start < cond.size() && regexec(const_cast(&re_sub), cond.c_str() + start, 1, &re_match, 0) == 0) - { - ret += cond.substr(start, re_match.rm_so); - - auto s = cond.substr(start + re_match.rm_so, re_match.rm_eo - re_match.rm_so); - auto *li = lists.at(s); - - if (li) - { - li->used = true; - if(li->items.empty()) - { - start += re_match.rm_eo; - while (start < cond.size() && delims.contains(cond[start])) - { - if (cond[start] == ',') - { - ++start; - break; - } - ret.push_back(cond[start]); - ++start; - } - continue; - } - - for (const auto &item : li->items) - { - if (item.empty()) - { - continue; - } - - if (first) - { - first = false; - } - else - { - while (!ret.empty() && delims.contains(ret.back())) - { - ret.pop_back(); - } - ret += ", "; - } - ret += item; - } - } - else - { - ret += s; - } - start += re_match.rm_eo; - } - - if (start <= cond.size()) - { - ret += cond.substr(start); - } - } - - // top level search - // find all "(..)" entries - std::string insert_lists(const std::string &cond, lists_map_t &lists) const - { - std::string ret; - regmatch_t re_match; - size_t start = 0; - while (start < cond.size() && regexec(const_cast(&re_list), cond.c_str() + start, 1, &re_match, 0)==0) - { - ret += cond.substr(start, re_match.rm_so); - ret += "("; - cat_lists(ret, cond.substr(start + re_match.rm_so + 1, re_match.rm_eo - re_match.rm_so - 2), lists); - ret += ")"; - start += re_match.rm_eo; - } - - if (start <= cond.size()) - { - ret += cond.substr(start); - } - - return ret.empty() ? cond : ret; - } -}; - - // note: there is no visibility order between filter conditions and lists static shared_ptr parse_condition( string condition, indexed_vector& lists, const rule_loader::context &ctx) { - - static const list_inserter list_inserter; - - auto cond = list_inserter.insert_lists(condition, lists); - - libsinsp::filter::parser p(cond); + for (auto &l : lists) + { + if (resolve_list(condition, l)) + { + l.used = true; + } + } + libsinsp::filter::parser p(condition); p.set_max_depth(1000); try { @@ -903,9 +804,10 @@ static shared_ptr parse_condition( } catch (const sinsp_exception& e) { - throw falco_exception("Compilation error when compiling \n" - + condition + "\n" - + cond + "\n: " + to_string(p.get_pos().col) + ": " + e.what()); + throw rule_loader::rule_load_exception( + load_result::LOAD_ERR_COMPILE_CONDITION, + e.what(), + ctx); } }