From 71124d3a9cc5c3efc595b5e2a845b703a88dc9be Mon Sep 17 00:00:00 2001
From: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
Date: Tue, 17 Dec 2024 15:34:04 +0100
Subject: [PATCH] new: extend BIND_X

Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
---
 driver/SCHEMA_VERSION                         |  2 +-
 driver/bpf/fillers.h                          | 14 ++--
 driver/event_table.c                          | 10 ++-
 .../syscall_dispatched_events/bind.bpf.c      |  3 +
 driver/ppm_fillers.c                          | 15 ++--
 .../test_suites/syscall_exit_suite/bind_x.cpp | 20 ++++-
 .../engines/savefile/converter.cpp            | 79 +++++++++++++++++++
 userspace/libscap/engine/gvisor/fillers.cpp   |  8 +-
 userspace/libscap/engine/gvisor/fillers.h     |  3 +-
 userspace/libscap/engine/gvisor/parsers.cpp   |  3 +-
 .../engine/savefile/converter/table.cpp       |  3 +
 userspace/libscap/scap_event.c                |  1 +
 userspace/libsinsp/test/events_net.ut.cpp     | 15 ++--
 .../libsinsp/test/parsers/parse_connect.cpp   |  9 ++-
 14 files changed, 147 insertions(+), 38 deletions(-)

