From be64e3d55741533cc2e340a8a7b429cedf8a49cb Mon Sep 17 00:00:00 2001 From: Leonardo Di Giovanna Date: Wed, 18 Dec 2024 17:29:19 +0100 Subject: [PATCH] new: extend LISTEN_X Signed-off-by: Leonardo Di Giovanna --- driver/SCHEMA_VERSION | 2 +- driver/bpf/fillers.h | 16 ++++++ driver/event_table.c | 11 ++-- driver/fillers_table.c | 2 +- .../definitions/events_dimensions.h | 2 +- .../syscall_dispatched_events/listen.bpf.c | 16 +++++- driver/ppm_fillers.c | 29 ++++++++++- driver/ppm_fillers.h | 1 + .../syscall_exit_suite/listen_x.cpp | 10 +++- .../engines/savefile/converter.cpp | 50 +++++++++++++++++++ .../engine/savefile/converter/converter.cpp | 2 +- .../engine/savefile/converter/table.cpp | 7 ++- userspace/libscap/scap.h | 2 +- userspace/libscap/scap_event.c | 2 + userspace/libsinsp/test/events_net.ut.cpp | 26 ++++++---- .../libsinsp/test/parsers/parse_listen.cpp | 41 +++++++++++++++ .../test/scap_files/converter_tests.cpp | 41 +++++++++++++++ 17 files changed, 236 insertions(+), 24 deletions(-) create mode 100644 userspace/libsinsp/test/parsers/parse_listen.cpp diff --git a/driver/SCHEMA_VERSION b/driver/SCHEMA_VERSION index 15a2799817..18091983f5 100644 --- a/driver/SCHEMA_VERSION +++ b/driver/SCHEMA_VERSION @@ -1 +1 @@ -3.3.0 +3.4.0 diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 853d6d3501..8b24b8b49c 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -4133,6 +4133,22 @@ FILLER(sys_listen_e, true) { return bpf_push_s32_to_ring(data, (int32_t)backlog); } +FILLER(sys_listen_x, true) { + /* 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); + + /* Parameter 2: fd (type: PT_FD) */ + int32_t fd = (int32_t)bpf_syscall_get_argument(data, 0); + res = bpf_push_s64_to_ring(data, (int64_t)fd); + CHECK_RES(res); + + /* Parameter 3: backlog (type: PT_INT32) */ + int32_t backlog = (int32_t)bpf_syscall_get_argument(data, 1); + return bpf_push_s32_to_ring(data, (int32_t)backlog); +} + FILLER(sys_recvmsg_e, true) { /* Parameter 1: fd (type: PT_FD) */ int32_t fd = (int32_t)bpf_syscall_get_argument(data, 0); diff --git a/driver/event_table.c b/driver/event_table.c index 26a8eb1844..a707ec0237 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -191,11 +191,16 @@ const struct ppm_event_info g_event_info[] = { {"fd", PT_FD, PF_DEC}}}, [PPME_SOCKET_LISTEN_E] = {"listen", EC_NET | EC_SYSCALL, - EF_USES_FD, + EF_USES_FD | EF_TMP_CONVERTER_MANAGED, 2, {{"fd", PT_FD, PF_DEC}, {"backlog", PT_INT32, PF_DEC}}}, - [PPME_SOCKET_LISTEN_X] = - {"listen", EC_NET | EC_SYSCALL, EF_USES_FD, 1, {{"res", PT_ERRNO, PF_DEC}}}, + [PPME_SOCKET_LISTEN_X] = {"listen", + EC_NET | EC_SYSCALL, + EF_USES_FD | EF_TMP_CONVERTER_MANAGED, + 3, + {{"res", PT_ERRNO, PF_DEC}, + {"fd", PT_FD, PF_DEC}, + {"backlog", PT_INT32, PF_DEC}}}, [PPME_SOCKET_ACCEPT_E] = {"accept", EC_NET | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION, diff --git a/driver/fillers_table.c b/driver/fillers_table.c index 5fe6d3fb9d..1e1b953a16 100644 --- a/driver/fillers_table.c +++ b/driver/fillers_table.c @@ -41,7 +41,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = { [PPME_SOCKET_CONNECT_E] = {FILLER_REF(sys_connect_e)}, [PPME_SOCKET_CONNECT_X] = {FILLER_REF(sys_connect_x)}, [PPME_SOCKET_LISTEN_E] = {FILLER_REF(sys_listen_e)}, - [PPME_SOCKET_LISTEN_X] = {FILLER_REF(sys_single_x)}, + [PPME_SOCKET_LISTEN_X] = {FILLER_REF(sys_listen_x)}, [PPME_SOCKET_SEND_E] = {FILLER_REF(sys_send_e)}, [PPME_SOCKET_SEND_X] = {FILLER_REF(sys_send_x)}, [PPME_SOCKET_SENDTO_E] = {FILLER_REF(sys_sendto_e)}, diff --git a/driver/modern_bpf/definitions/events_dimensions.h b/driver/modern_bpf/definitions/events_dimensions.h index eb8c3b03df..95faea9979 100644 --- a/driver/modern_bpf/definitions/events_dimensions.h +++ b/driver/modern_bpf/definitions/events_dimensions.h @@ -96,7 +96,7 @@ #define ACCEPT4_E_SIZE HEADER_LEN + sizeof(uint32_t) + PARAM_LEN #define BIND_E_SIZE HEADER_LEN + sizeof(int64_t) + PARAM_LEN #define LISTEN_E_SIZE HEADER_LEN + sizeof(int64_t) + sizeof(int32_t) + PARAM_LEN * 2 -#define LISTEN_X_SIZE HEADER_LEN + sizeof(int64_t) + PARAM_LEN +#define LISTEN_X_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(int32_t) + PARAM_LEN * 3 #define CLONE_E_SIZE HEADER_LEN #define CLONE3_E_SIZE HEADER_LEN #define FORK_E_SIZE HEADER_LEN diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/listen.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/listen.bpf.c index b36ea8ff3d..892da8aa4e 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/listen.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/listen.bpf.c @@ -12,7 +12,7 @@ SEC("tp_btf/sys_enter") int BPF_PROG(listen_e, struct pt_regs *regs, long id) { - /* Collect parameters at the beginning to manage socketcalls */ + /* Collect parameters at the beginning to manage socketcalls */ unsigned long args[2] = {0}; extract__network_args(args, 2, regs); @@ -46,6 +46,10 @@ int BPF_PROG(listen_e, struct pt_regs *regs, long id) { SEC("tp_btf/sys_exit") int BPF_PROG(listen_x, struct pt_regs *regs, long ret) { + /* Collect parameters at the beginning to manage socketcalls */ + unsigned long args[2] = {0}; + extract__network_args(args, 2, regs); + struct ringbuf_struct ringbuf; if(!ringbuf__reserve_space(&ringbuf, LISTEN_X_SIZE, PPME_SOCKET_LISTEN_X)) { return 0; @@ -55,9 +59,17 @@ int BPF_PROG(listen_x, struct pt_regs *regs, long ret) { /*=============================== COLLECT PARAMETERS ===========================*/ - /* Parameter 1: res (type: PT_ERRNO)*/ + /* Parameter 1: res (type: PT_ERRNO) */ ringbuf__store_s64(&ringbuf, ret); + /* Parameter 2: fd (type: PT_FD) */ + int32_t fd = (int32_t)args[0]; + ringbuf__store_s64(&ringbuf, (int64_t)fd); + + /* Parameter 3: backlog (type: PT_INT32) */ + int32_t backlog = (int32_t)args[1]; + ringbuf__store_s32(&ringbuf, backlog); + /*=============================== COLLECT PARAMETERS ===========================*/ ringbuf__submit_event(&ringbuf); diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index a3a16e2b6e..71dd94082d 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -2723,7 +2723,7 @@ int f_sys_listen_e(struct event_filler_arguments *args) { int32_t fd = 0; int32_t backlog = 0; - /* Parameter 1: fd (type: PT_FD)*/ + /* Parameter 1: fd (type: PT_FD) */ syscall_get_arguments_deprecated(args, 0, 1, &val); fd = (int32_t)val; res = val_to_ring(args, (int64_t)fd, 0, false, 0); @@ -2738,6 +2738,33 @@ int f_sys_listen_e(struct event_filler_arguments *args) { return add_sentinel(args); } +int f_sys_listen_x(struct event_filler_arguments *args) { + int res; + unsigned long val = 0; + int64_t retval; + int32_t fd = 0; + int32_t backlog = 0; + + /* 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: fd (type: PT_FD) */ + syscall_get_arguments_deprecated(args, 0, 1, &val); + fd = (int32_t)val; + res = val_to_ring(args, (int64_t)fd, 0, false, 0); + CHECK_RES(res); + + /* Parameter 3: backlog (type: PT_INT32) */ + syscall_get_arguments_deprecated(args, 1, 1, &val); + backlog = (int32_t)val; + res = val_to_ring(args, (int32_t)backlog, 0, false, 0); + CHECK_RES(res); + + return add_sentinel(args); +} + int f_sys_recvmsg_e(struct event_filler_arguments *args) { unsigned long val = 0; int res = 0; diff --git a/driver/ppm_fillers.h b/driver/ppm_fillers.h index fba89c8c48..8d19c5945a 100644 --- a/driver/ppm_fillers.h +++ b/driver/ppm_fillers.h @@ -167,6 +167,7 @@ or GPL2.txt for full copies of the license. FN(sys_recvfrom_e) \ FN(sys_recvmsg_e) \ FN(sys_listen_e) \ + FN(sys_listen_x) \ FN(sys_signalfd_e) \ FN(sys_splice_e) \ FN(sys_umount_x) \ diff --git a/test/drivers/test_suites/syscall_exit_suite/listen_x.cpp b/test/drivers/test_suites/syscall_exit_suite/listen_x.cpp index 661c50fdd7..637d655d48 100644 --- a/test/drivers/test_suites/syscall_exit_suite/listen_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/listen_x.cpp @@ -29,11 +29,17 @@ TEST(SyscallExit, listenX) { /*=============================== ASSERT PARAMETERS ===========================*/ - /* Parameter 1: fd (type: PT_FD) */ + /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)errno_value); + /* Parameter 2: fd (type: PT_FD) */ + evt_test->assert_numeric_param(2, (int64_t)socket_fd); + + /* Parameter 3: backlog (type: PT_INT32) */ + evt_test->assert_numeric_param(3, (int32_t)backlog); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(1); + evt_test->assert_num_params_pushed(3); } #endif diff --git a/test/libscap/test_suites/engines/savefile/converter.cpp b/test/libscap/test_suites/engines/savefile/converter.cpp index 8d4b4d386a..15abeb9647 100644 --- a/test/libscap/test_suites/engines/savefile/converter.cpp +++ b/test/libscap/test_suites/engines/savefile/converter.cpp @@ -311,3 +311,53 @@ TEST_F(convert_event_test, PPME_SOCKET_SOCKET_X_to_4_params_with_enter) { create_safe_scap_event(ts, tid, PPME_SOCKET_SOCKET_X, 1, fd), create_safe_scap_event(ts, tid, PPME_SOCKET_SOCKET_X, 4, fd, domain, type, proto)); } + +//////////////////////////// +// LISTEN +//////////////////////////// + +TEST_F(convert_event_test, PPME_SOCKET_LISTEN_E_store) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t fd = 25; + int32_t backlog = 5; + auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_E, 2, fd, backlog); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); +} + +TEST_F(convert_event_test, PPME_SOCKET_LISTEN_X_to_3_params_no_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + + // Defaulted to 0 + int64_t fd = 0; + int32_t backlog = 0; + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_X, 1, res), + create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_X, 3, res, fd, backlog)); +} + +TEST_F(convert_event_test, PPME_SOCKET_LISTEN_X_to_3_params_with_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + int64_t fd = 25; + int32_t backlog = 5; + + // After the first conversion we should have the storage + auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_E, 2, fd, backlog); + 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_SOCKET_LISTEN_X, 1, res), + create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_X, 3, res, fd, backlog)); +} diff --git a/userspace/libscap/engine/savefile/converter/converter.cpp b/userspace/libscap/engine/savefile/converter/converter.cpp index 4ca85a27a5..932b479f4a 100644 --- a/userspace/libscap/engine/savefile/converter/converter.cpp +++ b/userspace/libscap/engine/savefile/converter/converter.cpp @@ -446,7 +446,7 @@ extern "C" conversion_result scap_convert_event(scap_evt *new_evt, if(!is_conversion_needed(evt_to_convert)) { snprintf(error, SCAP_LASTERR_SIZE, - "Conversion not need for event type '%d' nparams '%d'. Please double check", + "Conversion not needed for event type '%d' nparams '%d'. Please double check", evt_to_convert->type, evt_to_convert->nparams); return CONVERSION_ERROR; diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp index d2eae93447..3747044550 100644 --- a/userspace/libscap/engine/savefile/converter/table.cpp +++ b/userspace/libscap/engine/savefile/converter/table.cpp @@ -48,4 +48,9 @@ const std::unordered_map g_conversion_table = { .instrs({{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}, {C_INSTR_FROM_ENTER, 2}})}, -}; + /*====================== LISTEN ======================*/ + {conversion_key{PPME_SOCKET_LISTEN_E, 2}, conversion_info().action(C_ACTION_STORE)}, + {conversion_key{PPME_SOCKET_LISTEN_X, 1}, + conversion_info() + .action(C_ACTION_ADD_PARAMS) + .instrs({{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}})}}; diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 6685f9f32b..9426671abd 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(3, 0, 0) +#define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(3, 4, 0) // // This is the dimension we used before introducing the variable buffer size. diff --git a/userspace/libscap/scap_event.c b/userspace/libscap/scap_event.c index 6ba2cfef4c..8ee64418b2 100644 --- a/userspace/libscap/scap_event.c +++ b/userspace/libscap/scap_event.c @@ -534,6 +534,8 @@ int get_exit_event_fd_location(ppm_event_code etype) { case PPME_SOCKET_BIND_X: location = 2; break; + case PPME_SOCKET_LISTEN_X: + location = 1; default: break; } diff --git a/userspace/libsinsp/test/events_net.ut.cpp b/userspace/libsinsp/test/events_net.ut.cpp index 14224b3db2..bdcc75207b 100644 --- a/userspace/libsinsp/test/events_net.ut.cpp +++ b/userspace/libsinsp/test/events_net.ut.cpp @@ -370,13 +370,16 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv4) { ASSERT_FALSE(field_has_value(evt, "fd.rport")); ASSERT_FALSE(field_has_value(evt, "fd.lport")); + int64_t server_fd = sinsp_test_input::socket_params::default_fd; + int32_t backlog = 5; + add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_LISTEN_E, 2, server_fd, backlog); add_event_advance_ts(increasing_ts(), 1, - PPME_SOCKET_LISTEN_E, - 2, - sinsp_test_input::socket_params::default_fd, - (uint32_t)5); - add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_LISTEN_X, 1, (int64_t)0); + PPME_SOCKET_LISTEN_X, + 3, + return_value, + server_fd, + backlog); sockaddr_in client = test_utils::fill_sockaddr_in(DEFAULT_CLIENT_PORT, DEFAULT_IPV4_CLIENT_STRING); @@ -434,13 +437,16 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv6) { ASSERT_EQ(get_field_as_string(evt, "fd.name"), fdname); ASSERT_EQ(get_field_as_string(evt, "fd.is_server"), "true"); + int64_t server_fd = sinsp_test_input::socket_params::default_fd; + int32_t backlog = 5; + add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_LISTEN_E, 2, server_fd, backlog); add_event_advance_ts(increasing_ts(), 1, - PPME_SOCKET_LISTEN_E, - 2, - sinsp_test_input::socket_params::default_fd, - (uint32_t)5); - add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_LISTEN_X, 1, (int64_t)0); + PPME_SOCKET_LISTEN_X, + 3, + return_value, + server_fd, + backlog); sockaddr_in6 client = test_utils::fill_sockaddr_in6(DEFAULT_CLIENT_PORT, DEFAULT_IPV6_CLIENT_STRING); diff --git a/userspace/libsinsp/test/parsers/parse_listen.cpp b/userspace/libsinsp/test/parsers/parse_listen.cpp new file mode 100644 index 0000000000..bea137a074 --- /dev/null +++ b/userspace/libsinsp/test/parsers/parse_listen.cpp @@ -0,0 +1,41 @@ + +// 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 + +TEST_F(sinsp_with_test_input, LISTEN_parse_unix_socket) { + add_default_init_thread(); + open_inspector(); + + int64_t return_value = 55; + int64_t socket_fd = 77; + int32_t backlog = 5; + const auto evt = add_event_advance_ts(increasing_ts(), + INIT_TID, + PPME_SOCKET_LISTEN_X, + 3, + return_value, + socket_fd, + backlog); + + // we want to check that the returned value is as expected. + ASSERT_EQ(evt->get_param_by_name("res")->as(), return_value); + + // we want to check that `get_fd_info()->m_fd` returns the correct socket fd. + ASSERT_EQ(evt->get_param_by_name("fd")->as(), socket_fd); + + // we want to check that the socket backlog is as expected. + ASSERT_EQ(evt->get_param_by_name("backlog")->as(), backlog); +} diff --git a/userspace/libsinsp/test/scap_files/converter_tests.cpp b/userspace/libsinsp/test/scap_files/converter_tests.cpp index 1e5a5533b9..5dde6b176b 100644 --- a/userspace/libsinsp/test/scap_files/converter_tests.cpp +++ b/userspace/libsinsp/test/scap_files/converter_tests.cpp @@ -158,3 +158,44 @@ TEST_F(scap_file_test, socket_x_check_final_converted_event) { assert_event_presence( create_safe_scap_event(ts, tid, PPME_SOCKET_SOCKET_X, 4, fd, domain, type, proto)); } + +//////////////////////////// +// LISTEN +//////////////////////////// + +TEST_F(scap_file_test, listen_e_same_number_of_events) { + open_filename("kexec_arm64.scap"); + assert_num_event_type(PPME_SOCKET_LISTEN_E, 1); +} + +TEST_F(scap_file_test, listen_x_same_number_of_events) { + open_filename("kexec_arm64.scap"); + assert_num_event_type(PPME_SOCKET_LISTEN_X, 1); +} + +TEST_F(scap_file_test, listen_x_check_final_converted_event) { + open_filename("kexec_arm64.scap"); + + // Inside the scap-file the event `57008` is the following: + // - type=PPME_SOCKET_LISTEN_X, + // - ts=1687966709944348874 + // - tid=141291 + // - args=res=0 + // + // And its corresponding enter event `57007` is the following: + // - type=PPME_SOCKET_LISTEN_E + // - ts=1687966709944347577 + // - tid=141291 + // - args=fd=25(/tmp/pty1908604488/pty.sock) + // - backlog=4096 + // + // Let's see the new PPME_SOCKET_LISTEN_X event! + + uint64_t ts = 1687966709944348874; + int64_t tid = 141291; + int64_t res = 0; + int64_t fd = 25; + int32_t backlog = 4096; + assert_event_presence( + create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_X, 3, res, fd, backlog)); +}