From 0ec2ad8422b2ac06a034f335c7768c5ab0d13736 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Fri, 28 Jun 2024 15:56:45 +0000 Subject: [PATCH] new(libsinsp): add basename() string transformer Signed-off-by: Luca Guerra --- userspace/libsinsp/filter/parser.cpp | 2 +- userspace/libsinsp/filter/parser.h | 2 +- .../libsinsp/sinsp_filter_transformer.cpp | 27 +++++++ userspace/libsinsp/sinsp_filter_transformer.h | 7 ++ userspace/libsinsp/test/filter_parser.ut.cpp | 2 +- .../libsinsp/test/filter_transformer.ut.cpp | 73 +++++++++++++++++++ 6 files changed, 110 insertions(+), 3 deletions(-) diff --git a/userspace/libsinsp/filter/parser.cpp b/userspace/libsinsp/filter/parser.cpp index f108bec3cd..705b7d68c7 100644 --- a/userspace/libsinsp/filter/parser.cpp +++ b/userspace/libsinsp/filter/parser.cpp @@ -90,7 +90,7 @@ static constexpr const char* s_field_transformer_val = "val("; static const std::vector s_field_transformers = { - "tolower(", "toupper(", "b64(", + "tolower(", "toupper(", "b64(", "basename(", }; static inline void update_pos(const char c, ast::pos_info& pos) diff --git a/userspace/libsinsp/filter/parser.h b/userspace/libsinsp/filter/parser.h index a0af7f6fcc..a783e592d1 100644 --- a/userspace/libsinsp/filter/parser.h +++ b/userspace/libsinsp/filter/parser.h @@ -67,7 +67,7 @@ namespace re2 { class RE2; }; // | 'startswith ' | 'bstartswith ' | 'endswith ' // ListOperator ::= 'intersects' | 'in' | 'pmatch' // FieldTransformerVal ::= 'val(' -// FieldTransformerType ::= 'tolower(' | 'toupper(' | 'b64(' +// FieldTransformerType ::= 'tolower(' | 'toupper(' | 'b64(' | 'basename(' // // Tokens (Regular Expressions): // Identifier ::= [a-zA-Z]+[a-zA-Z0-9_]* diff --git a/userspace/libsinsp/sinsp_filter_transformer.cpp b/userspace/libsinsp/sinsp_filter_transformer.cpp index 2cb2bdcb76..e67bf12765 100644 --- a/userspace/libsinsp/sinsp_filter_transformer.cpp +++ b/userspace/libsinsp/sinsp_filter_transformer.cpp @@ -115,6 +115,19 @@ bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const // for STORAGE, the transformed type is the same as the input type return true; } + case FTR_BASENAME: + { + switch(t) + { + case PT_CHARBUF: + case PT_FSPATH: + case PT_FSRELPATH: + // for BASENAME, the transformed type is the same as the input type + return true; + default: + return false; + } + } default: throw_unsupported_err(m_type); return false; @@ -180,6 +193,20 @@ bool sinsp_filter_transformer::transform_values(std::vector& ve } return true; } + case FTR_BASENAME: + { + return string_transformer(vec, t, [](std::string_view in, storage_t& out) -> bool { + auto last_slash_pos = in.find_last_of("/"); + ssize_t start_idx = last_slash_pos == std::string_view::npos ? 0 : last_slash_pos + 1; + + for (ssize_t i = start_idx; i < in.length(); i++) + { + out.push_back(in[i]); + } + + return true; + }); + } default: throw_unsupported_err(m_type); return false; diff --git a/userspace/libsinsp/sinsp_filter_transformer.h b/userspace/libsinsp/sinsp_filter_transformer.h index 697d912888..f01ca41bb7 100644 --- a/userspace/libsinsp/sinsp_filter_transformer.h +++ b/userspace/libsinsp/sinsp_filter_transformer.h @@ -28,6 +28,7 @@ enum filter_transformer_type: uint8_t FTR_TOLOWER = 1, FTR_BASE64 = 2, FTR_STORAGE = 3, // This transformer is only used internally + FTR_BASENAME = 4, }; static inline std::string filter_transformer_type_str(filter_transformer_type m) @@ -42,6 +43,8 @@ static inline std::string filter_transformer_type_str(filter_transformer_type m) return "b64"; case FTR_STORAGE: return "storage"; + case FTR_BASENAME: + return "basename"; default: throw sinsp_exception("unknown field transfomer id " + std::to_string(m)); } @@ -65,6 +68,10 @@ static inline filter_transformer_type filter_transformer_from_str(const std::str { return filter_transformer_type::FTR_STORAGE; } + if (str == "basename") + { + return filter_transformer_type::FTR_BASENAME; + } throw sinsp_exception("unknown field transfomer '" + str + "'"); } diff --git a/userspace/libsinsp/test/filter_parser.ut.cpp b/userspace/libsinsp/test/filter_parser.ut.cpp index dd21b951ab..b18c71ae40 100644 --- a/userspace/libsinsp/test/filter_parser.ut.cpp +++ b/userspace/libsinsp/test/filter_parser.ut.cpp @@ -111,7 +111,7 @@ TEST(parser, supported_field_transformers) { std::string expected_val = "val"; std::vector expected = { - "tolower", "toupper", "b64" }; + "tolower", "toupper", "b64", "basename" }; auto actual = parser::supported_field_transformers(); ASSERT_EQ(actual.size(), expected.size()); diff --git a/userspace/libsinsp/test/filter_transformer.ut.cpp b/userspace/libsinsp/test/filter_transformer.ut.cpp index becd522822..5ecddfe656 100644 --- a/userspace/libsinsp/test/filter_transformer.ut.cpp +++ b/userspace/libsinsp/test/filter_transformer.ut.cpp @@ -21,6 +21,7 @@ limitations under the License. #include #include #include +#include static std::unordered_set all_param_types() { @@ -231,3 +232,75 @@ TEST(sinsp_filter_transformer, b64) EXPECT_EQ(t, PT_CHARBUF); } } + +TEST(sinsp_filter_transformer, basename) +{ + sinsp_filter_transformer tr(filter_transformer_type::FTR_BASENAME); + + auto all_types = all_param_types(); + + auto supported_types = std::unordered_set({PT_CHARBUF, PT_FSPATH, PT_FSRELPATH }); + + auto test_cases = std::vector>{ + {"/home/ubuntu/hello.txt", "hello.txt"}, + {"/usr/local/bin/cat", "cat"}, + {"/", ""}, + {"", ""}, + {"/hello/", ""}, + {"hello", "hello"}, + }; + + + std::vector sample_vals; + + for (auto& tc : test_cases) + { + sample_vals.push_back(const_str_to_extract_value(tc.first.c_str())); + } + + // check for unsupported types + for (auto t : all_types) + { + if (supported_types.find(t) == supported_types.end()) + { + auto vals = sample_vals; + EXPECT_FALSE(tr.transform_type(t)) << supported_type_msg(t, false); + EXPECT_ANY_THROW(tr.transform_values(vals, t)) << supported_type_msg(t, false); + } + } + + // check for supported types + for (auto t : supported_types) + { + auto original = t; + EXPECT_TRUE(tr.transform_type(t)) << supported_type_msg(original, true); + EXPECT_EQ(original, t); // note: basename is expected not to alter the type + + auto vals = sample_vals; + EXPECT_TRUE(tr.transform_values(vals, t)) << supported_type_msg(original, true); + EXPECT_EQ(original, t); + EXPECT_EQ(vals.size(), test_cases.size()); + + for (uint32_t i = 0; i < test_cases.size(); i++) + { + EXPECT_EQ(std::string((const char *)vals[i].ptr), test_cases[i].second) << eq_test_msg(test_cases[i]); + EXPECT_EQ(vals[i].len, test_cases[i].second.length() + 1) << eq_test_msg(test_cases[i]); + } + } +} + +TEST_F(sinsp_with_test_input, basename_transformer) +{ + add_default_init_thread(); + open_inspector(); + + sinsp_evt *evt; + + int64_t dirfd = 3; + const char *file_to_run = "/tmp/file_to_run"; + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_E, 3, file_to_run, 0, 0); + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_X, 6, dirfd, file_to_run, 0, 0, 0, (uint64_t) 0); + + EXPECT_TRUE(eval_filter(evt, "basename(fd.name) = file_to_run")); + EXPECT_FALSE(eval_filter(evt, "basename(fd.name) = /tmp/file_to_run")); +}