diff --git a/driver/SCHEMA_VERSION b/driver/SCHEMA_VERSION
index fd2a01863f..944880fa15 100644
--- a/driver/SCHEMA_VERSION
+++ b/driver/SCHEMA_VERSION
@@ -1 +1 @@
-3.1.0
+3.2.0
diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h
index 64bf7480ff..d3d12d4506 100644
--- a/driver/bpf/fillers.h
+++ b/driver/bpf/fillers.h
@@ -3941,18 +3941,15 @@ FILLER(sys_socket_bind_x, true) {
 	uint16_t size = 0;
 	int err = 0;
 	long retval;
+	int32_t fd;
 	int res;
 
-	/*
-	 * res
-	 */
+	/* Parameter 1: res (type: PT_ERRNO) */
 	retval = bpf_syscall_get_retval(data->ctx);
 	res = bpf_push_s64_to_ring(data, retval);
 	CHECK_RES(res);
 
-	/*
-	 * addr
-	 */
+	/* Parameter 2: addr (type: PT_SOCKADDR) */
 	usrsockaddr = (struct sockaddr __user *)bpf_syscall_get_argument(data, 1);
 	val = bpf_syscall_get_argument(data, 2);
 
@@ -3974,8 +3971,11 @@ FILLER(sys_socket_bind_x, true) {
 	 */
 	data->curarg_already_on_frame = true;
 	res = bpf_val_to_ring_len(data, 0, size);
+	CHECK_RES(res);
 
-	return res;
+	/* Parameter 3: fd (type: PT_FD) */
+	fd = bpf_syscall_get_argument(data, 0);
+	return bpf_push_s64_to_ring(data, (int64_t)fd);
 }
 
 static __always_inline int f_sys_recv_x_common(struct filler_data *data, long retval) {
diff --git a/driver/event_table.c b/driver/event_table.c
index d8160f5369..26305f7a29 100644
--- a/driver/event_table.c
+++ b/driver/event_table.c
@@ -164,14 +164,16 @@ const struct ppm_event_info g_event_info[] = {
                                   {{"fd", PT_FD, PF_DEC}}},
         [PPME_SOCKET_BIND_E] = {"bind",
                                 EC_NET | EC_SYSCALL,
-                                EF_USES_FD | EF_MODIFIES_STATE,
+                                EF_USES_FD | EF_MODIFIES_STATE | EF_TMP_CONVERTER_MANAGED,
                                 1,
                                 {{"fd", PT_FD, PF_DEC}}},
         [PPME_SOCKET_BIND_X] = {"bind",
                                 EC_NET | EC_SYSCALL,
-                                EF_USES_FD | EF_MODIFIES_STATE,
-                                2,
-                                {{"res", PT_ERRNO, PF_DEC}, {"addr", PT_SOCKADDR, PF_NA}}},
+                                EF_USES_FD | EF_MODIFIES_STATE | EF_TMP_CONVERTER_MANAGED,
+                                3,
+                                {{"res", PT_ERRNO, PF_DEC},
+                                 {"addr", PT_SOCKADDR, PF_NA},
+                                 {"fd", PT_FD, PF_DEC}}},
         [PPME_SOCKET_CONNECT_E] = {"connect",
                                    EC_NET | EC_SYSCALL,
                                    EF_USES_FD | EF_MODIFIES_STATE,
diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/bind.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/bind.bpf.c
index 0d106c1eff..43a8c3f996 100644
--- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/bind.bpf.c
+++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/bind.bpf.c
@@ -66,6 +66,9 @@ int BPF_PROG(bind_x, struct pt_regs *regs, long ret) {
 	uint16_t addrlen = (uint16_t)args[2];
 	auxmap__store_sockaddr_param(auxmap, sockaddr_ptr, addrlen);
 
+	/* Parameter 3: fd (type: PT_FD) */
+	auxmap__store_s64_param(auxmap, (int64_t)(int32_t)args[0]);
+
 	/*=============================== COLLECT PARAMETERS  ===========================*/
 
 	auxmap__finalize_event_header(auxmap);
diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c
index 1fe3366ac9..6e2a1746b8 100644
--- a/driver/ppm_fillers.c
+++ b/driver/ppm_fillers.c
@@ -1630,16 +1630,13 @@ int f_sys_socket_bind_x(struct event_filler_arguments *args) {
 	unsigned long val;
 	struct sockaddr_storage address;
 	char *targetbuf = args->str_storage;
+	int32_t fd = 0;
 
-	/*
-	 * res
-	 */
+	/* Parameter 1: res (type: PT_ERRNO) */
 	retval = (int64_t)syscall_get_return_value(current, args->regs);
 	res = val_to_ring(args, retval, 0, false, 0);
 
-	/*
-	 * addr
-	 */
+	/* Parameter 2: addr (type: PT_SOCKADDR) */
 	syscall_get_arguments_deprecated(args, 1, 1, &val);
 
 	usrsockaddr = (struct sockaddr __user *)val;
@@ -1668,6 +1665,12 @@ int f_sys_socket_bind_x(struct event_filler_arguments *args) {
 	res = val_to_ring(args, (uint64_t)targetbuf, size, false, 0);
 	CHECK_RES(res);
 
+	/* Parameter 3: 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);
+
 	return add_sentinel(args);
 }
 
diff --git a/test/drivers/test_suites/syscall_exit_suite/bind_x.cpp b/test/drivers/test_suites/syscall_exit_suite/bind_x.cpp
index 1c11e23ac0..d882c0a18a 100644
--- a/test/drivers/test_suites/syscall_exit_suite/bind_x.cpp
+++ b/test/drivers/test_suites/syscall_exit_suite/bind_x.cpp
@@ -50,9 +50,12 @@ TEST(SyscallExit, bindX_INET) {
 	/* Parameter 2: addr (type: PT_SOCKADDR) */
 	evt_test->assert_addr_info_inet_param(2, PPM_AF_INET, IPV4_SERVER, IPV4_PORT_SERVER_STRING);
 
+	/* Parameter 3: fd (type: PT_FD) */
+	evt_test->assert_numeric_param(3, (int64_t)server_socket_fd);
+
 	/*=============================== ASSERT PARAMETERS  ===========================*/
 
-	evt_test->assert_num_params_pushed(2);
+	evt_test->assert_num_params_pushed(3);
 }
 
 TEST(SyscallExit, bindX_INET6) {
@@ -101,9 +104,12 @@ TEST(SyscallExit, bindX_INET6) {
 	/* Parameter 2: addr (type: PT_SOCKADDR) */
 	evt_test->assert_addr_info_inet6_param(2, PPM_AF_INET6, IPV6_SERVER, IPV6_PORT_SERVER_STRING);
 
+	/* Parameter 3: fd (type: PT_FD) */
+	evt_test->assert_numeric_param(3, (int64_t)server_socket_fd);
+
 	/*=============================== ASSERT PARAMETERS  ===========================*/
 
-	evt_test->assert_num_params_pushed(2);
+	evt_test->assert_num_params_pushed(3);
 }
 
 #ifdef __NR_unlinkat
@@ -153,9 +159,12 @@ TEST(SyscallExit, bindX_UNIX) {
 	/* Parameter 2: addr (type: PT_SOCKADDR) */
 	evt_test->assert_addr_info_unix_param(2, PPM_AF_UNIX, UNIX_SERVER);
 
+	/* Parameter 3: fd (type: PT_FD) */
+	evt_test->assert_numeric_param(3, (int64_t)server_socket_fd);
+
 	/*=============================== ASSERT PARAMETERS  ===========================*/
 
-	evt_test->assert_num_params_pushed(2);
+	evt_test->assert_num_params_pushed(3);
 }
 #endif /* __NR_unlinkat */
 
@@ -195,9 +204,12 @@ TEST(SyscallExit, bindX_failure) {
 	/* Since the pointer to the `sockaddr` is `NULL` we expect an empty param here. */
 	evt_test->assert_empty_param(2);
 
+	/* Parameter 3: fd (type: PT_FD) */
+	evt_test->assert_numeric_param(3, (int64_t)mock_fd);
+
 	/*=============================== ASSERT PARAMETERS  ===========================*/
 
-	evt_test->assert_num_params_pushed(2);
+	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 8a0d822988..ee24440e8e 100644
--- a/test/libscap/test_suites/engines/savefile/converter.cpp
+++ b/test/libscap/test_suites/engines/savefile/converter.cpp
@@ -12,6 +12,8 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 #include "convert_event_test.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
 
 TEST_F(convert_event_test, conversion_not_needed) {
 	uint64_t ts = 12;
@@ -184,3 +186,80 @@ TEST_F(convert_event_test, PPME_SYSCALL_PREAD_X__to_4_params_with_enter) {
 	                               size,
 	                               pos));
 }
+
+////////////////////////////
+// BIND
+////////////////////////////
+
+TEST_F(convert_event_test, PPME_SOCKET_BIND_E_store) {
+	uint64_t ts = 12;
+	int64_t tid = 25;
+
+	int64_t fd = 25;
+	auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_BIND_E, 1, fd);
+	assert_single_conversion_skip(evt);
+	assert_event_storage_presence(evt);
+}
+
+TEST_F(convert_event_test, PPME_SOCKET_BIND_X_to_3_params_no_enter) {
+	uint64_t ts = 12;
+	int64_t tid = 25;
+
+	int64_t res = 89;
+	struct sockaddr_in sockaddr = {};
+	sockaddr.sin_family = AF_INET;
+	sockaddr.sin_port = htons(1234);
+	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	// Defaulted to 0
+	int64_t fd = 0;
+
+	assert_single_conversion_success(
+	        conversion_result::CONVERSION_COMPLETED,
+	        create_safe_scap_event(ts,
+	                               tid,
+	                               PPME_SOCKET_BIND_X,
+	                               2,
+	                               res,
+	                               scap_const_sized_buffer{&sockaddr, sizeof(sockaddr)}),
+	        create_safe_scap_event(ts,
+	                               tid,
+	                               PPME_SOCKET_BIND_X,
+	                               3,
+	                               res,
+	                               scap_const_sized_buffer{&sockaddr, sizeof(sockaddr)},
+	                               fd));
+}
+
+TEST_F(convert_event_test, PPME_SOCKET_BIND_X_to_3_params_with_enter) {
+	uint64_t ts = 12;
+	int64_t tid = 25;
+
+	int64_t res = 89;
+	struct sockaddr_in sockaddr = {};
+	sockaddr.sin_family = AF_INET;
+	sockaddr.sin_port = htons(1234);
+	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+	int64_t fd = 100;
+
+	// After the first conversion we should have the storage
+	auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_BIND_E, 1, fd);
+	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_BIND_X,
+	                               2,
+	                               res,
+	                               scap_const_sized_buffer{&sockaddr, sizeof(sockaddr)}),
+	        create_safe_scap_event(ts,
+	                               tid,
+	                               PPME_SOCKET_BIND_X,
+	                               3,
+	                               res,
+	                               scap_const_sized_buffer{&sockaddr, sizeof(sockaddr)},
+	                               fd));
+}
diff --git a/userspace/libscap/engine/gvisor/fillers.cpp b/userspace/libscap/engine/gvisor/fillers.cpp
index 48de12dfae..71c48dec71 100644
--- a/userspace/libscap/engine/gvisor/fillers.cpp
+++ b/userspace/libscap/engine/gvisor/fillers.cpp
@@ -1202,14 +1202,16 @@ int32_t fill_event_bind_x(scap_sized_buffer scap_buf,
                           size_t* event_size,
                           char* scap_err,
                           int64_t res,
-                          scap_const_sized_buffer addr) {
+                          scap_const_sized_buffer addr,
+                          int64_t fd) {
 	return scap_event_encode_params(scap_buf,
 	                                event_size,
 	                                scap_err,
 	                                PPME_SOCKET_BIND_X,
-	                                2,
+	                                3,
 	                                res,
-	                                addr);
+	                                addr,
+	                                fd);
 }
 
 // PPME_SYSCALL_ACCEPT_5_E
