Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(savefile): introduce scap-file converter skeleton #2168

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions driver/ppm_events_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -2056,6 +2056,8 @@ enum ppm_event_flags {
// overhead to full event capture */ SUPPORT DROPPED
EF_LARGE_PAYLOAD = (1 << 11), /* This event has a large payload, ie: up to UINT32_MAX bytes. DO
NOT USE ON syscalls-driven events!!! */
EF_TMP_CONVERTER_MANAGED = (1 << 12), /* todo!: this must be removed when we will mark ENTER
events as OLD_VERSION */
};

/*
Expand Down
5 changes: 5 additions & 0 deletions test/libscap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ if(BUILD_LIBSCAP_GVISOR)
)# Used for <pkg/sentry/...> includes
endif()

file(GLOB_RECURSE SAVEFILE_TEST_SUITE
"${CMAKE_CURRENT_SOURCE_DIR}/test_suites/engines/savefile/*.cpp"
)
list(APPEND LIBSCAP_TESTS_SOURCES ${SAVEFILE_TEST_SUITE})

# Summary logs
set(LIBSCAP_UNIT_TESTS_PREFIX "[LIBSCAP UNIT TESTS]")
message(STATUS "${LIBSCAP_UNIT_TESTS_PREFIX} LIBSCAP_TESTS_SOURCES: ${LIBSCAP_TESTS_SOURCES}")
Expand Down
139 changes: 139 additions & 0 deletions test/libscap/test_suites/engines/savefile/convert_event_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 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 <libscap/scap.h>
#include <gtest/gtest.h>
#include <cstdarg>
#include <memory>
#include <stdexcept>
#include <libscap/engine/savefile/converter/converter.h>

typedef std::shared_ptr<scap_evt> safe_scap_evt_t;
safe_scap_evt_t new_safe_scap_evt(scap_evt *evt) {
return safe_scap_evt_t{evt, free};
}
class convert_event_test : public testing::Test {
static constexpr uint16_t safe_margin = 100;

protected:
virtual void TearDown() {
// At every iteration we want to clear the storage in the converter
scap_clear_converter_storage();
}
safe_scap_evt_t create_safe_scap_event(uint64_t ts,
uint64_t tid,
ppm_event_code event_type,
uint32_t n,
...) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
va_list args;
va_start(args, n);
scap_evt *evt = scap_create_event_v(error, ts, tid, event_type, n, args);
va_end(args);
if(evt == NULL) {
throw std::runtime_error("Error creating event: " + std::string(error));
}
return new_safe_scap_evt(evt);
}
// The expected result can be either CONVERSION_CONTINUE or CONVERSION_COMPLETED
void assert_single_conversion_success(enum conversion_result expected_res,
safe_scap_evt_t evt_to_convert,
safe_scap_evt_t expected_evt) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
// We assume it's okay to create a new event with the same size as the expected event
auto storage = new_safe_scap_evt((scap_evt *)calloc(1, expected_evt->len));
// First we check the conversion result matches the expected result
ASSERT_EQ(scap_convert_event(storage.get(), evt_to_convert.get(), error), expected_res)
<< "Different conversion results: " << error;
if(!scap_compare_events(storage.get(), expected_evt.get(), error)) {
printf("\nExpected event:\n");
scap_print_event(expected_evt.get(), PRINT_FULL);
printf("\nConverted event:\n");
scap_print_event(storage.get(), PRINT_FULL);
FAIL() << error;
}
}
void assert_single_conversion_failure(safe_scap_evt_t evt_to_convert) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
// We assume it's okay to create a new event with the same size as the expected event
auto storage = new_safe_scap_evt((scap_evt *)calloc(1, evt_to_convert->len));
// First we check the conversion result matches the expected result
ASSERT_EQ(scap_convert_event(storage.get(), evt_to_convert.get(), error), CONVERSION_ERROR)
<< "The conversion is not failed: " << error;
}
void assert_single_conversion_skip(safe_scap_evt_t evt_to_convert) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
// We assume it's okay to create a new event with the same size as the expected event
auto storage = new_safe_scap_evt((scap_evt *)calloc(1, evt_to_convert->len));
// First we check the conversion result matches the expected result
ASSERT_EQ(scap_convert_event(storage.get(), evt_to_convert.get(), error), CONVERSION_SKIP)
<< "The conversion is not skipped: " << error;
}
void assert_full_conversion(safe_scap_evt_t evt_to_convert, safe_scap_evt_t expected_evt) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
// Here we need to allocate more space than the expected event because in the middle we
// could have larger events. We could also use `MAX_EVENT_SIZE` but probably it will just
// slowdown tests.
auto to_convert_evt = new_safe_scap_evt(
(scap_evt *)calloc(1, expected_evt->len + convert_event_test::safe_margin));
auto new_evt = new_safe_scap_evt(
(scap_evt *)calloc(1, expected_evt->len + convert_event_test::safe_margin));
// We copy the event to convert into the new larger storage since during the conversions it
// could contain larger events than the initial one.
// We copy it in the new event to match the for loop logic.
memcpy(new_evt.get(), evt_to_convert.get(), evt_to_convert->len);
int conv_num = 0;
conversion_result conv_res = CONVERSION_CONTINUE;
for(conv_num = 0; conv_num < MAX_CONVERSION_BOUNDARY && conv_res == CONVERSION_CONTINUE;
conv_num++) {
// Copy the new event into the one to convert for the next conversion.
memcpy(to_convert_evt.get(), new_evt.get(), new_evt->len);
conv_res = scap_convert_event((scap_evt *)new_evt.get(),
(scap_evt *)to_convert_evt.get(),
error);
}
switch(conv_res) {
case CONVERSION_ERROR:
FAIL() << "Unexpected CONVERSION_ERROR: " << error;
case CONVERSION_SKIP:
FAIL() << "Unexpected CONVERSION_SKIP";
case CONVERSION_CONTINUE:
if(conv_num < MAX_CONVERSION_BOUNDARY) {
FAIL() << "Unexpected CONVERSION_CONTINUE without reaching max boundary";
} else {
FAIL() << "Unexpected CONVERSION_CONTINUE reaching max boundary";
}
default:
break;
}
if(!scap_compare_events(new_evt.get(), expected_evt.get(), error)) {
printf("\nExpected event:\n");
scap_print_event(expected_evt.get(), PRINT_FULL);
printf("\nConverted event:\n");
scap_print_event(new_evt.get(), PRINT_FULL);
FAIL() << error;
}
}
void assert_event_storage_presence(safe_scap_evt_t expected_evt) {
char error[SCAP_LASTERR_SIZE] = {'\0'};
int64_t tid = expected_evt.get()->tid;
auto event = scap_retrieve_evt_from_converter_storage(tid);
if(!event) {
FAIL() << "Event with tid " << tid << " not found in the storage";
}
if(!scap_compare_events(event, expected_evt.get(), error)) {
FAIL() << "Different events: " << error;
}
}
};
23 changes: 23 additions & 0 deletions test/libscap/test_suites/engines/savefile/converter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 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 "convert_event_test.h"

// todo!: remove it when we will add the first example.
TEST_F(convert_event_test, tmp_example) {
uint64_t ts = 12;
int64_t tid = 25;

// At the moment we don't have event managed by the converter so this should fail.
assert_single_conversion_failure(create_safe_scap_event(ts, tid, PPME_SYSCALL_OPEN_E, 0));
}
55 changes: 55 additions & 0 deletions test/libscap/test_suites/userspace/scap_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,58 @@ TEST(scap_event, empty_buffers) {
EXPECT_EQ(decoded_params[0].size, sizeof(uint64_t));
EXPECT_EQ(decoded_params[1].size, 0);
}

TEST(scap_event, test_scap_create_event) {
char error[SCAP_LASTERR_SIZE];
uint64_t ts = 12;
int64_t tid = 25;
int64_t fd = 6;
const char *name = "/etc/passwd";
uint32_t flags = 0;
uint32_t mode = 37;
uint32_t dev = 0;
uint64_t ino = 0;
scap_evt *evt = scap_create_event(error,
ts,
tid,
PPME_SYSCALL_OPEN_X,
6,
fd,
name,
flags,
mode,
dev,
ino);
if(evt == NULL) {
FAIL() << "Error creating event: " << error;
}
uint16_t total_evt_len = 78;
// Assert header
ASSERT_EQ(evt->ts, ts);
ASSERT_EQ(evt->tid, tid);
ASSERT_EQ(evt->type, PPME_SYSCALL_OPEN_X);
ASSERT_EQ(evt->len, total_evt_len);
ASSERT_EQ(evt->nparams, 6);
// Assert len array
uint16_t *lens16 = (uint16_t *)((char *)evt + sizeof(scap_evt));
ASSERT_EQ(lens16[0], 8);
ASSERT_EQ(lens16[1], 12);
ASSERT_EQ(lens16[2], 4);
ASSERT_EQ(lens16[3], 4);
ASSERT_EQ(lens16[4], 4);
ASSERT_EQ(lens16[5], 8);
// Assert parameters
char *val = ((char *)evt + sizeof(scap_evt) + 6 * sizeof(uint16_t));
ASSERT_EQ(*(int32_t *)val, fd);
val += 8;
ASSERT_STREQ(val, name);
val += 12;
ASSERT_EQ(*(uint32_t *)val, flags);
val += 4;
ASSERT_EQ(*(uint32_t *)val, mode);
val += 4;
ASSERT_EQ(*(uint32_t *)val, dev);
val += 4;
ASSERT_EQ(*(uint64_t *)val, ino);
free(evt);
}
1 change: 1 addition & 0 deletions userspace/libscap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ add_library(
scap_event_schema STATIC
scap_event.c
ppm_sc_names.c
scap_print_event.c
${LIBS_DIR}/driver/dynamic_params_table.c
${LIBS_DIR}/driver/event_table.c
${LIBS_DIR}/driver/flags_table.c
Expand Down
8 changes: 6 additions & 2 deletions userspace/libscap/engine/savefile/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
#
# Since we have circular dependencies between libscap and the savefile engine, make this library
# always static (directly linked into libscap)
add_subdirectory(converter)
add_library(scap_engine_savefile STATIC scap_savefile.c scap_reader_gzfile.c scap_reader_buffered.c)

add_dependencies(scap_engine_savefile zlib)
target_link_libraries(scap_engine_savefile PRIVATE scap_engine_noop scap_platform_util ${ZLIB_LIB})
add_dependencies(scap_engine_savefile zlib scap_savefile_converter)
target_link_libraries(
scap_engine_savefile PRIVATE scap_engine_noop scap_platform_util scap_savefile_converter
${ZLIB_LIB}
)
24 changes: 24 additions & 0 deletions userspace/libscap/engine/savefile/converter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2024 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.
#

# Since we have circular dependencies between libscap and the savefile engine, make this library
# always static (directly linked into libscap)
add_library(scap_savefile_converter STATIC converter.cpp)

add_dependencies(scap_savefile_converter uthash)
target_include_directories(
scap_savefile_converter PRIVATE ${LIBS_DIR} ${LIBS_DIR}/userspace
${LIBS_DIR}/userspace/libscap/engine/savefile
)
Loading
Loading