From 4b09b0b40dde3e9283a7d633ec29dd42a040405a Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 29 Nov 2024 16:37:39 +0100 Subject: [PATCH 01/11] new: extend READ_X/PREAD_X Signed-off-by: Andrea Terzolo --- driver/SCHEMA_VERSION | 2 +- driver/bpf/fillers.h | 72 +++++++++--- driver/event_table.c | 23 ++-- driver/fillers_table.c | 2 +- .../syscall_dispatched_events/pread64.bpf.c | 12 ++ .../syscall_dispatched_events/read.bpf.c | 11 +- driver/ppm_fillers.c | 107 +++++++++++++----- driver/ppm_fillers.h | 1 + .../syscall_exit_suite/pread64_x.cpp | 11 +- .../test_suites/syscall_exit_suite/read_x.cpp | 34 ++++-- userspace/libscap/engine/gvisor/fillers.cpp | 22 +++- userspace/libscap/engine/gvisor/fillers.h | 9 +- userspace/libscap/engine/gvisor/parsers.cpp | 9 +- userspace/libscap/scap.h | 2 +- userspace/libscap/scap_api_version.c | 23 ++-- 15 files changed, 253 insertions(+), 87 deletions(-) diff --git a/driver/SCHEMA_VERSION b/driver/SCHEMA_VERSION index e9763f6bfe..4a36342fca 100644 --- a/driver/SCHEMA_VERSION +++ b/driver/SCHEMA_VERSION @@ -1 +1 @@ -2.23.0 +3.0.0 diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 7c65d66417..8a7fb4396f 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -407,28 +407,30 @@ FILLER(sys_read_e, true) { } FILLER(sys_read_x, true) { - unsigned long bufsize; - unsigned long val; - long retval; - int res; - /* Parameter 1: res (type: PT_ERRNO) */ - retval = bpf_syscall_get_retval(data->ctx); - res = bpf_push_s64_to_ring(data, (int64_t)retval); + long retval = bpf_syscall_get_retval(data->ctx); + int res = bpf_push_s64_to_ring(data, (int64_t)retval); CHECK_RES(res); - if(retval < 0) { - /* Parameter 2: data (type: PT_BYTEBUF) */ - return bpf_push_empty_param(data); + // We will use it for dynamic snaplen calculation and we will push it also to the buffer. + data->fd = bpf_syscall_get_argument(data, 0); + + /* Parameter 2: data (type: PT_BYTEBUF) */ + if(retval > 0) { + unsigned long val = bpf_syscall_get_argument(data, 1); + res = __bpf_val_to_ring(data, val, retval, PT_BYTEBUF, -1, true, USER); + } else { + res = bpf_push_empty_param(data); } + CHECK_RES(res); - val = bpf_syscall_get_argument(data, 1); - bufsize = retval; + /* Parameter 3: fd (type: PT_FD) */ + res = bpf_push_s64_to_ring(data, (int64_t)data->fd); + CHECK_RES(res); - /* Parameter 2: data (type: PT_BYTEBUF) */ - data->fd = bpf_syscall_get_argument(data, 0); - return __bpf_val_to_ring(data, val, bufsize, PT_BYTEBUF, -1, true, USER); - ; + /* Parameter 4: size (type: PT_UINT32) */ + size_t size = bpf_syscall_get_argument(data, 2); + return bpf_push_u32_to_ring(data, size); } FILLER(sys_write_e, true) { @@ -4753,6 +4755,44 @@ FILLER(sys_pread64_e, true) { return bpf_push_u64_to_ring(data, val); } +FILLER(sys_pread64_x, true) { +// This is due to the `pos` parameter +#ifndef CAPTURE_64BIT_ARGS_SINGLE_REGISTER +#error Implement this +#endif + unsigned long val = 0; + + /* Parameter 1: res (type: PT_ERRNO) */ + long retval = bpf_syscall_get_retval(data->ctx); + int res = bpf_push_s64_to_ring(data, (int64_t)retval); + CHECK_RES(res); + + // We will use it for dynamic snaplen calculation and we will push it also to the buffer. + data->fd = bpf_syscall_get_argument(data, 0); + + /* Parameter 2: data (type: PT_BYTEBUF) */ + if(retval > 0) { + val = bpf_syscall_get_argument(data, 1); + res = __bpf_val_to_ring(data, val, retval, PT_BYTEBUF, -1, true, USER); + } else { + res = bpf_push_empty_param(data); + } + CHECK_RES(res); + + /* Parameter 3: fd (type: PT_FD) */ + res = bpf_push_s64_to_ring(data, (int64_t)data->fd); + CHECK_RES(res); + + /* Parameter 4: size (type: PT_UINT32) */ + size_t size = bpf_syscall_get_argument(data, 2); + res = bpf_push_u32_to_ring(data, size); + CHECK_RES(res); + + /* Parameter 5: pos (type: PT_UINT64) */ + val = bpf_syscall_get_argument(data, 3); + return bpf_push_u64_to_ring(data, val); +} + FILLER(sys_pwrite64_e, true) { #ifndef CAPTURE_64BIT_ARGS_SINGLE_REGISTER #error Implement this diff --git a/driver/event_table.c b/driver/event_table.c index 66d7b3bb5c..3a13b26cb2 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -85,14 +85,17 @@ const struct ppm_event_info g_event_info[] = { {{"res", PT_ERRNO, PF_DEC}}}, [PPME_SYSCALL_READ_E] = {"read", EC_IO_READ | EC_SYSCALL, - EF_USES_FD | EF_READS_FROM_FD, + EF_USES_FD | EF_READS_FROM_FD | EF_TMP_CONVERTER_MANAGED, 2, {{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC}}}, [PPME_SYSCALL_READ_X] = {"read", EC_IO_READ | EC_SYSCALL, - EF_USES_FD | EF_READS_FROM_FD, - 2, - {{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}}, + EF_USES_FD | EF_READS_FROM_FD | EF_TMP_CONVERTER_MANAGED, + 4, + {{"res", PT_ERRNO, PF_DEC}, + {"data", PT_BYTEBUF, PF_NA}, + {"fd", PT_FD, PF_DEC}, + {"size", PT_UINT32, PF_DEC}}}, [PPME_SYSCALL_WRITE_E] = {"write", EC_IO_WRITE | EC_SYSCALL, EF_USES_FD | EF_WRITES_TO_FD, @@ -549,16 +552,20 @@ const struct ppm_event_info g_event_info[] = { {"unlinkat", EC_FILE | EC_SYSCALL, EF_OLD_VERSION, 1, {{"res", PT_ERRNO, PF_DEC}}}, [PPME_SYSCALL_PREAD_E] = {"pread", EC_IO_READ | EC_SYSCALL, - EF_USES_FD | EF_READS_FROM_FD, + EF_USES_FD | EF_READS_FROM_FD | EF_TMP_CONVERTER_MANAGED, 3, {{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC}, {"pos", PT_UINT64, PF_DEC}}}, [PPME_SYSCALL_PREAD_X] = {"pread", EC_IO_READ | EC_SYSCALL, - EF_USES_FD | EF_READS_FROM_FD, - 2, - {{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}}, + EF_USES_FD | EF_READS_FROM_FD | EF_TMP_CONVERTER_MANAGED, + 5, + {{"res", PT_ERRNO, PF_DEC}, + {"data", PT_BYTEBUF, PF_NA}, + {"fd", PT_FD, PF_DEC}, + {"size", PT_UINT32, PF_DEC}, + {"pos", PT_UINT64, PF_DEC}}}, [PPME_SYSCALL_PWRITE_E] = {"pwrite", EC_IO_WRITE | EC_SYSCALL, EF_USES_FD | EF_WRITES_TO_FD, diff --git a/driver/fillers_table.c b/driver/fillers_table.c index 65b0d90926..c88a4b086c 100644 --- a/driver/fillers_table.c +++ b/driver/fillers_table.c @@ -115,7 +115,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = { [PPME_SYSCALL_UNLINKAT_E] = {FILLER_REF(sys_autofill), 2, APT_REG, {{0}, {1}}}, [PPME_SYSCALL_UNLINKAT_X] = {FILLER_REF(sys_single_x)}, [PPME_SYSCALL_PREAD_E] = {FILLER_REF(sys_pread64_e)}, - [PPME_SYSCALL_PREAD_X] = {FILLER_REF(sys_read_x)}, + [PPME_SYSCALL_PREAD_X] = {FILLER_REF(sys_pread64_x)}, [PPME_SYSCALL_PWRITE_E] = {FILLER_REF(sys_pwrite64_e)}, [PPME_SYSCALL_PWRITE_X] = {FILLER_REF(sys_write_x)}, [PPME_SYSCALL_READV_E] = {FILLER_REF(sys_readv_e)}, diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/pread64.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/pread64.bpf.c index 25c650e03a..2ebf111b80 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/pread64.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/pread64.bpf.c @@ -77,6 +77,18 @@ int BPF_PROG(pread64_x, struct pt_regs *regs, long ret) { auxmap__store_empty_param(auxmap); } + /* Parameter 3: fd (type: PT_FD) */ + int32_t fd = (int32_t)extract__syscall_argument(regs, 0); + auxmap__store_s64_param(auxmap, (int64_t)fd); + + /* Parameter 4: size (type: PT_UINT32) */ + uint32_t size = (uint32_t)extract__syscall_argument(regs, 2); + auxmap__store_u32_param(auxmap, (uint32_t)size); + + /* Parameter 5: pos (type: PT_UINT64) */ + uint64_t pos = (uint64_t)extract__syscall_argument(regs, 3); + auxmap__store_u64_param(auxmap, pos); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/read.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/read.bpf.c index c6df32c6ba..5496945015 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/read.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/read.bpf.c @@ -55,6 +55,7 @@ int BPF_PROG(read_x, struct pt_regs *regs, long ret) { /* Parameter 1: res (type: PT_ERRNO) */ auxmap__store_s64_param(auxmap, ret); + /* Parameter 2: data (type: PT_BYTEBUF) */ if(ret > 0) { /* We read the minimum between `snaplen` and what we really * have in the buffer. @@ -65,14 +66,20 @@ int BPF_PROG(read_x, struct pt_regs *regs, long ret) { snaplen = ret; } - /* Parameter 2: data (type: PT_BYTEBUF) */ unsigned long data_pointer = extract__syscall_argument(regs, 1); auxmap__store_bytebuf_param(auxmap, data_pointer, snaplen, USER); } else { - /* Parameter 2: data (type: PT_BYTEBUF) */ auxmap__store_empty_param(auxmap); } + /* Parameter 3: fd (type: PT_FD) */ + int32_t fd = (int32_t)extract__syscall_argument(regs, 0); + auxmap__store_s64_param(auxmap, (int64_t)fd); + + /* Parameter 4: size (type: PT_UINT32) */ + uint32_t size = (uint32_t)extract__syscall_argument(regs, 2); + auxmap__store_u32_param(auxmap, size); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 4bbc7016c2..b11a4540af 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -403,45 +403,34 @@ int f_sys_read_x(struct event_filler_arguments *args) { unsigned long val; int res; int64_t retval; - unsigned long bufsize; - /* - * Retrieve the FD. It will be used for dynamic snaplen calculation. - */ + // Retrieve the FD. It will be used for dynamic snaplen calculation. syscall_get_arguments_deprecated(args, 0, 1, &val); args->fd = (int)val; - /* - * res - */ + /* Parameter 1: res (type: PT_ERRNO) */ retval = (int64_t)(long)syscall_get_return_value(current, args->regs); res = val_to_ring(args, retval, 0, false, 0); CHECK_RES(res); - /* - * data - */ - if(retval < 0) { - /* - * The operation failed, return an empty buffer - */ - val = 0; - bufsize = 0; - } else { + /* Parameter 2: data (type: PT_BYTEBUF) */ + if(retval > 0) { + // val now contains the pointer to the buffer syscall_get_arguments_deprecated(args, 1, 1, &val); - - /* - * The return value can be lower than the value provided by the user, - * and we take that into account. - */ - bufsize = retval; + args->enforce_snaplen = true; + res = val_to_ring(args, val, retval, true, 0); + } else { + res = push_empty_param(args); } + CHECK_RES(res); - /* - * Copy the buffer - */ - args->enforce_snaplen = true; - res = val_to_ring(args, val, bufsize, true, 0); + /* Parameter 3: fd (type: PT_FD) */ + res = val_to_ring(args, (int64_t)args->fd, 0, false, 0); + CHECK_RES(res); + + /* Parameter 4: size (type: PT_UINT32) */ + syscall_get_arguments_deprecated(args, 2, 1, &val); + res = val_to_ring(args, val, 0, false, 0); CHECK_RES(res); return add_sentinel(args); @@ -3688,6 +3677,68 @@ int f_sys_pread64_e(struct event_filler_arguments *args) { return add_sentinel(args); } +int f_sys_pread64_x(struct event_filler_arguments *args) { + unsigned long val; + int res; + int64_t retval; + unsigned long pos64; + + // Retrieve the FD. It will be used for dynamic snaplen calculation. + syscall_get_arguments_deprecated(args, 0, 1, &val); + args->fd = (int)val; + + /* Parameter 1: res (type: PT_ERRNO) */ + retval = (int64_t)(long)syscall_get_return_value(current, args->regs); + res = val_to_ring(args, retval, 0, false, 0); + CHECK_RES(res); + + /* Parameter 2: data (type: PT_BYTEBUF) */ + if(retval > 0) { + // val now contains the pointer to the buffer + syscall_get_arguments_deprecated(args, 1, 1, &val); + args->enforce_snaplen = true; + res = val_to_ring(args, val, retval, true, 0); + } else { + res = push_empty_param(args); + } + CHECK_RES(res); + + /* Parameter 3: fd (type: PT_FD) */ + res = val_to_ring(args, (int64_t)args->fd, 0, false, 0); + CHECK_RES(res); + + /* Parameter 4: size (type: PT_UINT32) */ + syscall_get_arguments_deprecated(args, 2, 1, &val); + res = val_to_ring(args, val, 0, false, 0); + CHECK_RES(res); + + /* Parameter 5: pos (type: PT_UINT64) */ +#ifndef CAPTURE_64BIT_ARGS_SINGLE_REGISTER + { + unsigned long pos0; + unsigned long pos1; +#if defined CONFIG_X86 + syscall_get_arguments_deprecated(args, 3, 1, &pos0); + syscall_get_arguments_deprecated(args, 4, 1, &pos1); +#elif defined CONFIG_ARM && CONFIG_AEABI + syscall_get_arguments_deprecated(args, 4, 1, &pos0); + syscall_get_arguments_deprecated(args, 5, 1, &pos1); +#else +#error This architecture/abi not yet supported +#endif + + pos64 = merge_64(pos1, pos0); + } +#else + syscall_get_arguments_deprecated(args, 3, 1, &pos64); +#endif + + res = val_to_ring(args, pos64, 0, false, 0); + CHECK_RES(res); + + return add_sentinel(args); +} + int f_sys_pwrite64_e(struct event_filler_arguments *args) { unsigned long val; unsigned long size; diff --git a/driver/ppm_fillers.h b/driver/ppm_fillers.h index 32e55ac77e..fba89c8c48 100644 --- a/driver/ppm_fillers.h +++ b/driver/ppm_fillers.h @@ -191,6 +191,7 @@ or GPL2.txt for full copies of the license. FN(sys_process_vm_readv_x) \ FN(sys_process_vm_writev_x) \ FN(sys_delete_module_x) \ + FN(sys_pread64_x) \ FN(terminate_filler) #define FILLER_ENUM_FN(x) PPM_FILLER_##x, diff --git a/test/drivers/test_suites/syscall_exit_suite/pread64_x.cpp b/test/drivers/test_suites/syscall_exit_suite/pread64_x.cpp index 612df847aa..ff0a621b5e 100644 --- a/test/drivers/test_suites/syscall_exit_suite/pread64_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/pread64_x.cpp @@ -40,9 +40,18 @@ TEST(SyscallExit, preadX_fail) { /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_empty_param(2); + /* Parameter 3: fd (type: PT_FD) */ + evt_test->assert_numeric_param(3, int64_t(-1)); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, uint32_t(size)); + + /* Parameter 5: pos (type: PT_UINT64) */ + evt_test->assert_numeric_param(5, uint64_t(pos)); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } #endif diff --git a/test/drivers/test_suites/syscall_exit_suite/read_x.cpp b/test/drivers/test_suites/syscall_exit_suite/read_x.cpp index 9193859422..bcc6c2e08c 100644 --- a/test/drivers/test_suites/syscall_exit_suite/read_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/read_x.cpp @@ -46,9 +46,15 @@ TEST(SyscallExit, readX_no_snaplen) { /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, read_bytes); + /* Parameter 3: fd (type: PT_FD) */ + evt_test->assert_numeric_param(3, (int64_t)fd); + + /* Parameter 4: size (type: PT_UINT32)*/ + evt_test->assert_numeric_param(4, (uint32_t)data_len); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_snaplen) { @@ -93,9 +99,15 @@ TEST(SyscallExit, readX_snaplen) { /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 3: fd (type: PT_FD) */ + evt_test->assert_numeric_param(3, (int64_t)fd); + + /* Parameter 4: size (type: PT_UINT32)*/ + evt_test->assert_numeric_param(4, (uint32_t)data_len); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readXfail) { @@ -134,9 +146,15 @@ TEST(SyscallExit, readXfail) { /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_empty_param(2); + /* Parameter 3: fd (type: PT_FD) */ + evt_test->assert_numeric_param(3, (int64_t)-1); + + /* Parameter 4: size (type: PT_UINT32)*/ + evt_test->assert_numeric_param(4, (uint32_t)data_len); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_ipv4_tcp_message_truncated_by_snaplen) { @@ -174,7 +192,7 @@ TEST(SyscallExit, readX_ipv4_tcp_message_truncated_by_snaplen) { /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_ipv4_tcp_message_not_truncated_fullcapture_port) { @@ -225,7 +243,7 @@ TEST(SyscallExit, readX_ipv4_tcp_message_not_truncated_fullcapture_port) { /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_ipv4_udp_message_truncated_by_snaplen) { @@ -263,7 +281,7 @@ TEST(SyscallExit, readX_ipv4_udp_message_truncated_by_snaplen) { /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_ipv4_udp_message_truncated_fullcapture_client_port) { @@ -314,7 +332,7 @@ TEST(SyscallExit, readX_ipv4_udp_message_truncated_fullcapture_client_port) { /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } TEST(SyscallExit, readX_ipv4_udp_message_not_truncated_fullcapture_server_port) { @@ -365,7 +383,7 @@ TEST(SyscallExit, readX_ipv4_udp_message_not_truncated_fullcapture_server_port) /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(4); } #endif diff --git a/userspace/libscap/engine/gvisor/fillers.cpp b/userspace/libscap/engine/gvisor/fillers.cpp index 7cbafc280b..48de12dfae 100644 --- a/userspace/libscap/engine/gvisor/fillers.cpp +++ b/userspace/libscap/engine/gvisor/fillers.cpp @@ -601,14 +601,18 @@ int32_t fill_event_read_e(scap_sized_buffer scap_buf, int32_t fill_event_read_x(scap_sized_buffer scap_buf, size_t* event_size, char* scap_err, - int64_t res) { + int64_t res, + int64_t fd, + uint32_t size) { return scap_event_encode_params(scap_buf, event_size, scap_err, PPME_SYSCALL_READ_X, - 2, + 4, res, - scap_const_sized_buffer{NULL, 0}); // data -- INVALID + scap_const_sized_buffer{NULL, 0}, // data -- INVALID + fd, + size); } // PPME_SYSCALL_PREAD_E @@ -636,14 +640,20 @@ int32_t fill_event_pread_e(scap_sized_buffer scap_buf, int32_t fill_event_pread_x(scap_sized_buffer scap_buf, size_t* event_size, char* scap_err, - int64_t res) { + int64_t res, + int64_t fd, + uint32_t size, + uint64_t pos) { return scap_event_encode_params(scap_buf, event_size, scap_err, PPME_SYSCALL_PREAD_X, - 2, + 5, res, - scap_const_sized_buffer{NULL, 0}); // data -- INVALID + scap_const_sized_buffer{NULL, 0}, // data -- INVALID + fd, + size, + pos); } // PPME_SYSCALL_READV_E diff --git a/userspace/libscap/engine/gvisor/fillers.h b/userspace/libscap/engine/gvisor/fillers.h index a25b14f88f..d7b7b8bd9a 100644 --- a/userspace/libscap/engine/gvisor/fillers.h +++ b/userspace/libscap/engine/gvisor/fillers.h @@ -194,7 +194,9 @@ int32_t fill_event_read_e(scap_sized_buffer scap_buf, int32_t fill_event_read_x(scap_sized_buffer scap_buf, size_t* event_size, char* scap_err, - int64_t res); + int64_t res, + int64_t fd, + uint32_t size); int32_t fill_event_pread_e(scap_sized_buffer scap_buf, size_t* event_size, @@ -206,7 +208,10 @@ int32_t fill_event_pread_e(scap_sized_buffer scap_buf, int32_t fill_event_pread_x(scap_sized_buffer scap_buf, size_t* event_size, char* scap_err, - int64_t res); + int64_t res, + int64_t fd, + uint32_t size, + uint64_t pos); int32_t fill_event_readv_e(scap_sized_buffer scap_buf, size_t* event_size, diff --git a/userspace/libscap/engine/gvisor/parsers.cpp b/userspace/libscap/engine/gvisor/parsers.cpp index d3b2515d49..73cdaedeca 100644 --- a/userspace/libscap/engine/gvisor/parsers.cpp +++ b/userspace/libscap/engine/gvisor/parsers.cpp @@ -471,14 +471,19 @@ static parse_result parse_read(uint32_t id, ret.status = scap_gvisor::fillers::fill_event_read_x(scap_buf, &ret.size, scap_err, - gvisor_evt.exit().result()); + gvisor_evt.exit().result(), + gvisor_evt.fd(), + gvisor_evt.count()); break; case __NR_pread64: ret.status = scap_gvisor::fillers::fill_event_pread_x(scap_buf, &ret.size, scap_err, - gvisor_evt.exit().result()); + gvisor_evt.exit().result(), + gvisor_evt.fd(), + gvisor_evt.count(), + gvisor_evt.offset()); break; case __NR_readv: diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 7136090e51..8d332060f0 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -102,7 +102,7 @@ struct scap_vtable; // and handle the result // #define SCAP_MINIMUM_DRIVER_API_VERSION PPM_API_VERSION(8, 0, 0) -#define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(2, 0, 0) +#define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(3, 0, 0) // // This is the dimension we used before introducing the variable buffer size. diff --git a/userspace/libscap/scap_api_version.c b/userspace/libscap/scap_api_version.c index c87c54a05a..c522c06efe 100644 --- a/userspace/libscap/scap_api_version.c +++ b/userspace/libscap/scap_api_version.c @@ -63,17 +63,18 @@ static int32_t check_api_compatibility_impl(uint64_t current_version, const char* label, char* error) { if(!scap_is_api_compatible(current_version, minimum_version)) { - return scap_errprintf(error, - 0, - "Driver supports %s version %llu.%llu.%llu, but running version " - "needs %llu.%llu.%llu", - label, - PPM_API_VERSION_MAJOR(current_version), - PPM_API_VERSION_MINOR(current_version), - PPM_API_VERSION_PATCH(current_version), - PPM_API_VERSION_MAJOR(minimum_version), - PPM_API_VERSION_MINOR(minimum_version), - PPM_API_VERSION_PATCH(minimum_version)); + return scap_errprintf( + error, + 0, + "Minimum %s version supported by scap: %llu.%llu.%llu, but the running " + "driver uses %llu.%llu.%llu", + label, + PPM_API_VERSION_MAJOR(current_version), + PPM_API_VERSION_MINOR(current_version), + PPM_API_VERSION_PATCH(current_version), + PPM_API_VERSION_MAJOR(minimum_version), + PPM_API_VERSION_MINOR(minimum_version), + PPM_API_VERSION_PATCH(minimum_version)); } return SCAP_SUCCESS; } From 42f5ff5435dd76b9c917ba7b1e879476cc037fd4 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 29 Nov 2024 16:38:32 +0100 Subject: [PATCH 02/11] new: add READ_X/PREAD_X conversion Signed-off-by: Andrea Terzolo --- .../engines/savefile/converter.cpp | 158 +++++++++++++++++- .../engine/savefile/converter/table.cpp | 17 +- 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/test/libscap/test_suites/engines/savefile/converter.cpp b/test/libscap/test_suites/engines/savefile/converter.cpp index 2b46b80781..e38c4ee6d1 100644 --- a/test/libscap/test_suites/engines/savefile/converter.cpp +++ b/test/libscap/test_suites/engines/savefile/converter.cpp @@ -13,11 +13,161 @@ 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) { +//////////////////////////// +// READ +//////////////////////////// + +TEST_F(convert_event_test, PPME_SYSCALL_READ_E_store) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t fd = 25; + uint32_t size = 89; + + auto evt = create_safe_scap_event(ts, tid, PPME_SYSCALL_READ_E, 2, fd, size); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); +} + +TEST_F(convert_event_test, PPME_SYSCALL_READ_X_to_4_params_no_enter) { 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)); + int64_t res = 89; + uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + + // Defaulted to 0 + int64_t fd = 0; + uint32_t size = 0; + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_READ_X, + 2, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}), + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_READ_X, + 4, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + fd, + size)); +} + +TEST_F(convert_event_test, PPME_SYSCALL_READ_X__to_4_params_with_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + int64_t fd = 25; + uint32_t size = 36; + + // After the first conversion we should have the storage + auto evt = create_safe_scap_event(ts, tid, PPME_SYSCALL_READ_E, 2, fd, size); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_READ_X, + 2, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}), + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_READ_X, + 4, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + fd, + size)); +} + +//////////////////////////// +// PREAD +//////////////////////////// + +TEST_F(convert_event_test, PPME_SYSCALL_PREAD_E_store) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t fd = 25; + uint32_t size = 89; + uint64_t pos = 7; + + auto evt = create_safe_scap_event(ts, tid, PPME_SYSCALL_PREAD_E, 3, fd, size, pos); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); +} + +TEST_F(convert_event_test, PPME_SYSCALL_PREAD_X_to_4_params_no_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + + // Defaulted to 0 + int64_t fd = 0; + uint32_t size = 0; + int64_t pos = 0; + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_PREAD_X, + 2, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}), + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_PREAD_X, + 5, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + fd, + size, + pos)); +} + +TEST_F(convert_event_test, PPME_SYSCALL_PREAD_X__to_4_params_with_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + int64_t fd = 25; + uint32_t size = 36; + uint64_t pos = 7; + + // After the first conversion we should have the storage + auto evt = create_safe_scap_event(ts, tid, PPME_SYSCALL_PREAD_E, 3, fd, size, pos); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_PREAD_X, + 2, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}), + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_PREAD_X, + 5, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + fd, + size, + pos)); } diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp index cac323ffca..39f01ecbdf 100644 --- a/userspace/libscap/engine/savefile/converter/table.cpp +++ b/userspace/libscap/engine/savefile/converter/table.cpp @@ -20,4 +20,19 @@ limitations under the License. #include #include -const std::unordered_map g_conversion_table = {}; +const std::unordered_map g_conversion_table = { + //////////////////////////// + // READ + //////////////////////////// + {{PPME_SYSCALL_READ_E, 2}, {.action = C_ACTION_STORE}}, + {{PPME_SYSCALL_READ_X, 2}, + {.action = C_ACTION_ADD_PARAMS, + .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}}}}, + //////////////////////////// + // PREAD + //////////////////////////// + {{PPME_SYSCALL_PREAD_E, 3}, {.action = C_ACTION_STORE}}, + {{PPME_SYSCALL_PREAD_X, 2}, + {.action = C_ACTION_ADD_PARAMS, + .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}, {C_INSTR_FROM_ENTER, 2}}}}, +}; From 2274a15297d250a5951597ac129d49d32d81beb9 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 29 Nov 2024 16:38:59 +0100 Subject: [PATCH 03/11] update(tests): update some sinsp tests Signed-off-by: Andrea Terzolo --- userspace/libsinsp/test/filter_op_bcontains.ut.cpp | 6 ++++-- userspace/libsinsp/test/filter_transformer.ut.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/userspace/libsinsp/test/filter_op_bcontains.ut.cpp b/userspace/libsinsp/test/filter_op_bcontains.ut.cpp index e5c236fdab..e8354661b7 100644 --- a/userspace/libsinsp/test/filter_op_bcontains.ut.cpp +++ b/userspace/libsinsp/test/filter_op_bcontains.ut.cpp @@ -30,9 +30,11 @@ TEST_F(sinsp_with_test_input, bcontains_bstartswith) { sinsp_evt* evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_READ_X, - 2, + 4, (int64_t)0, - scap_const_sized_buffer{read_buf, sizeof(read_buf)}); + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + (int64_t)0, + (uint32_t)0); // test filters with bcontains EXPECT_FALSE(filter_compiles("evt.buffer bcontains")); diff --git a/userspace/libsinsp/test/filter_transformer.ut.cpp b/userspace/libsinsp/test/filter_transformer.ut.cpp index d40ce639c9..81262276a2 100644 --- a/userspace/libsinsp/test/filter_transformer.ut.cpp +++ b/userspace/libsinsp/test/filter_transformer.ut.cpp @@ -405,9 +405,11 @@ TEST_F(sinsp_with_test_input, len_transformer) { evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_READ_X, - 2, + 4, (int64_t)0, - scap_const_sized_buffer{read_buf, sizeof(read_buf)}); + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + (int64_t)0, + (uint32_t)0); EXPECT_TRUE(eval_filter(evt, "len(evt.arg.data) == 6")); } From 32cd3a46c7b9a12ec9f04663539ac46905ac32ac Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 29 Nov 2024 17:16:32 +0100 Subject: [PATCH 04/11] update(tests): adapt old scap-file tests We cannot rely anymore on the event number to search an event since we could filter some enter events in the middle Signed-off-by: Andrea Terzolo --- .../scap_files/kexec_arm64/kexec_arm64.cpp | 31 ++-- .../test/scap_files/kexec_x86/kexec_x86.cpp | 37 ++--- .../libsinsp/test/scap_files/scap_file_test.h | 142 ++++++++++++++++++ 3 files changed, 170 insertions(+), 40 deletions(-) create mode 100644 userspace/libsinsp/test/scap_files/scap_file_test.h diff --git a/userspace/libsinsp/test/scap_files/kexec_arm64/kexec_arm64.cpp b/userspace/libsinsp/test/scap_files/kexec_arm64/kexec_arm64.cpp index e55e0241b6..6e9c3830ff 100644 --- a/userspace/libsinsp/test/scap_files/kexec_arm64/kexec_arm64.cpp +++ b/userspace/libsinsp/test/scap_files/kexec_arm64/kexec_arm64.cpp @@ -17,27 +17,23 @@ limitations under the License. */ -#include -#include +#include +#include -TEST(scap_file_kexec_arm64, tail_lineage) { - std::string path = LIBSINSP_TEST_SCAP_FILES_DIR + std::string("kexec_arm64.scap"); - sinsp m_inspector; - m_inspector.open_savefile(path); +TEST_F(scap_file_test, kexec_arm64_tail_lineage) { + open_filename("kexec_arm64.scap"); /* Check that containerd_shim main at the beginning is not a reaper since we cannot recover * that info from proc scan. */ - auto containerd_shim1_tinfo = m_inspector.get_thread_ref(141207); + auto containerd_shim1_tinfo = m_inspector->get_thread_ref(141207); ASSERT_TRUE(containerd_shim1_tinfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo); ASSERT_FALSE(containerd_shim1_tinfo->m_tginfo->is_reaper()); /* Search the tail execve event */ int64_t tid_tail = 141546; - auto evt = scap_file_test_helpers::capture_search_evt_by_type_and_tid(&m_inspector, - PPME_SYSCALL_EXECVE_19_X, - tid_tail); + auto evt = capture_search_evt_by_type_and_tid(PPME_SYSCALL_EXECVE_19_X, tid_tail); std::vector traverse_parents; sinsp_threadinfo::visitor_func_t visitor = [&traverse_parents](sinsp_threadinfo* pt) { @@ -79,18 +75,15 @@ TEST(scap_file_kexec_arm64, tail_lineage) { ASSERT_EQ(traverse_parents, expected_traverse_parents_after_execve); /* At the beninning of the capture containerd_shim1 was not a reaper */ - containerd_shim1_tinfo = m_inspector.get_thread_ref(tid_containerd_shim1); + containerd_shim1_tinfo = m_inspector->get_thread_ref(tid_containerd_shim1); ASSERT_TRUE(containerd_shim1_tinfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo->is_reaper()); } -TEST(scap_file_kexec_arm64, final_thread_table_dim) { - std::string path = LIBSINSP_TEST_SCAP_FILES_DIR + std::string("kexec_arm64.scap"); - sinsp m_inspector; - m_inspector.open_savefile(path); - - /* Get the final event of the capture and check the thread_table dim */ - scap_file_test_helpers::capture_search_evt_by_num(&m_inspector, 907459); - ASSERT_EQ(m_inspector.m_thread_manager->get_thread_count(), 612); +TEST_F(scap_file_test, kexec_arm64_final_thread_table_dim) { + open_filename("kexec_arm64.scap"); + read_until_EOF(); + /* Check the thread_table dim at the end of the capture */ + ASSERT_EQ(m_inspector->m_thread_manager->get_thread_count(), 612); } diff --git a/userspace/libsinsp/test/scap_files/kexec_x86/kexec_x86.cpp b/userspace/libsinsp/test/scap_files/kexec_x86/kexec_x86.cpp index 05231ec0d5..4d0063e743 100644 --- a/userspace/libsinsp/test/scap_files/kexec_x86/kexec_x86.cpp +++ b/userspace/libsinsp/test/scap_files/kexec_x86/kexec_x86.cpp @@ -17,27 +17,23 @@ limitations under the License. */ -#include -#include +#include +#include -TEST(scap_file_kexec_x86, tail_lineage) { - std::string path = LIBSINSP_TEST_SCAP_FILES_DIR + std::string("kexec_x86.scap"); - sinsp m_inspector; - m_inspector.open_savefile(path); +TEST_F(scap_file_test, kexec_x86_tail_lineage) { + open_filename("kexec_x86.scap"); /* Check that containerd_shim main at the beginning is not a reaper since we cannot recover * that info from proc scan. */ - auto containerd_shim1_tinfo = m_inspector.get_thread_ref(107196); + auto containerd_shim1_tinfo = m_inspector->get_thread_ref(107196); ASSERT_TRUE(containerd_shim1_tinfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo); ASSERT_FALSE(containerd_shim1_tinfo->m_tginfo->is_reaper()); /* Search the tail execve event */ int64_t tid_tail = 107370; - auto evt = scap_file_test_helpers::capture_search_evt_by_type_and_tid(&m_inspector, - PPME_SYSCALL_EXECVE_19_X, - tid_tail); + auto evt = capture_search_evt_by_type_and_tid(PPME_SYSCALL_EXECVE_19_X, tid_tail); std::vector traverse_parents; sinsp_threadinfo::visitor_func_t visitor = [&traverse_parents](sinsp_threadinfo* pt) { @@ -82,8 +78,10 @@ TEST(scap_file_kexec_x86, tail_lineage) { evt->get_thread_info()->traverse_parent_state(visitor); ASSERT_EQ(traverse_parents, expected_traverse_parents_after_execve); - /* At event num `161343` all runc threads are dead */ - evt = scap_file_test_helpers::capture_search_evt_by_num(&m_inspector, 161343); + /* We search the event immediately after the proc_exit of last `runc` thread. + * It is a WRITE made by tid 107370. + */ + evt = capture_search_evt_by_type_and_tid(PPME_SYSCALL_WRITE_X, 107370); /* This should be the new father of [sh](107364) since it is a reaper */ tid_containerd_shim1 = 107196; @@ -110,18 +108,15 @@ TEST(scap_file_kexec_x86, tail_lineage) { ASSERT_EQ(traverse_parents, expected_traverse_parents_after_remove); /* At the beninning of the capture containerd_shim1 was not a reaper */ - containerd_shim1_tinfo = m_inspector.get_thread_ref(tid_containerd_shim1); + containerd_shim1_tinfo = m_inspector->get_thread_ref(tid_containerd_shim1); ASSERT_TRUE(containerd_shim1_tinfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo); ASSERT_TRUE(containerd_shim1_tinfo->m_tginfo->is_reaper()); } -TEST(scap_file_kexec_x86, final_thread_table_dim) { - std::string path = LIBSINSP_TEST_SCAP_FILES_DIR + std::string("kexec_x86.scap"); - sinsp m_inspector; - m_inspector.open_savefile(path); - - /* Get the final event of the capture and check the thread_table dim */ - scap_file_test_helpers::capture_search_evt_by_num(&m_inspector, 523413); - ASSERT_EQ(m_inspector.m_thread_manager->get_thread_count(), 558); +TEST_F(scap_file_test, kexec_x86_final_thread_table_dim) { + open_filename("kexec_x86.scap"); + read_until_EOF(); + /* Check the thread_table dim at the end of the capture */ + ASSERT_EQ(m_inspector->m_thread_manager->get_thread_count(), 558); } diff --git a/userspace/libsinsp/test/scap_files/scap_file_test.h b/userspace/libsinsp/test/scap_files/scap_file_test.h new file mode 100644 index 0000000000..d098097c88 --- /dev/null +++ b/userspace/libsinsp/test/scap_files/scap_file_test.h @@ -0,0 +1,142 @@ +// 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 +#include +#include +#include + +typedef std::unique_ptr safe_scap_evt_t; + +class scap_file_test : public testing::Test { +private: + safe_scap_evt_t create_safe_scap_evt(scap_evt* evt) { return safe_scap_evt_t{evt, free}; } + +protected: + void open_filename(const std::string file_name) { + std::string path = LIBSINSP_TEST_SCAP_FILES_DIR + file_name; + m_inspector = std::make_unique(); + m_inspector->open_savefile(path); + } + + void assert_num_event_type(ppm_event_code event_type, uint64_t expected_count) { + sinsp_evt* evt = nullptr; + int ret = SCAP_SUCCESS; + uint64_t count = 0; + while(1) { + ret = m_inspector->next(&evt); + if(ret == SCAP_EOF) { + break; + } + if(ret != SCAP_SUCCESS) { + throw std::runtime_error("Error reading event. scap_code: " + std::to_string(ret) + + ", " + m_inspector->getlasterr()); + } + if(evt->get_type() == event_type) { + count++; + } + } + ASSERT_EQ(count, expected_count); + } + + void assert_no_event_type(ppm_event_code event_type) { + sinsp_evt* evt = nullptr; + int ret = SCAP_SUCCESS; + while(1) { + ret = m_inspector->next(&evt); + if(ret == SCAP_EOF) { + break; + } + if(ret != SCAP_SUCCESS) { + throw std::runtime_error("Error reading event. scap_code: " + std::to_string(ret) + + ", " + m_inspector->getlasterr()); + } + if(evt->get_type() == event_type) { + FAIL(); + } + } + } + + 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 create_safe_scap_evt(evt); + } + + void assert_event_presence(safe_scap_evt_t expected_evt) { + sinsp_evt* evt = nullptr; + char error[SCAP_LASTERR_SIZE] = {'\0'}; + int ret = SCAP_SUCCESS; + while(1) { + ret = m_inspector->next(&evt); + if(ret == SCAP_EOF) { + break; + } + if(ret != SCAP_SUCCESS) { + throw std::runtime_error("Error reading event. scap_code: " + std::to_string(ret) + + ", " + m_inspector->getlasterr()); + } + if(evt->get_scap_evt()->ts == expected_evt->ts && + evt->get_scap_evt()->tid == expected_evt->tid) { + if(!scap_compare_events(evt->get_scap_evt(), expected_evt.get(), error)) { + printf("\nExpected event:\n"); + scap_print_event(expected_evt.get(), PRINT_FULL); + printf("\nConverted event:\n"); + scap_print_event(evt->get_scap_evt(), PRINT_FULL); + FAIL() << error; + } + return; + } + } + FAIL() << "There is no an event with ts: " << expected_evt->ts + << " and tid: " << expected_evt->tid; + } + + sinsp_evt* capture_search_evt_by_type_and_tid(uint64_t type, int64_t tid) { + sinsp_evt* evt; + int ret = SCAP_SUCCESS; + while(ret != SCAP_EOF) { + ret = m_inspector->next(&evt); + if(ret == SCAP_SUCCESS && evt->get_type() == type && evt->get_tid() == tid) { + return evt; + } + } + return NULL; + } + + void read_until_EOF() { + sinsp_evt* evt; + int ret = SCAP_SUCCESS; + while(ret != SCAP_EOF) { + ret = m_inspector->next(&evt); + } + } + + std::unique_ptr m_inspector; +}; From 4f77cea0c79d903d513c6d57009fd262af2f7293 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 30 Nov 2024 15:10:00 +0100 Subject: [PATCH 05/11] update: print hex representation for bytebuf Signed-off-by: Andrea Terzolo --- userspace/libscap/scap_print_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/userspace/libscap/scap_print_event.c b/userspace/libscap/scap_print_event.c index a1bb5190a9..b6626ad792 100644 --- a/userspace/libscap/scap_print_event.c +++ b/userspace/libscap/scap_print_event.c @@ -210,15 +210,15 @@ static void print_parameter(int16_t num_param, scap_evt *ev, uint16_t offset) { case PT_CHARBUF: case PT_FSPATH: + case PT_FSRELPATH: printf("PARAM %d: %s\n", num_param, valptr); break; case PT_BYTEBUF: case PT_CHARBUFARRAY: - case PT_FSRELPATH: - printf("PARAM %d: ", num_param); + printf("PARAM %d\n: ", num_param); for(int j = 0; j < len; j++) { - printf("%c", *(char *)(valptr + j)); + printf("%c(%x)\n", *(char *)(valptr + j), *(char *)(valptr + j)); } printf("\n"); break; From 98448e341205514dc3a06958eee64473c904fe43 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 30 Nov 2024 15:10:57 +0100 Subject: [PATCH 06/11] update: introduce scap-file conversion in savefile engine Signed-off-by: Andrea Terzolo --- userspace/libscap/engine/savefile/savefile.h | 3 + .../libscap/engine/savefile/scap_savefile.c | 105 ++++++++++++++++-- 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/userspace/libscap/engine/savefile/savefile.h b/userspace/libscap/engine/savefile/savefile.h index d68c43bf63..f39f00dd5f 100644 --- a/userspace/libscap/engine/savefile/savefile.h +++ b/userspace/libscap/engine/savefile/savefile.h @@ -110,4 +110,7 @@ struct savefile_engine { size_t m_reader_evt_buf_size; uint32_t m_last_evt_dump_flags; struct scap_platform* m_platform; + // Used by the scap-file converter + char* m_new_evt; + char* m_to_convert_evt; }; diff --git a/userspace/libscap/engine/savefile/scap_savefile.c b/userspace/libscap/engine/savefile/scap_savefile.c index 21db8ba120..19dedf2cae 100644 --- a/userspace/libscap/engine/savefile/scap_savefile.c +++ b/userspace/libscap/engine/savefile/scap_savefile.c @@ -30,6 +30,7 @@ struct iovec { #endif #define HANDLE(engine) ((struct savefile_engine *)(engine.m_handle)) +#define MAX_EVENT_SIZE 64 * 1024 #include #include @@ -39,8 +40,8 @@ struct iovec { #include #include #include - #include +#include // // Read the section header block @@ -1811,14 +1812,10 @@ static int32_t scap_read_init(struct savefile_engine *handle, return SCAP_SUCCESS; } -// -// Read an event from disk -// -static int32_t next(struct scap_engine_handle engine, - scap_evt **pevent, - uint16_t *pdevid, - uint32_t *pflags) { - struct savefile_engine *handle = engine.m_handle; +static int32_t next_event_from_file(struct savefile_engine *handle, + scap_evt **pevent, + uint16_t *pdevid, + uint32_t *pflags) { block_header bh; size_t readsize; uint32_t readlen; @@ -2022,6 +2019,86 @@ static int32_t next(struct scap_engine_handle engine, return SCAP_SUCCESS; } +// +// Read an event from disk +// +static int32_t next(struct scap_engine_handle engine, + scap_evt **pevent, + uint16_t *pdevid, + uint32_t *pflags) { + struct savefile_engine *handle = engine.m_handle; +read_event: + int32_t res = next_event_from_file(handle, pevent, pdevid, pflags); + // If we fail we don't convert the event. + if(res != SCAP_SUCCESS) { + return res; + } + + // If we don't need a conversion terminate here. + if(!is_conversion_needed((*pevent))) { + return SCAP_SUCCESS; + } + + // We do it only the first time if at least one conversion is needed. + if(!handle->m_new_evt) { + handle->m_new_evt = calloc(1, MAX_EVENT_SIZE); + } + if(!handle->m_to_convert_evt) { + handle->m_to_convert_evt = calloc(1, MAX_EVENT_SIZE); + } + + // Start the conversion loop. + 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++) { + // Before each conversion we move the current event into the storage + memcpy(handle->m_to_convert_evt, *pevent, (*pevent)->len); + conv_res = scap_convert_event((scap_evt *)handle->m_new_evt, + (scap_evt *)handle->m_to_convert_evt, + handle->m_lasterr); + // At the end of the conversion in any case we swith to the new event pointer + *pevent = (scap_evt *)handle->m_new_evt; + } + + switch(conv_res) { + case CONVERSION_ERROR: + return SCAP_FAILURE; + + case CONVERSION_SKIP: + // Probably an enter event that we don't want to consider. So we read another event. + goto read_event; + + case CONVERSION_COMPLETED: + case CONVERSION_CONTINUE: + default: + break; + } + + if(conv_num == MAX_CONVERSION_BOUNDARY) { + if(conv_res == CONVERSION_COMPLETED) { + // We reached the max conversion boundary with a correct conversion + // we need to bump `MAX_CONVERSION_BOUNDARY` in the code. + snprintf(handle->m_lasterr, + SCAP_LASTERR_SIZE, + "reached '%d' with a correct resolution. Bump it in the code.", + MAX_CONVERSION_BOUNDARY); + } else if(conv_res == CONVERSION_CONTINUE) { + // We forgot to end the conversion somewhere + snprintf(handle->m_lasterr, + SCAP_LASTERR_SIZE, + "reached '%d' conversions with evt (%d) without reaching an end", + MAX_CONVERSION_BOUNDARY, + (*pevent)->type); + } else { + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "Unknown error"); + } + return SCAP_FAILURE; + } + + return SCAP_SUCCESS; +} + uint64_t scap_savefile_ftell(struct scap_engine_handle engine) { scap_reader_t *reader = HANDLE(engine)->m_reader; return reader->tell(reader); @@ -2184,6 +2261,16 @@ static int32_t scap_savefile_close(struct scap_engine_handle engine) { handle->m_reader_evt_buf = NULL; } + if(handle->m_new_evt) { + free(handle->m_new_evt); + handle->m_new_evt = NULL; + } + + if(handle->m_to_convert_evt) { + free(handle->m_to_convert_evt); + handle->m_to_convert_evt = NULL; + } + return SCAP_SUCCESS; } From 1373517b160a8935a772752f4406d0057402eb8c Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Mon, 2 Dec 2024 09:43:37 +0100 Subject: [PATCH 07/11] new(tests): add some tests for scap-file conversion Signed-off-by: Andrea Terzolo --- userspace/libsinsp/test/CMakeLists.txt | 2 +- .../test/scap_files/converter_tests.cpp | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 userspace/libsinsp/test/scap_files/converter_tests.cpp diff --git a/userspace/libsinsp/test/CMakeLists.txt b/userspace/libsinsp/test/CMakeLists.txt index 84e9e4f9be..fb8c467547 100644 --- a/userspace/libsinsp/test/CMakeLists.txt +++ b/userspace/libsinsp/test/CMakeLists.txt @@ -52,7 +52,7 @@ if((NOT ${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "s390x") AND ${SCAP_FILES_SUITE_ # Binary dir in which we will save all our Cmake files file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/scap_files") # Add here the name for new scap-files - set(SCAP_FILE_NAMES "kexec_arm64.scap" "kexec_x86.scap" "sample.scap") + set(SCAP_FILE_NAMES "kexec_arm64.scap" "kexec_x86.scap" "sample.scap" "scap_2013.scap") set(SCAP_FILE_DOWNLOAD_PREFIX "https://falco-distribution.s3.eu-west-1.amazonaws.com/fixtures/libs/scap_files" ) diff --git a/userspace/libsinsp/test/scap_files/converter_tests.cpp b/userspace/libsinsp/test/scap_files/converter_tests.cpp new file mode 100644 index 0000000000..3bb42f5876 --- /dev/null +++ b/userspace/libsinsp/test/scap_files/converter_tests.cpp @@ -0,0 +1,131 @@ +// 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 + +// Use `sudo sysdig -r -S -q` to check the number of events in the scap file. +// When you find a specific event to assert use +// `sudo sysdig -r <> -d "evt.num =<>" -p "ts=%evt.rawtime,tid=%thread.tid,args=%evt.arg.args"` + +//////////////////////////// +// READ +//////////////////////////// + +TEST_F(scap_file_test, no_read_e) { + open_filename("scap_2013.scap"); + // we shouldn't see the enter events + assert_no_event_type(PPME_SYSCALL_READ_E); +} + +TEST_F(scap_file_test, read_x_same_number_of_exit_events) { + open_filename("scap_2013.scap"); + assert_num_event_type(PPME_SYSCALL_READ_X, 24957); +} + +TEST_F(scap_file_test, read_x_check_final_converted_event) { + open_filename("scap_2013.scap"); + + // Inside the scap-file the event `430682` is the following: + // - type=PPME_SYSCALL_READ_X + // - ts=1380933088076148247 + // - tid=44106 + // - args=res=270 data=HTTP/1.1 302 Found\0Date: Sat, 05 Oct 2013 00:31:28 GMT\0Server: + // Apache/2.4.4 (U + // + // And its corresponding enter event `430681` is the following: + // - type=PPME_SYSCALL_READ_E + // - ts=1380933088076145348 + // - tid=44106, + // - args=fd=33(<4t>127.0.0.1:38308->127.0.0.1:80) size=8192 + // + // Let's see the new PPME_SYSCALL_READ_X event! + uint64_t ts = 1380933088076148247; + int64_t tid = 44106; + int64_t res = 270; + // this is NULL termiinated so we have 81 bytes but in the scap-file we want only 80 bytes + // without the NULL terminator + char read_buf[] = { + "HTTP/1.1 302 Found\r\nDate: Sat, 05 Oct 2013 00:31:28 GMT\r\nServer: Apache/2.4.4 " + "(U"}; + int64_t fd = 33; + uint32_t size = 8192; + assert_event_presence( + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_READ_X, + 4, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf) - 1}, + fd, + size)); +} + +//////////////////////////// +// PREAD +//////////////////////////// + +TEST_F(scap_file_test, no_pread_e) { + open_filename("kexec_arm64.scap"); + assert_no_event_type(PPME_SYSCALL_PREAD_E); +} + +TEST_F(scap_file_test, pread_x_same_number_of_exit_events) { + open_filename("kexec_arm64.scap"); + assert_num_event_type(PPME_SYSCALL_PREAD_X, 3216); +} + +TEST_F(scap_file_test, pread_x_check_final_converted_event) { + open_filename("kexec_arm64.scap"); + + // Inside the scap-file the event `862450` is the following: + // - type=PPME_SYSCALL_PREAD_X, + // - ts=1687966733234634809 + // - tid=552 + // - args=res=400 + // data=...._...tty1............................tty1LOGIN............................... + // + // And its corresponding enter event `862449` is the following: + // - type=PPME_SYSCALL_PREAD_E + // - ts=1687966733234634235 + // - tid=552 + // - args=fd=19(/var/run/utmp) size=400 pos=800 + // + // Let's see the new PPME_SYSCALL_PREAD_X event! + uint64_t ts = 1687966733234634809; + int64_t tid = 552; + int64_t res = 400; + uint8_t read_buf[] = {6, 0, 0, 0, '_', 2, 0, 0, 't', 't', 'y', '1', 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 't', 't', 'y', '1', 'L', 'O', 'G', 'I', + 'N', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int64_t fd = 19; + uint32_t size = 400; + int64_t pos = 800; + assert_event_presence( + create_safe_scap_event(ts, + tid, + PPME_SYSCALL_PREAD_X, + 5, + res, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}, + fd, + size, + pos)); +} From 28d032b756f114d0a534533a98048a8f7092a66c Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Mon, 2 Dec 2024 11:31:17 +0100 Subject: [PATCH 08/11] fix(ci): fix CI errors with GNU 8.3.0 Signed-off-by: Andrea Terzolo --- .../engine/savefile/converter/converter.cpp | 56 ++++++++++++++++++- .../engine/savefile/converter/table.cpp | 18 +++--- .../libscap/engine/savefile/scap_savefile.c | 2 +- userspace/libscap/scap.h | 1 - userspace/libscap/scap_event.c | 54 ------------------ userspace/libsinsp/event.h | 6 +- 6 files changed, 69 insertions(+), 68 deletions(-) diff --git a/userspace/libscap/engine/savefile/converter/converter.cpp b/userspace/libscap/engine/savefile/converter/converter.cpp index ed91382d1e..10afe32d14 100644 --- a/userspace/libscap/engine/savefile/converter/converter.cpp +++ b/userspace/libscap/engine/savefile/converter/converter.cpp @@ -116,12 +116,66 @@ static char *get_param_ptr(scap_evt *evt, uint8_t num_param) { return ptr + ptr_off; } +static inline uint8_t get_size_bytes_from_type(enum ppm_param_type t) { + switch(t) { + case PT_INT8: + case PT_UINT8: + case PT_FLAGS8: + case PT_ENUMFLAGS8: + return 1; + + case PT_INT16: + case PT_UINT16: + case PT_FLAGS16: + case PT_ENUMFLAGS16: + case PT_SYSCALLID: + return 2; + + case PT_INT32: + case PT_UINT32: + case PT_FLAGS32: + case PT_ENUMFLAGS32: + case PT_UID: + case PT_GID: + case PT_MODE: + return 4; + + case PT_INT64: + case PT_UINT64: + case PT_RELTIME: + case PT_ABSTIME: + case PT_ERRNO: + case PT_FD: + case PT_PID: + return 8; + + case PT_BYTEBUF: + case PT_CHARBUF: + case PT_SOCKADDR: + case PT_SOCKTUPLE: + case PT_FDLIST: + case PT_FSPATH: + case PT_CHARBUFARRAY: + case PT_CHARBUF_PAIR_ARRAY: + case PT_FSRELPATH: + case PT_DYN: + return 0; + + default: + // We forgot to handle something + assert(false); + break; + } + assert(false); + return 0; +} + // This writes len + the param static void push_default_parameter(scap_evt *evt, uint16_t *params_offset, uint8_t param_num) { // Please ensure that `new_evt->type` is already the final type you want to obtain. // Otherwise we will access the wrong entry in the event table. const struct ppm_event_info *event_info = &(g_event_info[evt->type]); - uint16_t len = scap_get_size_bytes_from_type(event_info->params[param_num].type); + uint16_t len = get_size_bytes_from_type(event_info->params[param_num].type); uint16_t lens_offset = sizeof(scap_evt) + param_num * sizeof(uint16_t); PRINT_MESSAGE( diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp index 39f01ecbdf..2665627f4f 100644 --- a/userspace/libscap/engine/savefile/converter/table.cpp +++ b/userspace/libscap/engine/savefile/converter/table.cpp @@ -24,15 +24,17 @@ const std::unordered_map g_conversion_table = { //////////////////////////// // READ //////////////////////////// - {{PPME_SYSCALL_READ_E, 2}, {.action = C_ACTION_STORE}}, - {{PPME_SYSCALL_READ_X, 2}, - {.action = C_ACTION_ADD_PARAMS, - .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}}}}, + {conversion_key{PPME_SYSCALL_READ_E, 2}, conversion_info{.action = C_ACTION_STORE}}, + {conversion_key{PPME_SYSCALL_READ_X, 2}, + conversion_info{.action = C_ACTION_ADD_PARAMS, + .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}}}}, //////////////////////////// // PREAD //////////////////////////// - {{PPME_SYSCALL_PREAD_E, 3}, {.action = C_ACTION_STORE}}, - {{PPME_SYSCALL_PREAD_X, 2}, - {.action = C_ACTION_ADD_PARAMS, - .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}, {C_INSTR_FROM_ENTER, 2}}}}, + {conversion_key{PPME_SYSCALL_PREAD_E, 3}, conversion_info{.action = C_ACTION_STORE}}, + {conversion_key{PPME_SYSCALL_PREAD_X, 2}, + conversion_info{.action = C_ACTION_ADD_PARAMS, + .instr = {{C_INSTR_FROM_ENTER, 0}, + {C_INSTR_FROM_ENTER, 1}, + {C_INSTR_FROM_ENTER, 2}}}}, }; diff --git a/userspace/libscap/engine/savefile/scap_savefile.c b/userspace/libscap/engine/savefile/scap_savefile.c index 19dedf2cae..214611f06c 100644 --- a/userspace/libscap/engine/savefile/scap_savefile.c +++ b/userspace/libscap/engine/savefile/scap_savefile.c @@ -2027,7 +2027,7 @@ static int32_t next(struct scap_engine_handle engine, uint16_t *pdevid, uint32_t *pflags) { struct savefile_engine *handle = engine.m_handle; -read_event: +read_event:; int32_t res = next_event_from_file(handle, pevent, pdevid, pflags); // If we fail we don't convert the event. if(res != SCAP_SUCCESS) { diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 8d332060f0..7ffae1a56b 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -855,7 +855,6 @@ int32_t scap_event_encode_params_v(struct scap_sized_buffer event_buf, ppm_event_code event_type, uint32_t n, va_list args); -uint8_t scap_get_size_bytes_from_type(enum ppm_param_type t); bool scap_compare_events(scap_evt* curr, scap_evt* expected, char* error); scap_evt* scap_create_event_v(char* error, uint64_t ts, diff --git a/userspace/libscap/scap_event.c b/userspace/libscap/scap_event.c index 86ab922f65..d375fb7666 100644 --- a/userspace/libscap/scap_event.c +++ b/userspace/libscap/scap_event.c @@ -356,60 +356,6 @@ int32_t scap_event_encode_params_v(const struct scap_sized_buffer event_buf, return SCAP_SUCCESS; } -uint8_t scap_get_size_bytes_from_type(enum ppm_param_type t) { - switch(t) { - case PT_INT8: - case PT_UINT8: - case PT_FLAGS8: - case PT_ENUMFLAGS8: - return 1; - - case PT_INT16: - case PT_UINT16: - case PT_FLAGS16: - case PT_ENUMFLAGS16: - case PT_SYSCALLID: - return 2; - - case PT_INT32: - case PT_UINT32: - case PT_FLAGS32: - case PT_ENUMFLAGS32: - case PT_UID: - case PT_GID: - case PT_MODE: - return 4; - - case PT_INT64: - case PT_UINT64: - case PT_RELTIME: - case PT_ABSTIME: - case PT_ERRNO: - case PT_FD: - case PT_PID: - return 8; - - case PT_BYTEBUF: - case PT_CHARBUF: - case PT_SOCKADDR: - case PT_SOCKTUPLE: - case PT_FDLIST: - case PT_FSPATH: - case PT_CHARBUFARRAY: - case PT_CHARBUF_PAIR_ARRAY: - case PT_FSRELPATH: - case PT_DYN: - return 0; - - default: - // We forgot to handle something - ASSERT(false); - break; - } - ASSERT(false); - return 0; -} - // This should be only used for testing purposes in production we should use directly `memcmp` for // the whole event bool scap_compare_events(scap_evt *curr, scap_evt *expected, char *error) { diff --git a/userspace/libsinsp/event.h b/userspace/libsinsp/event.h index 3555d9cfe0..d16f3d1feb 100644 --- a/userspace/libsinsp/event.h +++ b/userspace/libsinsp/event.h @@ -750,10 +750,10 @@ class SINSP_PUBLIC sinsp_evt { } // the only return values should be on 32 or 64 bits - switch(scap_get_size_bytes_from_type(p->get_info()->type)) { - case 4: + switch(p->m_len) { + case sizeof(int32_t): return (int64_t)p->as(); - case 8: + case sizeof(int64_t): return p->as(); default: ASSERT(false); From 3c1bba349dfe54631c11e2c2c8d06d8d2496c0e4 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Mon, 2 Dec 2024 12:41:00 +0100 Subject: [PATCH 09/11] updare: don't use designated initializers Signed-off-by: Andrea Terzolo --- .../engine/savefile/converter/converter.cpp | 24 ++++++++--------- .../engine/savefile/converter/table.cpp | 27 +++++++++---------- .../libscap/engine/savefile/converter/types.h | 21 ++++++++++++--- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/userspace/libscap/engine/savefile/converter/converter.cpp b/userspace/libscap/engine/savefile/converter/converter.cpp index 10afe32d14..70e6283ff6 100644 --- a/userspace/libscap/engine/savefile/converter/converter.cpp +++ b/userspace/libscap/engine/savefile/converter/converter.cpp @@ -305,7 +305,7 @@ static conversion_result convert_event(scap_evt *new_evt, uint16_t params_offset = 0; int param_to_populate = 0; - switch(ci.action) { + switch(ci.m_action) { case C_ACTION_SKIP: return CONVERSION_SKIP; @@ -316,7 +316,7 @@ static conversion_result convert_event(scap_evt *new_evt, case C_ACTION_ADD_PARAMS: memcpy(new_evt, evt_to_convert, sizeof(scap_evt)); // The new number of params is the previous one plus the number of conversion instructions. - new_evt->nparams = evt_to_convert->nparams + ci.instr.size(); + new_evt->nparams = evt_to_convert->nparams + ci.m_instrs.size(); params_offset = copy_old_params(new_evt, evt_to_convert); param_to_populate = evt_to_convert->nparams; break; @@ -324,14 +324,14 @@ static conversion_result convert_event(scap_evt *new_evt, case C_ACTION_CHANGE_TYPE: memcpy(new_evt, evt_to_convert, sizeof(scap_evt)); // The new number of params is the number of conversion instructions. - new_evt->nparams = ci.instr.size(); - new_evt->type = ci.desired_type; + new_evt->nparams = ci.m_instrs.size(); + new_evt->type = ci.m_desired_type; params_offset = sizeof(scap_evt) + new_evt->nparams * sizeof(uint16_t); param_to_populate = 0; break; default: - snprintf(error, SCAP_LASTERR_SIZE, "Unhandled conversion action '%d'.", ci.action); + snprintf(error, SCAP_LASTERR_SIZE, "Unhandled conversion action '%d'.", ci.m_action); return CONVERSION_ERROR; } @@ -347,10 +347,10 @@ static conversion_result convert_event(scap_evt *new_evt, bool used_enter_event = false; // We iterate over the instructions - for(int i = 0; i < ci.instr.size(); i++, param_to_populate++) { + for(int i = 0; i < ci.m_instrs.size(); i++, param_to_populate++) { PRINT_MESSAGE("Instruction n° %d. Param to populate: %d\n", i, param_to_populate); - switch(ci.instr[i].flags) { + switch(ci.m_instrs[i].flags) { case C_INSTR_FROM_DEFAULT: tmp_evt = NULL; break; @@ -383,14 +383,14 @@ static conversion_result convert_event(scap_evt *new_evt, case C_INSTR_FROM_OLD: tmp_evt = evt_to_convert; - if(tmp_evt->nparams <= ci.instr[i].param_num) { + if(tmp_evt->nparams <= ci.m_instrs[i].param_num) { // todo!: this sounds like an error but let's see in the future. At the moment we // fail snprintf(error, SCAP_LASTERR_SIZE, "We want to take parameter '%d' from event '%d' but this event has only " "'%d' parameters!", - ci.instr[i].param_num, + ci.m_instrs[i].param_num, tmp_evt->type, tmp_evt->nparams); return CONVERSION_ERROR; @@ -401,8 +401,8 @@ static conversion_result convert_event(scap_evt *new_evt, snprintf(error, SCAP_LASTERR_SIZE, "Unknown instruction (flags: %d, param_num: %d).", - ci.instr[i].flags, - ci.instr[i].param_num); + ci.m_instrs[i].flags, + ci.m_instrs[i].param_num); return CONVERSION_ERROR; } @@ -413,7 +413,7 @@ static conversion_result convert_event(scap_evt *new_evt, tmp_evt, ¶ms_offset, param_to_populate, - ci.instr[i].param_num); + ci.m_instrs[i].param_num); } } diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp index 2665627f4f..e00f683e7d 100644 --- a/userspace/libscap/engine/savefile/converter/table.cpp +++ b/userspace/libscap/engine/savefile/converter/table.cpp @@ -20,21 +20,20 @@ limitations under the License. #include #include +// We cannot use designated initializers, we need c++20 const std::unordered_map g_conversion_table = { - //////////////////////////// - // READ - //////////////////////////// - {conversion_key{PPME_SYSCALL_READ_E, 2}, conversion_info{.action = C_ACTION_STORE}}, + /*====================== READ ======================*/ + {conversion_key{PPME_SYSCALL_READ_E, 2}, conversion_info().action(C_ACTION_STORE)}, {conversion_key{PPME_SYSCALL_READ_X, 2}, - conversion_info{.action = C_ACTION_ADD_PARAMS, - .instr = {{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}}}}, - //////////////////////////// - // PREAD - //////////////////////////// - {conversion_key{PPME_SYSCALL_PREAD_E, 3}, conversion_info{.action = C_ACTION_STORE}}, + conversion_info() + .action(C_ACTION_ADD_PARAMS) + .instrs({{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}})}, + /*====================== PREAD ======================*/ + {conversion_key{PPME_SYSCALL_PREAD_E, 3}, conversion_info().action(C_ACTION_STORE)}, {conversion_key{PPME_SYSCALL_PREAD_X, 2}, - conversion_info{.action = C_ACTION_ADD_PARAMS, - .instr = {{C_INSTR_FROM_ENTER, 0}, - {C_INSTR_FROM_ENTER, 1}, - {C_INSTR_FROM_ENTER, 2}}}}, + conversion_info() + .action(C_ACTION_ADD_PARAMS) + .instrs({{C_INSTR_FROM_ENTER, 0}, + {C_INSTR_FROM_ENTER, 1}, + {C_INSTR_FROM_ENTER, 2}})}, }; diff --git a/userspace/libscap/engine/savefile/converter/types.h b/userspace/libscap/engine/savefile/converter/types.h index 1548701649..f1151a1d3a 100644 --- a/userspace/libscap/engine/savefile/converter/types.h +++ b/userspace/libscap/engine/savefile/converter/types.h @@ -62,7 +62,22 @@ struct hash { } // namespace std struct conversion_info { - uint8_t action = 0; - uint16_t desired_type = 0; // Needed only when action is `C_ACTION_CHANGE_TYPE` - std::vector instr = {}; + uint8_t m_action = 0; + uint16_t m_desired_type = 0; // Needed only when action is `C_ACTION_CHANGE_TYPE` + std::vector m_instrs = {}; + + conversion_info& action(conversion_action a) { + m_action = (uint8_t)a; + return *this; + }; + + conversion_info& desired_type(uint16_t t) { + m_desired_type = t; + return *this; + }; + + conversion_info& instrs(std::vector i) { + m_instrs = i; + return *this; + }; }; From 74eba846cc7227f09dc9f3c81b8dceb5ed03ade4 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Mon, 2 Dec 2024 17:19:24 +0100 Subject: [PATCH 10/11] fix(ci): fix windows CI Signed-off-by: Andrea Terzolo --- userspace/libscap/engine/savefile/converter/converter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/userspace/libscap/engine/savefile/converter/converter.cpp b/userspace/libscap/engine/savefile/converter/converter.cpp index 70e6283ff6..e0fdacc5ca 100644 --- a/userspace/libscap/engine/savefile/converter/converter.cpp +++ b/userspace/libscap/engine/savefile/converter/converter.cpp @@ -26,6 +26,7 @@ limitations under the License. #include #include #include +#include typedef std::shared_ptr safe_scap_evt_t; @@ -36,8 +37,6 @@ static inline safe_scap_evt_t safe_scap_evt(scap_evt *evt) { // use a shared pointer to store the events static std::unordered_map evt_storage = {}; -extern const struct ppm_event_info g_event_info[]; - static const char *get_event_name(ppm_event_code event_type) { const struct ppm_event_info *event_info = &g_event_info[event_type]; return event_info->name; From 45e39f0f884ad72541e875c0c4b2ac4b9a6a0bdf Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 3 Dec 2024 11:10:30 +0100 Subject: [PATCH 11/11] cleanup: refuse `EF_LARGE_PAYLOAD` events Signed-off-by: Andrea Terzolo --- .../test_suites/engines/savefile/converter.cpp | 13 +++++++++++++ .../libscap/engine/savefile/converter/converter.cpp | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/libscap/test_suites/engines/savefile/converter.cpp b/test/libscap/test_suites/engines/savefile/converter.cpp index e38c4ee6d1..8a0d822988 100644 --- a/test/libscap/test_suites/engines/savefile/converter.cpp +++ b/test/libscap/test_suites/engines/savefile/converter.cpp @@ -13,6 +13,19 @@ limitations under the License. */ #include "convert_event_test.h" +TEST_F(convert_event_test, conversion_not_needed) { + uint64_t ts = 12; + int64_t tid = 25; + const char data[] = "hello world"; + + auto evt = create_safe_scap_event(ts, + tid, + PPME_CONTAINER_JSON_2_E, + 1, + scap_const_sized_buffer{&data, strlen(data) + 1}); + assert_single_conversion_failure(evt); +} + //////////////////////////// // READ //////////////////////////// diff --git a/userspace/libscap/engine/savefile/converter/converter.cpp b/userspace/libscap/engine/savefile/converter/converter.cpp index e0fdacc5ca..a0c8195df4 100644 --- a/userspace/libscap/engine/savefile/converter/converter.cpp +++ b/userspace/libscap/engine/savefile/converter/converter.cpp @@ -253,6 +253,10 @@ static uint16_t copy_old_params(scap_evt *new_evt, scap_evt *evt_to_convert) { return new_evt_offset + size_to_copy; } +static bool is_large_payload(scap_evt *evt_to_convert) { + return g_event_info[evt_to_convert->type].flags & EF_LARGE_PAYLOAD; +} + extern "C" bool is_conversion_needed(scap_evt *evt_to_convert) { assert(evt_to_convert->type < PPM_EVENT_MAX); const struct ppm_event_info *event_info = &(g_event_info[evt_to_convert->type]); @@ -297,6 +301,15 @@ static conversion_result convert_event(scap_evt *new_evt, scap_evt *evt_to_convert, const conversion_info &ci, char *error) { + // todo!: add the support for large payload events if we need to handle at least one of them. + if(is_large_payload(evt_to_convert)) { + snprintf(error, + SCAP_LASTERR_SIZE, + "The event '%d' has a large payload. We don't support it yet.", + evt_to_convert->type); + return CONVERSION_ERROR; + } + ///////////////////////////// // Dispatch the action /////////////////////////////