diff --git a/userspace/libscap/engine/gvisor/fillers.h b/userspace/libscap/engine/gvisor/fillers.h
index d7b7b8bd9a..fb93e8a93f 100644
--- a/userspace/libscap/engine/gvisor/fillers.h
+++ b/userspace/libscap/engine/gvisor/fillers.h
@@ -441,7 +441,8 @@ int32_t fill_event_bind_x(scap_sized_buffer scap_buf,
                           size_t* event_size,
                           char* scap_err,
                           int64_t res,
-                          scap_const_sized_buffer addr);
+                          scap_const_sized_buffer addr,
+                          int64_t fd);
 
 int32_t fill_event_accept_5_e(scap_sized_buffer scap_buf, size_t* event_size, char* scap_err);
 
diff --git a/userspace/libscap/engine/gvisor/parsers.cpp b/userspace/libscap/engine/gvisor/parsers.cpp
index 73cdaedeca..0d78fbf333 100644
--- a/userspace/libscap/engine/gvisor/parsers.cpp
+++ b/userspace/libscap/engine/gvisor/parsers.cpp
@@ -994,7 +994,8 @@ static parse_result parse_bind(uint32_t id,
 		                                                &ret.size,
 		                                                scap_err,
 		                                                gvisor_evt.exit().result(),
-		                                                scap_const_sized_buffer{targetbuf, size});
+		                                                scap_const_sized_buffer{targetbuf, size},
+		                                                gvisor_evt.fd());
 	} else {
 		ret.status = scap_gvisor::fillers::fill_event_bind_e(scap_buf,
 		                                                     &ret.size,
diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp
index e00f683e7d..aa326a8779 100644
--- a/userspace/libscap/engine/savefile/converter/table.cpp
+++ b/userspace/libscap/engine/savefile/converter/table.cpp
@@ -36,4 +36,7 @@ const std::unordered_map<conversion_key, conversion_info> g_conversion_table = {
                  .instrs({{C_INSTR_FROM_ENTER, 0},
                           {C_INSTR_FROM_ENTER, 1},
                           {C_INSTR_FROM_ENTER, 2}})},
+        {conversion_key{PPME_SOCKET_BIND_E, 1}, conversion_info().action(C_ACTION_STORE)},
+        {conversion_key{PPME_SOCKET_BIND_X, 2},
+         conversion_info().action(C_ACTION_ADD_PARAMS).instrs({{C_INSTR_FROM_ENTER, 0}})},
 };
diff --git a/userspace/libscap/scap_event.c b/userspace/libscap/scap_event.c
index c13a55efb5..6ba2cfef4c 100644
--- a/userspace/libscap/scap_event.c
+++ b/userspace/libscap/scap_event.c
@@ -531,6 +531,7 @@ int get_exit_event_fd_location(ppm_event_code etype) {
 	switch(etype) {
 	case PPME_SYSCALL_READ_X:
 	case PPME_SYSCALL_PREAD_X:
+	case PPME_SOCKET_BIND_X:
 		location = 2;
 		break;
 	default:
diff --git a/userspace/libsinsp/test/events_net.ut.cpp b/userspace/libsinsp/test/events_net.ut.cpp
index faedbcf878..efc846b0b9 100644
--- a/userspace/libsinsp/test/events_net.ut.cpp
+++ b/userspace/libsinsp/test/events_net.ut.cpp
@@ -368,10 +368,6 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv4) {
 	                     (uint32_t)0);
 	add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_SOCKET_X, 1, server_fd);
 
-	/* We have no parsers for bind enter event */
-	evt = add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_BIND_E, 1, server_fd);
-	ASSERT_EQ(get_field_as_string(evt, "fd.name"), "");
-
 	sockaddr_in server =
 	        test_utils::fill_sockaddr_in(DEFAULT_SERVER_PORT, DEFAULT_IPV4_SERVER_STRING);
 	std::vector<uint8_t> server_sockaddr =
