mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 11:42:06 +00:00
Compare commits
13 Commits
exec-hashe
...
fix/dev_ve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43e4d25848 | ||
|
|
67d592e83a | ||
|
|
356a4a0749 | ||
|
|
910b8ff858 | ||
|
|
83b12bab1d | ||
|
|
ecc1853d60 | ||
|
|
fbd6628693 | ||
|
|
ba61706557 | ||
|
|
234026e14b | ||
|
|
d03826379b | ||
|
|
3697d1fae2 | ||
|
|
e76c31b493 | ||
|
|
d95e36b526 |
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -14,6 +14,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Update base image
|
||||
run: sudo apt update -y
|
||||
@@ -47,6 +48,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Update base image
|
||||
run: sudo apt update -y
|
||||
@@ -80,6 +82,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Update base image
|
||||
run: sudo apt update -y
|
||||
@@ -113,6 +116,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Update base image
|
||||
run: sudo apt update -y
|
||||
@@ -151,6 +155,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: falco
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Link falco repo to /source/falco
|
||||
run: |
|
||||
|
||||
@@ -16,18 +16,32 @@ include(GetGitRevisionDescription)
|
||||
|
||||
# Create the falco version variable according to git index
|
||||
if(NOT FALCO_VERSION)
|
||||
string(STRIP "${FALCO_HASH}" FALCO_HASH)
|
||||
# Try to obtain the exact git tag
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
# Obtain the closest tag
|
||||
git_describe(FALCO_VERSION "--always" "--tags" "--abbrev=7")
|
||||
# Fallback version
|
||||
if(FALCO_VERSION MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
endif()
|
||||
# Format FALCO_VERSION to be semver with prerelease and build part
|
||||
string(REPLACE "-g" "+" FALCO_VERSION "${FALCO_VERSION}")
|
||||
# Fetch current hash
|
||||
get_git_head_revision(refspec FALCO_HASH)
|
||||
if(NOT FALCO_HASH OR FALCO_HASH MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
else()
|
||||
# Obtain the closest tag
|
||||
git_get_latest_tag(FALCO_LATEST_TAG)
|
||||
if(NOT FALCO_LATEST_TAG OR FALCO_LATEST_TAG MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
else()
|
||||
# Compute commit delta since tag
|
||||
git_get_delta_from_tag(FALCO_DELTA ${FALCO_LATEST_TAG} ${FALCO_HASH})
|
||||
if(NOT FALCO_DELTA OR FALCO_DELTA MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
else()
|
||||
# Cut hash to 7 bytes
|
||||
string(SUBSTRING ${FALCO_HASH} 0 7 FALCO_HASH)
|
||||
# Format FALCO_VERSION to be semver with prerelease and build part
|
||||
set(FALCO_VERSION
|
||||
"${FALCO_LATEST_TAG}-${FALCO_DELTA}+${FALCO_HASH}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# A tag has been found: use it as the Falco version
|
||||
set(FALCO_VERSION "${FALCO_TAG}")
|
||||
|
||||
@@ -86,29 +86,36 @@ function(get_git_head_revision _refspecvar _hashvar)
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
function(git_get_latest_tag _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
|
||||
# We use git describe --tags `git rev-list --tags --max-count=1`
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
rev-list
|
||||
--tags
|
||||
--max-count=1
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND tail -n1
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
tag_hash
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${tag_hash}-${res}-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
--tags
|
||||
${tag_hash}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
@@ -120,10 +127,108 @@ function(git_describe _var)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_delta_from_tag _var tag hash)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
|
||||
# Count commits in HEAD
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
rev-list
|
||||
--count
|
||||
${hash}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out_counter_head
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(${_var} "HEADCOUNT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Count commits in latest tag
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
rev-list
|
||||
--count
|
||||
${tag}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out_counter_tag
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(${_var} "TAGCOUNT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
expr
|
||||
${out_counter_head} - ${out_counter_tag}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out_delta
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(${_var} "DELTA-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(${_var} "${out_delta}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE)
|
||||
"${out}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
|
||||
@@ -150,6 +150,7 @@ syscall_event_drops:
|
||||
- alert
|
||||
rate: .03333
|
||||
max_burst: 1
|
||||
simulate_drops: false
|
||||
|
||||
# Falco uses a shared buffer between the kernel and userspace to receive
|
||||
# the events (eg., system call information) in userspace.
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
items: [probe_rpminfo, probe_rpmverify, probe_rpmverifyfile, probe_rpmverifypackage]
|
||||
|
||||
- macro: rpm_procs
|
||||
condition: (proc.name in (rpm_binaries, openscap_rpm_binaries) or proc.name in (salt-minion))
|
||||
condition: (proc.name in (rpm_binaries, openscap_rpm_binaries) or proc.name in (salt-call, salt-minion))
|
||||
|
||||
- list: deb_binaries
|
||||
items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, dpkg-divert, apt, apt-get, aptitude,
|
||||
@@ -1441,7 +1441,7 @@
|
||||
and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries,
|
||||
cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries,
|
||||
vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries,
|
||||
in.proftpd, mandb, salt-minion, postgres_mgmt_binaries,
|
||||
in.proftpd, mandb, salt-call, salt-minion, postgres_mgmt_binaries,
|
||||
google_oslogin_
|
||||
)
|
||||
and not cmp_cp_by_passwd
|
||||
@@ -3064,7 +3064,7 @@
|
||||
|
||||
- rule: Linux Kernel Module Injection Detected
|
||||
desc: Detect kernel module was injected (from container).
|
||||
condition: spawned_process and container and proc.name=insmod and not proc.args in (white_listed_modules)
|
||||
condition: spawned_process and container and proc.name=insmod and not proc.args in (white_listed_modules) and thread.cap_effective icontains sys_module
|
||||
output: Linux Kernel Module injection using insmod detected (user=%user.name user_loginuid=%user.loginuid parent_process=%proc.pname module=%proc.args %container.info image=%container.image.repository:%container.image.tag)
|
||||
priority: WARNING
|
||||
tags: [process]
|
||||
@@ -3240,3 +3240,16 @@
|
||||
command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [filesystem, mitre_credential_access, mitre_discovery]
|
||||
|
||||
- list: known_ptrace_binaries
|
||||
items: []
|
||||
|
||||
- macro: known_ptrace_procs
|
||||
condition: (proc.name in (known_ptrace_binaries))
|
||||
|
||||
- rule: PTRACE attached to process
|
||||
desc: "This rule detects an attempt to inject code into a process using PTRACE."
|
||||
condition: evt.type=ptrace and evt.dir=> and evt.arg.request in (5, 6, 11, 20, 27) and proc_name_exists and not known_ptrace_procs
|
||||
output: Detected ptrace PTRACE_ATTACH attempt (proc.cmdline=%proc.cmdline container=%container.info evt.type=%evt.type evt.arg.request=%evt.arg.request proc.pid=%proc.pid proc.cwd=%proc.cwd proc.ppid=%proc.ppid proc.pcmdline=%proc.pcmdline proc.sid=%proc.sid proc.exepath=%proc.exepath user.uid=%user.uid user.loginuid=%user.loginuid user.loginname=%user.loginname user.name=%user.name group.gid=%group.gid group.name=%group.name container.id=%container.id container.name=%container.name image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [process]
|
||||
@@ -20,9 +20,27 @@ limitations under the License.
|
||||
using namespace std;
|
||||
using namespace libsinsp::filter::ast;
|
||||
|
||||
static pos_info create_pos(uint32_t idx, uint32_t line, uint32_t col)
|
||||
{
|
||||
pos_info ret;
|
||||
ret.idx = idx;
|
||||
ret.line = line;
|
||||
ret.col = col;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool operator==(const pos_info& p1, const pos_info& p2)
|
||||
{
|
||||
return (p1.idx == p2.idx) &&
|
||||
(p1.line == p2.line) &&
|
||||
(p1.col == p2.col);
|
||||
}
|
||||
|
||||
TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
{
|
||||
string macro_name = "test_macro";
|
||||
pos_info macro_pos = create_pos(12, 85, 27);
|
||||
|
||||
SECTION("in the general case")
|
||||
{
|
||||
@@ -31,7 +49,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
|
||||
std::vector<std::unique_ptr<expr>> filter_and;
|
||||
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
|
||||
filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
|
||||
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos)));
|
||||
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));
|
||||
|
||||
std::vector<std::unique_ptr<expr>> expected_and;
|
||||
@@ -45,7 +63,8 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
// first run
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(filter->is_equal(expected.get()));
|
||||
|
||||
@@ -61,7 +80,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
std::shared_ptr<expr> macro = std::move(
|
||||
unary_check_expr::create("test.field", "", "exists"));
|
||||
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos));
|
||||
|
||||
filter_macro_resolver resolver;
|
||||
resolver.set_macro(macro_name, macro);
|
||||
@@ -71,7 +90,8 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(filter.get() != old_filter_ptr);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(filter->is_equal(macro.get()));
|
||||
|
||||
@@ -89,14 +109,17 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
string a_macro_name = macro_name + "_1";
|
||||
string b_macro_name = macro_name + "_2";
|
||||
|
||||
pos_info a_macro_pos = create_pos(11, 75, 43);
|
||||
pos_info b_macro_pos = create_pos(91, 21, 9);
|
||||
|
||||
std::shared_ptr<expr> a_macro = std::move(
|
||||
unary_check_expr::create("one.field", "", "exists"));
|
||||
std::shared_ptr<expr> b_macro = std::move(
|
||||
unary_check_expr::create("another.field", "", "exists"));
|
||||
|
||||
std::vector<std::unique_ptr<expr>> filter_or;
|
||||
filter_or.push_back(value_expr::create(a_macro_name));
|
||||
filter_or.push_back(value_expr::create(b_macro_name));
|
||||
filter_or.push_back(value_expr::create(a_macro_name, a_macro_pos));
|
||||
filter_or.push_back(value_expr::create(b_macro_name, b_macro_pos));
|
||||
std::shared_ptr<expr> filter = std::move(or_expr::create(filter_or));
|
||||
|
||||
std::vector<std::unique_ptr<expr>> expected_or;
|
||||
@@ -111,11 +134,16 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
// first run
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 2);
|
||||
REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
|
||||
!= resolver.get_resolved_macros().end());
|
||||
REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
|
||||
!= resolver.get_resolved_macros().end());
|
||||
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name);
|
||||
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end());
|
||||
REQUIRE(a_resolved_itr->first == a_macro_name);
|
||||
REQUIRE(a_resolved_itr->second == a_macro_pos);
|
||||
|
||||
auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
|
||||
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(b_resolved_itr->first == b_macro_name);
|
||||
REQUIRE(b_resolved_itr->second == b_macro_pos);
|
||||
REQUIRE(filter->is_equal(expected_filter.get()));
|
||||
|
||||
// second run
|
||||
@@ -130,15 +158,18 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
string a_macro_name = macro_name + "_1";
|
||||
string b_macro_name = macro_name + "_2";
|
||||
|
||||
pos_info a_macro_pos = create_pos(47, 1, 76);
|
||||
pos_info b_macro_pos = create_pos(111, 65, 2);
|
||||
|
||||
std::vector<std::unique_ptr<expr>> a_macro_and;
|
||||
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
|
||||
a_macro_and.push_back(value_expr::create(b_macro_name));
|
||||
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos));
|
||||
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));
|
||||
|
||||
std::shared_ptr<expr> b_macro = std::move(
|
||||
unary_check_expr::create("another.field", "", "exists"));
|
||||
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos));
|
||||
|
||||
std::vector<std::unique_ptr<expr>> expected_and;
|
||||
expected_and.push_back(unary_check_expr::create("one.field", "", "exists"));
|
||||
@@ -152,10 +183,17 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
// first run
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 2);
|
||||
REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
|
||||
!= resolver.get_resolved_macros().end());
|
||||
REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
|
||||
!= resolver.get_resolved_macros().end());
|
||||
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name);
|
||||
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end());
|
||||
REQUIRE(a_resolved_itr->first == a_macro_name);
|
||||
REQUIRE(a_resolved_itr->second == a_macro_pos);
|
||||
|
||||
auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
|
||||
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(b_resolved_itr->first == b_macro_name);
|
||||
REQUIRE(b_resolved_itr->second == b_macro_pos);
|
||||
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(filter->is_equal(expected_filter.get()));
|
||||
|
||||
@@ -170,18 +208,20 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
|
||||
TEST_CASE("Should find unknown macros", "[rule_loader]")
|
||||
{
|
||||
string macro_name = "test_macro";
|
||||
pos_info macro_pos = create_pos(9, 4, 2);
|
||||
|
||||
SECTION("in the general case")
|
||||
{
|
||||
std::vector<std::unique_ptr<expr>> filter_and;
|
||||
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
|
||||
filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
|
||||
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos)));
|
||||
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));
|
||||
|
||||
filter_macro_resolver resolver;
|
||||
REQUIRE(resolver.run(filter) == false);
|
||||
REQUIRE(resolver.get_unknown_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos);
|
||||
REQUIRE(resolver.get_resolved_macros().empty());
|
||||
}
|
||||
|
||||
@@ -190,12 +230,15 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
|
||||
string a_macro_name = macro_name + "_1";
|
||||
string b_macro_name = macro_name + "_2";
|
||||
|
||||
pos_info a_macro_pos = create_pos(32, 84, 9);
|
||||
pos_info b_macro_pos = create_pos(1, 0, 5);
|
||||
|
||||
std::vector<std::unique_ptr<expr>> a_macro_and;
|
||||
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
|
||||
a_macro_and.push_back(value_expr::create(b_macro_name));
|
||||
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos));
|
||||
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));
|
||||
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos));
|
||||
auto expected_filter = clone(a_macro.get());
|
||||
|
||||
filter_macro_resolver resolver;
|
||||
@@ -204,9 +247,11 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
|
||||
// first run
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_resolved_macros().begin() == a_macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->first == a_macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->second == a_macro_pos);
|
||||
REQUIRE(resolver.get_unknown_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_unknown_macros().begin() == b_macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->first == b_macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->second == b_macro_pos);
|
||||
REQUIRE(filter->is_equal(expected_filter.get()));
|
||||
}
|
||||
}
|
||||
@@ -214,15 +259,19 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
|
||||
TEST_CASE("Should undefine macro", "[rule_loader]")
|
||||
{
|
||||
string macro_name = "test_macro";
|
||||
pos_info macro_pos_1 = create_pos(12, 9, 3);
|
||||
pos_info macro_pos_2 = create_pos(9, 6, 3);
|
||||
|
||||
std::shared_ptr<expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
|
||||
std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name));
|
||||
std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name));
|
||||
std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name, macro_pos_1));
|
||||
std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name, macro_pos_2));
|
||||
filter_macro_resolver resolver;
|
||||
|
||||
resolver.set_macro(macro_name, macro);
|
||||
REQUIRE(resolver.run(a_filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos_1);
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(a_filter->is_equal(macro.get()));
|
||||
|
||||
@@ -230,21 +279,24 @@ TEST_CASE("Should undefine macro", "[rule_loader]")
|
||||
REQUIRE(resolver.run(b_filter) == false);
|
||||
REQUIRE(resolver.get_resolved_macros().empty());
|
||||
REQUIRE(resolver.get_unknown_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos_2);
|
||||
}
|
||||
|
||||
// checks that the macro AST is cloned and not shared across resolved filters
|
||||
TEST_CASE("Should clone macro AST", "[rule_loader]")
|
||||
{
|
||||
string macro_name = "test_macro";
|
||||
pos_info macro_pos = create_pos(5, 2, 8888);
|
||||
std::shared_ptr<unary_check_expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
|
||||
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos));
|
||||
filter_macro_resolver resolver;
|
||||
|
||||
|
||||
resolver.set_macro(macro_name, macro);
|
||||
REQUIRE(resolver.run(filter) == true);
|
||||
REQUIRE(resolver.get_resolved_macros().size() == 1);
|
||||
REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name);
|
||||
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
|
||||
REQUIRE(resolver.get_unknown_macros().empty());
|
||||
REQUIRE(filter->is_equal(macro.get()));
|
||||
|
||||
|
||||
@@ -27,30 +27,51 @@ static uint16_t other_non_default_ruleset = 2;
|
||||
static std::set<std::string> tags = {"some_tag", "some_other_tag"};
|
||||
static std::set<uint16_t> evttypes = { ppm_event_type::PPME_GENERIC_E };
|
||||
|
||||
static std::shared_ptr<libsinsp::filter::ast::expr> create_filter()
|
||||
static std::shared_ptr<gen_event_filter_factory> create_factory()
|
||||
{
|
||||
libsinsp::filter::parser parser("evt.type=open");
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse());
|
||||
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::shared_ptr<filter_ruleset> create_ruleset()
|
||||
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(
|
||||
std::shared_ptr<gen_event_filter_factory> f)
|
||||
{
|
||||
libsinsp::filter::parser parser("evt.type=open");
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::shared_ptr<gen_event_filter> create_filter(
|
||||
std::shared_ptr<gen_event_filter_factory> f,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> ast)
|
||||
{
|
||||
sinsp_filter_compiler compiler(f, ast.get());
|
||||
std::shared_ptr<gen_event_filter> filter(compiler.compile());
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
static std::shared_ptr<filter_ruleset> create_ruleset(
|
||||
std::shared_ptr<gen_event_filter_factory> f)
|
||||
{
|
||||
std::shared_ptr<gen_event_filter_factory> f(new sinsp_filter_factory(NULL));
|
||||
std::shared_ptr<filter_ruleset> ret(new evttype_index_ruleset(f));
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST_CASE("Should enable/disable on ruleset", "[rulesets]")
|
||||
{
|
||||
auto r = create_ruleset();
|
||||
auto filter = create_filter();
|
||||
auto f = create_factory();
|
||||
auto r = create_ruleset(f);
|
||||
auto ast = create_ast(f);
|
||||
auto filter = create_filter(f, ast);
|
||||
falco_rule rule;
|
||||
rule.name = "one_rule";
|
||||
rule.source = falco_common::syscall_source;
|
||||
rule.tags = tags;
|
||||
|
||||
r->add(rule, filter);
|
||||
r->add(rule, filter, ast);
|
||||
|
||||
SECTION("Should enable/disable for exact match w/ default ruleset")
|
||||
{
|
||||
@@ -184,21 +205,23 @@ TEST_CASE("Should enable/disable on ruleset", "[rulesets]")
|
||||
|
||||
TEST_CASE("Should enable/disable on ruleset for incremental adding tags", "[rulesets]")
|
||||
{
|
||||
auto r = create_ruleset();
|
||||
auto f = create_factory();
|
||||
auto r = create_ruleset(f);
|
||||
auto ast = create_ast(f);
|
||||
|
||||
auto rule1_filter = create_filter();
|
||||
auto rule1_filter = create_filter(f, ast);
|
||||
falco_rule rule1;
|
||||
rule1.name = "one_rule";
|
||||
rule1.source = falco_common::syscall_source;
|
||||
rule1.tags = {"rule1_tag"};
|
||||
r->add(rule1, rule1_filter);
|
||||
r->add(rule1, rule1_filter, ast);
|
||||
|
||||
auto rule2_filter = create_filter();
|
||||
auto rule2_filter = create_filter(f, ast);
|
||||
falco_rule rule2;
|
||||
rule2.name = "two_rule";
|
||||
rule2.source = falco_common::syscall_source;
|
||||
rule2.tags = {"rule2_tag"};
|
||||
r->add(rule2, rule2_filter);
|
||||
r->add(rule2, rule2_filter, ast);
|
||||
|
||||
std::set<std::string> want_tags;
|
||||
|
||||
|
||||
@@ -153,12 +153,11 @@ void evttype_index_ruleset::ruleset_filters::evttypes_for_ruleset(std::set<uint1
|
||||
|
||||
void evttype_index_ruleset::add(
|
||||
const falco_rule& rule,
|
||||
std::shared_ptr<gen_event_filter> filter,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> condition)
|
||||
{
|
||||
try
|
||||
{
|
||||
sinsp_filter_compiler compiler(m_filter_factory, condition.get());
|
||||
shared_ptr<gen_event_filter> filter(compiler.compile());
|
||||
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
|
||||
wrap->rule = rule;
|
||||
wrap->filter = filter;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
|
||||
void add(
|
||||
const falco_rule& rule,
|
||||
std::shared_ptr<gen_event_filter> filter,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> condition) override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
@@ -31,12 +31,14 @@ struct falco_source
|
||||
falco_source& operator = (falco_source&&) = default;
|
||||
falco_source(const falco_source& s):
|
||||
name(s.name),
|
||||
ruleset(s.ruleset),
|
||||
ruleset_factory(s.ruleset_factory),
|
||||
filter_factory(s.filter_factory),
|
||||
formatter_factory(s.formatter_factory) { };
|
||||
falco_source& operator = (const falco_source& s)
|
||||
{
|
||||
name = s.name;
|
||||
ruleset = s.ruleset;
|
||||
ruleset_factory = s.ruleset_factory;
|
||||
filter_factory = s.filter_factory;
|
||||
formatter_factory = s.formatter_factory;
|
||||
|
||||
@@ -21,12 +21,10 @@ using namespace libsinsp::filter;
|
||||
|
||||
bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
|
||||
{
|
||||
visitor v;
|
||||
m_unknown_macros.clear();
|
||||
m_resolved_macros.clear();
|
||||
v.m_unknown_macros = &m_unknown_macros;
|
||||
v.m_resolved_macros = &m_resolved_macros;
|
||||
v.m_macros = &m_macros;
|
||||
|
||||
visitor v(m_unknown_macros, m_resolved_macros, m_macros);
|
||||
v.m_node_substitute = nullptr;
|
||||
filter->accept(&v);
|
||||
if (v.m_node_substitute)
|
||||
@@ -39,12 +37,10 @@ bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
|
||||
|
||||
bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter)
|
||||
{
|
||||
visitor v;
|
||||
m_unknown_macros.clear();
|
||||
m_resolved_macros.clear();
|
||||
v.m_unknown_macros = &m_unknown_macros;
|
||||
v.m_resolved_macros = &m_resolved_macros;
|
||||
v.m_macros = &m_macros;
|
||||
|
||||
visitor v(m_unknown_macros, m_resolved_macros, m_macros);
|
||||
v.m_node_substitute = nullptr;
|
||||
filter->accept(&v);
|
||||
if (v.m_node_substitute)
|
||||
@@ -61,12 +57,12 @@ void filter_macro_resolver::set_macro(
|
||||
m_macros[name] = macro;
|
||||
}
|
||||
|
||||
const unordered_set<string>& filter_macro_resolver::get_unknown_macros() const
|
||||
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_unknown_macros() const
|
||||
{
|
||||
return m_unknown_macros;
|
||||
}
|
||||
|
||||
const unordered_set<string>& filter_macro_resolver::get_resolved_macros() const
|
||||
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_resolved_macros() const
|
||||
{
|
||||
return m_resolved_macros;
|
||||
}
|
||||
@@ -129,8 +125,8 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
|
||||
// we are supposed to get here only in case
|
||||
// of identier-only children from either a 'not',
|
||||
// an 'and' or an 'or'.
|
||||
auto macro = m_macros->find(e->value);
|
||||
if (macro != m_macros->end() && macro->second) // skip null-ptr macros
|
||||
auto macro = m_macros.find(e->value);
|
||||
if (macro != m_macros.end() && macro->second) // skip null-ptr macros
|
||||
{
|
||||
m_node_substitute = nullptr;
|
||||
auto new_node = ast::clone(macro->second.get());
|
||||
@@ -141,11 +137,11 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
|
||||
{
|
||||
m_node_substitute = std::move(new_node);
|
||||
}
|
||||
m_resolved_macros->insert(e->value);
|
||||
m_resolved_macros[e->value] = e->get_pos();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node_substitute = nullptr;
|
||||
m_unknown_macros->insert(e->value);
|
||||
m_unknown_macros[e->value] = e->get_pos();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class filter_macro_resolver
|
||||
\return true if at least one of the defined macros is resolved
|
||||
*/
|
||||
bool run(libsinsp::filter::ast::expr*& filter);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Version of run() that works with shared pointers
|
||||
*/
|
||||
@@ -58,12 +58,17 @@ class filter_macro_resolver
|
||||
std::string name,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> macro);
|
||||
|
||||
/*!
|
||||
\brief used in get_{resolved,unknown}_macros
|
||||
*/
|
||||
typedef std::unordered_map<std::string,libsinsp::filter::ast::pos_info> macro_info_map;
|
||||
|
||||
/*!
|
||||
\brief Returns a set containing the names of all the macros
|
||||
substituted during the last invocation of run(). Should be
|
||||
non-empty if the last invocation of run() returned true.
|
||||
*/
|
||||
const std::unordered_set<std::string>& get_resolved_macros() const;
|
||||
const macro_info_map& get_resolved_macros() const;
|
||||
|
||||
/*!
|
||||
\brief Returns a set containing the names of all the macros
|
||||
@@ -71,8 +76,8 @@ class filter_macro_resolver
|
||||
A macro remains unresolved if it is found inside the processed
|
||||
filter but it was not defined with set_macro();
|
||||
*/
|
||||
const std::unordered_set<std::string>& get_unknown_macros() const;
|
||||
|
||||
const macro_info_map& get_unknown_macros() const;
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<
|
||||
std::string,
|
||||
@@ -81,16 +86,18 @@ class filter_macro_resolver
|
||||
|
||||
struct visitor : public libsinsp::filter::ast::expr_visitor
|
||||
{
|
||||
visitor() = default;
|
||||
visitor(macro_info_map& unknown_macros, macro_info_map& resolved_macros, macro_defs& macros)
|
||||
: m_unknown_macros(unknown_macros), m_resolved_macros(resolved_macros), m_macros(macros) {}
|
||||
visitor(visitor&&) = default;
|
||||
visitor& operator = (visitor&&) = default;
|
||||
visitor(const visitor&) = delete;
|
||||
visitor& operator = (const visitor&) = delete;
|
||||
|
||||
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;
|
||||
std::unordered_set<std::string>* m_unknown_macros;
|
||||
std::unordered_set<std::string>* m_resolved_macros;
|
||||
macro_defs* m_macros;
|
||||
macro_info_map& m_unknown_macros;
|
||||
macro_info_map& m_resolved_macros;
|
||||
|
||||
macro_defs& m_macros;
|
||||
|
||||
void visit(libsinsp::filter::ast::and_expr* e) override;
|
||||
void visit(libsinsp::filter::ast::or_expr* e) override;
|
||||
@@ -101,7 +108,7 @@ class filter_macro_resolver
|
||||
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
|
||||
};
|
||||
|
||||
std::unordered_set<std::string> m_unknown_macros;
|
||||
std::unordered_set<std::string> m_resolved_macros;
|
||||
macro_info_map m_unknown_macros;
|
||||
macro_info_map m_resolved_macros;
|
||||
macro_defs m_macros;
|
||||
};
|
||||
|
||||
@@ -32,16 +32,20 @@ public:
|
||||
virtual ~filter_ruleset() = default;
|
||||
|
||||
/*!
|
||||
\brief Adds a rule and its filtering condition inside the manager.
|
||||
An exception is thrown is case of error. This method only adds the rule
|
||||
inside the internal collection, but does not enable it for any ruleset.
|
||||
The rule must be enabled for one or more rulesets with the enable() or
|
||||
enable_tags() methods.
|
||||
\brief Adds a rule and its filtering filter + condition inside the manager.
|
||||
This method only adds the rule inside the internal collection,
|
||||
but does not enable it for any ruleset. The rule must be enabled
|
||||
for one or more rulesets with the enable() or enable_tags() methods.
|
||||
The ast representation of the rule's condition is provided to allow
|
||||
the filter_ruleset object to parse the ast to obtain event types
|
||||
or do other analysis/indexing of the condition.
|
||||
\param rule The rule to be added
|
||||
\param the filter representing the rule's filtering condition.
|
||||
\param condition The AST representing the rule's filtering condition
|
||||
*/
|
||||
virtual void add(
|
||||
const falco_rule& rule,
|
||||
std::shared_ptr<gen_event_filter> filter,
|
||||
std::shared_ptr<libsinsp::filter::ast::expr> condition) = 0;
|
||||
|
||||
/*!
|
||||
|
||||
@@ -234,6 +234,7 @@ static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
|
||||
static void resolve_macros(
|
||||
indexed_vector<rule_loader::macro_info>& macros,
|
||||
std::shared_ptr<ast::expr>& ast,
|
||||
const std::string& condition,
|
||||
uint32_t visibility,
|
||||
const rule_loader::context &ctx)
|
||||
{
|
||||
@@ -248,15 +249,22 @@ static void resolve_macros(
|
||||
macro_resolver.run(ast);
|
||||
|
||||
// Note: only complaining about the first unknown macro
|
||||
THROW(!macro_resolver.get_unknown_macros().empty(),
|
||||
std::string("Undefined macro '")
|
||||
+ *macro_resolver.get_unknown_macros().begin()
|
||||
+ "' used in filter.",
|
||||
ctx);
|
||||
|
||||
for (auto &m : macro_resolver.get_resolved_macros())
|
||||
const filter_macro_resolver::macro_info_map& unresolved_macros = macro_resolver.get_unknown_macros();
|
||||
if(!unresolved_macros.empty())
|
||||
{
|
||||
macros.at(m)->used = true;
|
||||
auto it = unresolved_macros.begin();
|
||||
const rule_loader::context cond_ctx(it->second, condition, ctx);
|
||||
|
||||
THROW(true,
|
||||
std::string("Undefined macro '")
|
||||
+ it->first
|
||||
+ "' used in filter.",
|
||||
cond_ctx);
|
||||
}
|
||||
|
||||
for (auto &it : macro_resolver.get_resolved_macros())
|
||||
{
|
||||
macros.at(it.first)->used = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +371,7 @@ void rule_loader::compiler::compile_macros_infos(
|
||||
|
||||
for (auto &m : out)
|
||||
{
|
||||
resolve_macros(out, m.cond_ast, m.visibility, m.ctx);
|
||||
resolve_macros(out, m.cond_ast, m.cond, m.visibility, m.ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +412,7 @@ void rule_loader::compiler::compile_rule_infos(
|
||||
r.exceptions, rule.exception_fields, condition);
|
||||
}
|
||||
auto ast = parse_condition(condition, lists, r.cond_ctx);
|
||||
resolve_macros(macros, ast, MAX_VISIBILITY, r.ctx);
|
||||
resolve_macros(macros, ast, condition, MAX_VISIBILITY, r.ctx);
|
||||
|
||||
// check for warnings in the filtering condition
|
||||
warn_codes.clear();
|
||||
@@ -444,10 +452,12 @@ void rule_loader::compiler::compile_rule_infos(
|
||||
// This also compiles the filter, and might throw a
|
||||
// falco_exception with details on the compilation
|
||||
// failure.
|
||||
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, ast.get());
|
||||
try {
|
||||
source->ruleset->add(*out.at(rule_id), ast);
|
||||
shared_ptr<gen_event_filter> filter(compiler.compile());
|
||||
source->ruleset->add(*out.at(rule_id), filter, ast);
|
||||
}
|
||||
catch (const falco_exception& e)
|
||||
catch (const sinsp_exception& e)
|
||||
{
|
||||
// Allow errors containing "nonexistent field" if
|
||||
// skip_if_unknown_filter is true
|
||||
@@ -463,10 +473,14 @@ void rule_loader::compiler::compile_rule_infos(
|
||||
}
|
||||
else
|
||||
{
|
||||
rule_loader::context ctx(compiler.get_pos(),
|
||||
condition,
|
||||
r.cond_ctx);
|
||||
|
||||
throw rule_loader::rule_load_exception(
|
||||
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
|
||||
e.what(),
|
||||
r.cond_ctx);
|
||||
ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FALCO_BRANCH "@FALCO_REF@"
|
||||
#define FALCO_HASH "@FALCO_HASH@"
|
||||
#define FALCO_VERSION "@FALCO_VERSION@"
|
||||
#define FALCO_VERSION_MAJOR @FALCO_VERSION_MAJOR@
|
||||
#define FALCO_VERSION_MINOR @FALCO_VERSION_MINOR@
|
||||
|
||||
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
#define CPPHTTPLIB_ZLIB_SUPPORT
|
||||
#include <httplib.h>
|
||||
#include <thread>
|
||||
#include "configuration.h"
|
||||
|
||||
Reference in New Issue
Block a user