diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index d08f83dd..9b09899f 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -13,6 +13,7 @@ set(FALCO_ENGINE_SOURCE_FILES falco_common.cpp falco_engine.cpp + falco_load_result.cpp falco_utils.cpp json_evt.cpp evttype_index_ruleset.cpp diff --git a/userspace/engine/falco_load_result.cpp b/userspace/engine/falco_load_result.cpp new file mode 100644 index 00000000..a1c6aad8 --- /dev/null +++ b/userspace/engine/falco_load_result.cpp @@ -0,0 +1,104 @@ +/* +Copyright (C) 2022 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 "falco_load_result.h" + +static const std::string error_codes[] = { + "LOAD_ERR_FILE_READ", + "LOAD_ERR_YAML_PARSE", + "LOAD_ERR_YAML_VALIDATE", + "LOAD_ERR_COMPILE_CONDITION", + "LOAD_ERR_COMPILE_OUTPUT", + "LOAD_ERR_VALIDATE" +}; + +const std::string& falco::load_result::error_code_str(error_code ec) +{ + return error_codes[ec]; +} + +static const std::string error_strings[] = { + "File read error", + "YAML parse error", + "Error validating internal structure of YAML file", + "Error compiling condition", + "Error compiling output", + "Error validating rule/macro/list/exception objects" +}; + +const std::string& falco::load_result::error_str(error_code ec) +{ + return error_strings[ec]; +} + +static const std::string error_descs[] = { + "This occurs when falco can not read a given file. Check permissions and whether the file exists.", + "This occurs when the rules content is not valid YAML.", + "This occurs when the internal structure of the YAML file is incorrect. Examples include not consisting of a sequence of maps, a given rule/macro/list item not having required keys, values not having the right type (e.g. the items property of a list not being a sequence), etc.", + "This occurs when a condition string can not be compiled to a filter object.", + "This occurs when an output string can not be compiled to an output object.", + "This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc." +}; + +const std::string& falco::load_result::error_desc(error_code ec) +{ + return error_strings[ec]; +} + +static const std::string warning_codes[] = { + "LOAD_UNKNOWN_SOURCE", + "LOAD_UNSAFE_NA_CHECK", + "LOAD_NO_EVTTYPE", + "LOAD_UNKNOWN_FIELD", + "LOAD_UNUSED_MACRO", + "LOAD_UNUSED_LIST", + "LOAD_UNKNOWN_ITEM" +}; + +const std::string& falco::load_result::warning_code_str(warning_code wc) +{ + return warning_codes[wc]; +} + +static const std::string warning_strings[] = { + "Unknown event source", + "Unsafe comparison in condition", + "Condition has no event-type restriction", + "Unknown field in condition", + "Unused macro", + "Unused list", + "Unknown rules file item" +}; + +const std::string& falco::load_result::warning_str(warning_code wc) +{ + return warning_strings[wc]; +} + +static const std::string warning_descs[] = { + "A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.", + "Comparing a field value with is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.", + "A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.", + "A rule condition refers to a field that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.", + "A macro is defined in the rules content but is not used by any other macro or rule.", + "A list is defined in the rules content but is not used by any other list, macro, or rule.", + "An unknown top-level object is in the rules content. It will be ignored." +}; + +const std::string& falco::load_result::warning_desc(warning_code wc) +{ + return warning_descs[wc]; +} diff --git a/userspace/engine/falco_load_result.h b/userspace/engine/falco_load_result.h new file mode 100644 index 00000000..79560c5c --- /dev/null +++ b/userspace/engine/falco_load_result.h @@ -0,0 +1,94 @@ +/* +Copyright (C) 2022 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. +*/ + +#pragma once + +#include +#include + +namespace falco +{ + +// Represents the result of loading a rules file. +class load_result { +public: + + enum error_code { + LOAD_ERR_FILE_READ = 0, + LOAD_ERR_YAML_PARSE, + LOAD_ERR_YAML_VALIDATE, + LOAD_ERR_COMPILE_CONDITION, + LOAD_ERR_COMPILE_OUTPUT, + LOAD_ERR_VALIDATE + }; + + // The error code as a string + static const std::string& error_code_str(error_code ec); + + // A short string representation of the error + static const std::string& error_str(error_code ec); + + // A longer description of what the error represents and the + // impact. + static const std::string& error_desc(error_code ec); + + enum warning_code { + LOAD_UNKNOWN_SOURCE = 0, + LOAD_UNSAFE_NA_CHECK, + LOAD_NO_EVTTYPE, + LOAD_UNKNOWN_FIELD, + LOAD_UNUSED_MACRO, + LOAD_UNUSED_LIST, + LOAD_UNKNOWN_ITEM + }; + + // The warning code as a string + static const std::string& warning_code_str(warning_code ec); + + // A short string representation of the warning + static const std::string& warning_str(warning_code ec); + + // A longer description of what the warning represents and the + // impact. + static const std::string& warning_desc(warning_code ec); + + // If true, the rules were loaded successfully and can be used + // against events. If false, there were one or more + // errors--use one of the as_xxx methods to return information + // about why the rules could not be loaded. + virtual bool successful() = 0; + + // If true, there were one or more warnings. successful() and + // has_warnings() can both be true if there were only warnings. + virtual bool has_warnings() = 0; + + // This contains a human-readable version of the result, + // suitable for display to end users. + // + // When verbose is true, the returned value has full details + // on the result including document locations/context. + // + // When verbose is false, the returned value is a short string + // with the success value and a list of + // errors/warnings. Suitable for simple one-line display. + virtual const std::string& as_string(bool verbose) = 0; + + // This contains the full result structure as json, suitable + // for automated parsing/interpretation downstream. + virtual const nlohmann::json& as_json() = 0; +}; + +} // namespace falco