@@ -381,9 +377,10 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv4) {
 	        increasing_ts(),
 	        1,
 	        PPME_SOCKET_BIND_X,
-	        2,
+	        3,
 	        return_value,
-	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()});
+	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()},
+	        server_fd);
 	fdinfo = evt->get_fd_info();
 	ASSERT_NE(fdinfo, nullptr);
 	ASSERT_FALSE(fdinfo->is_ipv4_socket());
@@ -464,7 +461,6 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv6) {
 	                     (uint32_t)SOCK_STREAM,
 	                     0);
 	add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_SOCKET_X, 1, server_fd);
-	add_event_advance_ts(increasing_ts(), 1, PPME_SOCKET_BIND_E, 1, server_fd);
 
 	sockaddr_in6 server =
 	        test_utils::fill_sockaddr_in6(DEFAULT_SERVER_PORT, DEFAULT_IPV6_SERVER_STRING);
@@ -475,9 +471,10 @@ TEST_F(sinsp_with_test_input, net_bind_listen_accept_ipv6) {
 	        increasing_ts(),
 	        1,
 	        PPME_SOCKET_BIND_X,
-	        2,
+	        3,
 	        return_value,
-	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()});
+	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()},
+	        server_fd);
 	std::string fdname =
 	        std::string(DEFAULT_IPV6_SERVER_STRING) + ":" + std::string(DEFAULT_SERVER_PORT_STRING);
 	ASSERT_EQ(get_field_as_string(evt, "fd.name"), fdname);
