Skip to content

Commit

Permalink
new(libsinsp): add len() filter transformer
Browse files Browse the repository at this point in the history
Signed-off-by: Luca Guerra <luca@guerra.sh>
  • Loading branch information
LucaGuerra committed Oct 23, 2024
1 parent 6322a02 commit 4bf1050
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 23 deletions.
11 changes: 5 additions & 6 deletions userspace/libsinsp/filter/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,11 @@ static const std::vector<std::string> s_binary_list_ops = {

static constexpr const char* s_field_transformer_val = "val(";

static const std::vector<std::string> s_field_transformers = {
"tolower(",
"toupper(",
"b64(",
"basename(",
};
static const std::vector<std::string> s_field_transformers = {"tolower(",
"toupper(",
"b64(",
"basename(",
"len("};

static inline void update_pos(const char c, ast::pos_info& pos) {
pos.col++;
Expand Down
2 changes: 1 addition & 1 deletion userspace/libsinsp/filter/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class RE2;
// | 'startswith ' | 'bstartswith ' | 'endswith '
// ListOperator ::= 'intersects' | 'in' | 'pmatch'
// FieldTransformerVal ::= 'val('
// FieldTransformerType ::= 'tolower(' | 'toupper(' | 'b64(' | 'basename('
// FieldTransformerType ::= 'tolower(' | 'toupper(' | 'b64(' | 'basename(' | 'len('
//
// Tokens (Regular Expressions):
// Identifier ::= [a-zA-Z]+[a-zA-Z0-9_]*
Expand Down
77 changes: 71 additions & 6 deletions userspace/libsinsp/sinsp_filter_transformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,16 @@ bool sinsp_filter_transformer::string_transformer(std::vector<extract_value_t>&
return true;
}

bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const {
bool sinsp_filter_transformer::transform_type(ppm_param_type& t, uint32_t& flags) const {
bool is_list = flags & EPF_IS_LIST;
switch(m_type) {
case FTR_TOUPPER: {
switch(t) {
case PT_CHARBUF:
case PT_FSPATH:
case PT_FSRELPATH:
// for TOUPPER, the transformed type is the same as the input type
return true;
return !is_list;
default:
return false;
}
Expand All @@ -82,7 +83,7 @@ bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const {
case PT_FSPATH:
case PT_FSRELPATH:
// for TOLOWER, the transformed type is the same as the input type
return true;
return !is_list;
default:
return false;
}
Expand All @@ -92,7 +93,7 @@ bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const {
case PT_CHARBUF:
case PT_BYTEBUF:
// for BASE64, the transformed type is the same as the input type
return true;
return !is_list;
default:
return false;
}
Expand All @@ -107,6 +108,23 @@ bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const {
case PT_FSPATH:
case PT_FSRELPATH:
// for BASENAME, the transformed type is the same as the input type
return !is_list;
default:
return false;
}
}
case FTR_LEN: {
if(is_list) {
t = PT_UINT64;
flags = 0;
return true;
}
switch(t) {
case PT_CHARBUF:
case PT_BYTEBUF:
case PT_FSPATH:
case PT_FSRELPATH:
t = PT_UINT64;
return true;
default:
return false;
Expand All @@ -119,8 +137,11 @@ bool sinsp_filter_transformer::transform_type(ppm_param_type& t) const {
}

bool sinsp_filter_transformer::transform_values(std::vector<extract_value_t>& vec,
ppm_param_type& t) {
if(!transform_type(t)) {
ppm_param_type& t,
uint32_t& flags) {
bool is_list = flags & EPF_IS_LIST;
ppm_param_type original_type = t;
if(!transform_type(t, flags)) {
throw_type_incompatibility_err(t, filter_transformer_type_str(m_type));
}

Expand Down Expand Up @@ -180,6 +201,50 @@ bool sinsp_filter_transformer::transform_values(std::vector<extract_value_t>& ve
return true;
});
}
case FTR_LEN: {
assert((void("len() type must be PT_UINT64"), t == PT_UINT64));
if(is_list) {
uint64_t len = static_cast<uint64_t>(vec.size());
auto stored_val = store_scalar(len);
vec.clear();
vec.push_back(stored_val);
return true;
}

// not a list: could be string or buffer
bool is_string = false;
switch(original_type) {
case PT_CHARBUF:
case PT_FSPATH:
case PT_FSRELPATH:
is_string = true;
break;
case PT_BYTEBUF:
is_string = false;
break;
default:
return false;
}

for(std::size_t i = 0; i < vec.size(); i++) {
uint64_t len;
if(vec[i].ptr == nullptr) {
vec[i] = store_scalar(0);
continue;
}

if(is_string) {
len = static_cast<uint64_t>(
strnlen(reinterpret_cast<const char*>(vec[i].ptr), vec[i].len));
vec[i] = store_scalar(len);
continue;
}

len = static_cast<uint64_t>(vec[i].len);
vec[i] = store_scalar(len);
}
return true;
}
default:
throw_unsupported_err(m_type);
return false;
Expand Down
17 changes: 15 additions & 2 deletions userspace/libsinsp/sinsp_filter_transformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum filter_transformer_type : uint8_t {
FTR_BASE64 = 2,
FTR_STORAGE = 3, // This transformer is only used internally
FTR_BASENAME = 4,
FTR_LEN = 5
};

static inline std::string filter_transformer_type_str(filter_transformer_type m) {
Expand All @@ -42,6 +43,8 @@ static inline std::string filter_transformer_type_str(filter_transformer_type m)
return "storage";
case FTR_BASENAME:
return "basename";
case FTR_LEN:
return "len";
default:
throw sinsp_exception("unknown field transfomer id " + std::to_string(m));
}
Expand All @@ -63,6 +66,9 @@ static inline filter_transformer_type filter_transformer_from_str(const std::str
if(str == "basename") {
return filter_transformer_type::FTR_BASENAME;
}
if(str == "len") {
return filter_transformer_type::FTR_LEN;
}
throw sinsp_exception("unknown field transfomer '" + str + "'");
}

Expand All @@ -72,9 +78,9 @@ class sinsp_filter_transformer {

sinsp_filter_transformer(filter_transformer_type t): m_type(t) {};

bool transform_type(ppm_param_type& t) const;
bool transform_type(ppm_param_type& t, uint32_t& flags) const;

bool transform_values(std::vector<extract_value_t>& vals, ppm_param_type& t);
bool transform_values(std::vector<extract_value_t>& vals, ppm_param_type& t, uint32_t& flags);

private:
using str_transformer_func_t = std::function<bool(std::string_view in, storage_t& out)>;
Expand All @@ -83,6 +89,13 @@ class sinsp_filter_transformer {
ppm_param_type t,
str_transformer_func_t mod);

template<class T>
extract_value_t store_scalar(T value) {
uint8_t* bytes = reinterpret_cast<uint8_t*>(&value);
storage_t& stored_val = m_storage_values.emplace_back(bytes, bytes + sizeof(T));
return {static_cast<uint8_t*>(stored_val.data()), static_cast<uint32_t>(stored_val.size())};
}

filter_transformer_type m_type;
std::vector<storage_t> m_storage_values;
};
15 changes: 9 additions & 6 deletions userspace/libsinsp/sinsp_filtercheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ char* sinsp_filter_check::tostring(sinsp_evt* evt) {
}

auto ftype = get_transformed_field_info()->m_type;
if(m_field->m_flags & EPF_IS_LIST) {
if(get_transformed_field_info()->m_flags & EPF_IS_LIST) {
std::string res = "(";
for(auto& val : m_extracted_values) {
if(res.size() > 1) {
Expand Down Expand Up @@ -478,7 +478,7 @@ Json::Value sinsp_filter_check::tojson(sinsp_evt* evt) {
}

auto ftype = get_transformed_field_info()->m_type;
if(m_field->m_flags & EPF_IS_LIST) {
if(get_transformed_field_info()->m_flags & EPF_IS_LIST) {
for(auto& val : m_extracted_values) {
jsonval.append(rawval_to_json(val.ptr, ftype, m_field->m_print_format, val.len));
}
Expand Down Expand Up @@ -1045,11 +1045,12 @@ void sinsp_filter_check::add_transformer(filter_transformer_type trtype) {
// apply type transformation, both as a feasibility check and
// as an information to be returned later on
sinsp_filter_transformer tr(trtype);
if(!tr.transform_type(m_transformed_field->m_type)) {
if(!tr.transform_type(m_transformed_field->m_type, m_transformed_field->m_flags)) {
throw sinsp_exception("can't add field transformer: type '" +
std::string(param_type_to_string(m_transformed_field->m_type)) +
"' is not supported by '" + filter_transformer_type_str(trtype) +
"' transformer applied on field '" +
"' transformer applied on " +
(m_transformed_field->is_list() ? "list " : "") + "field '" +
std::string(get_field_info()->m_name) + "'");
}

Expand All @@ -1062,9 +1063,11 @@ void sinsp_filter_check::add_transformer(filter_transformer_type trtype) {
}

bool sinsp_filter_check::apply_transformers(std::vector<extract_value_t>& values) {
auto type = get_field_info()->m_type;
const filtercheck_field_info* field_info = get_field_info();
auto field_type = field_info->m_type;
auto field_flags = field_info->m_flags;
for(auto& tr : m_transformers) {
if(!tr.transform_values(values, type)) {
if(!tr.transform_values(values, field_type, field_flags)) {
return false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion userspace/libsinsp/sinsp_filtercheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class sinsp_filter_check {
//
// Extract the field from the event. If sanitize_strings is true, any
// string values are sanitized to remove nonprintable characters.
// By default, this fills the vector with only one value, retireved by calling the single-result
// By default, this fills the vector with only one value, retrieved by calling the single-result
// extract method.
// If a NULL value is returned by extract, the vector is emptied.
// Subclasses are meant to either override this, or the single-valued extract method.
Expand Down
2 changes: 1 addition & 1 deletion userspace/libsinsp/sinsp_filtercheck_fd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ static const filtercheck_field_info sinsp_filter_check_fd_fields[] = {
"FD full name raw. Just like fd.name, but only used if fd is a file path. File path is "
"kept raw with limited sanitization and without deriving the absolute path."},
{PT_CHARBUF,
EPF_IS_LIST | EPF_ARG_ALLOWED | EPF_NO_RHS | EPF_NO_TRANSFORMER,
EPF_IS_LIST | EPF_ARG_ALLOWED | EPF_NO_RHS,
PF_DEC,
"fd.types",
"FD Type",
Expand Down

0 comments on commit 4bf1050

Please sign in to comment.