diff --git a/userspace/libsinsp/test/parsers/parse_connect.cpp b/userspace/libsinsp/test/parsers/parse_connect.cpp
index 43bdf49525..25ac9dc340 100644
--- a/userspace/libsinsp/test/parsers/parse_connect.cpp
+++ b/userspace/libsinsp/test/parsers/parse_connect.cpp
@@ -121,14 +121,19 @@ TEST_F(sinsp_with_test_input, BIND_parse_unix_socket) {
 	sockaddr_un u_sockaddr = test_utils::fill_sockaddr_un(unix_path.c_str());
 	std::vector<uint8_t> server_sockaddr =
 	        test_utils::pack_sockaddr(reinterpret_cast<sockaddr*>(&u_sockaddr));
+	uint64_t socket_fd = 77;
 	auto evt = add_event_advance_ts(
 	        increasing_ts(),
 	        INIT_TID,
 	        PPME_SOCKET_BIND_X,
-	        2,
+	        3,
 	        return_value,
-	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()});
+	        scap_const_sized_buffer{server_sockaddr.data(), server_sockaddr.size()},
+	        socket_fd);
 
 	// we want to check that `get_param_value_str` returns the correct unix socket path
 	ASSERT_EQ(evt->get_param_value_str("addr"), unix_path);
+
+	// we want to check that `get_fd_info()->m_fd` returns the correct socket fd.
+	ASSERT_EQ(evt->get_param_by_name("fd")->as<int64_t>(), socket_fd);
 }