From 2f4e3fa516b259a0bb99066030f76ecc09667bea Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Mon, 12 Feb 2024 16:03:43 +0100 Subject: [PATCH 1/4] fix(modern_bpf): null destination address in sendto syscall Signed-off-by: Gianmatteo Palmieri --- .../helpers/store/auxmap_store_params.h | 21 ++++++++++++++++++- .../syscall_dispatched_events/accept.bpf.c | 2 +- .../syscall_dispatched_events/accept4.bpf.c | 2 +- .../syscall_dispatched_events/connect.bpf.c | 2 +- .../syscall_dispatched_events/recvfrom.bpf.c | 2 +- .../syscall_dispatched_events/recvmsg.bpf.c | 2 +- .../syscall_dispatched_events/sendmsg.bpf.c | 2 +- .../syscall_dispatched_events/sendto.bpf.c | 7 ++++--- 8 files changed, 30 insertions(+), 10 deletions(-) diff --git a/driver/modern_bpf/helpers/store/auxmap_store_params.h b/driver/modern_bpf/helpers/store/auxmap_store_params.h index 3c77f62566..2544f72a0a 100644 --- a/driver/modern_bpf/helpers/store/auxmap_store_params.h +++ b/driver/modern_bpf/helpers/store/auxmap_store_params.h @@ -566,8 +566,9 @@ static __always_inline void auxmap__store_sockaddr_param(struct auxiliary_map *a * @param auxmap pointer to the auxmap in which we are storing the param. * @param socket_fd socket from which we extract information about the tuple. * @param direction specifies the connection direction. + * @param usrsockaddr pointer to user provided sock address. */ -static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map *auxmap, uint32_t socket_fd, int direction) +static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map *auxmap, uint32_t socket_fd, int direction, struct sockaddr *usrsockaddr) { uint16_t final_param_len = 0; @@ -594,6 +595,15 @@ static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map * BPF_CORE_READ_INTO(&ipv4_remote, sk, __sk_common.skc_daddr); BPF_CORE_READ_INTO(&port_remote, sk, __sk_common.skc_dport); + /* Fallback to userspace struct if address info from kernel is NULL*/ + if (port_remote == 0 && usrsockaddr != NULL) + { + struct sockaddr_in usrsockaddr_in = {}; + bpf_probe_read_user(&usrsockaddr_in, bpf_core_type_size(struct sockaddr_in), (void *)usrsockaddr); + ipv4_remote = usrsockaddr_in.sin_addr.s_addr; + port_remote = usrsockaddr_in.sin_port; + } + /* Pack the tuple info: * - socket family * - src_ipv4 @@ -636,6 +646,15 @@ static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map * BPF_CORE_READ_INTO(&ipv6_remote, sk, __sk_common.skc_v6_daddr); BPF_CORE_READ_INTO(&port_remote, sk, __sk_common.skc_dport); + /* Fallback to userspace struct if address info from kernel is NULL*/ + if (port_remote == 0 && usrsockaddr != NULL) + { + struct sockaddr_in6 usrsockaddr_in6 = {}; + bpf_probe_read_user(&usrsockaddr_in6, bpf_core_type_size(struct sockaddr_in6), (void *)usrsockaddr); + bpf_probe_read_kernel(&ipv6_remote, sizeof(uint32_t)*4, usrsockaddr_in6.sin6_addr.in6_u.u6_addr32); + port_remote = usrsockaddr_in6.sin6_port; + } + /* Pack the tuple info: * - socket family * - src_ipv6 diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept.bpf.c index a3dfde8336..ee7fc5a56b 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept.bpf.c @@ -74,7 +74,7 @@ int BPF_PROG(accept_x, /* Parameter 2: tuple (type: PT_SOCKTUPLE) */ if(ret >= 0) { - auxmap__store_socktuple_param(auxmap, (int32_t)ret, INBOUND); + auxmap__store_socktuple_param(auxmap, (int32_t)ret, INBOUND, NULL); /* Collect parameters at the beginning to manage socketcalls */ unsigned long args[1]; diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept4.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept4.bpf.c index 2e1496c51c..67003794da 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept4.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/accept4.bpf.c @@ -78,7 +78,7 @@ int BPF_PROG(accept4_x, /* Parameter 2: tuple (type: PT_SOCKTUPLE) */ if(ret >= 0) { - auxmap__store_socktuple_param(auxmap, (int32_t)ret, INBOUND); + auxmap__store_socktuple_param(auxmap, (int32_t)ret, INBOUND, NULL); /* Collect parameters at the beginning to manage socketcalls */ unsigned long args[1]; diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/connect.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/connect.bpf.c index a1b34fad12..23cea8be68 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/connect.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/connect.bpf.c @@ -77,7 +77,7 @@ int BPF_PROG(connect_x, /* We need a valid sockfd to extract source data.*/ if(ret == 0 || ret == -EINPROGRESS) { - auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND); + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, NULL); } else { diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvfrom.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvfrom.bpf.c index e64ecffeb3..3bd2a58568 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvfrom.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvfrom.bpf.c @@ -93,7 +93,7 @@ int BPF_PROG(recvfrom_x, /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ uint32_t socket_fd = (uint32_t)args[0]; - auxmap__store_socktuple_param(auxmap, socket_fd, INBOUND); + auxmap__store_socktuple_param(auxmap, socket_fd, INBOUND, NULL); } else { diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvmsg.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvmsg.bpf.c index 95d8ac5283..38863cd959 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvmsg.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/recvmsg.bpf.c @@ -93,7 +93,7 @@ int BPF_PROG(recvmsg_x, /* Parameter 4: tuple (type: PT_SOCKTUPLE) */ uint32_t socket_fd = (uint32_t)args[0]; - auxmap__store_socktuple_param(auxmap, socket_fd, INBOUND); + auxmap__store_socktuple_param(auxmap, socket_fd, INBOUND, NULL); /* Parameter 5: msg_control (type: PT_BYTEBUF) */ if (msghhdr.msg_control != NULL) diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c index a2f1a021d6..41f3e42eef 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c @@ -45,7 +45,7 @@ int BPF_PROG(sendmsg_e, */ if(socket_fd >= 0) { - auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND); + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, NULL); } else { diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendto.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendto.bpf.c index 8180f57180..746f009398 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendto.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendto.bpf.c @@ -25,8 +25,8 @@ int BPF_PROG(sendto_e, /*=============================== COLLECT PARAMETERS ===========================*/ /* Collect parameters at the beginning to manage socketcalls */ - unsigned long args[3]; - extract__network_args(args, 3, regs); + unsigned long args[5]; + extract__network_args(args, 5, regs); /* Parameter 1: fd (type: PT_FD) */ int32_t socket_fd = (int32_t)args[0]; @@ -45,7 +45,8 @@ int BPF_PROG(sendto_e, */ if(socket_fd >= 0) { - auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND); + struct sockaddr *usrsockaddr = (struct sockaddr *)args[4]; + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, usrsockaddr); } else { From 2ea4184ddc24f291ae6341c453977ceea0cc5ba3 Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Tue, 13 Feb 2024 12:12:18 +0100 Subject: [PATCH 2/4] chore(modern_bpf): add more detailed comment Signed-off-by: Gianmatteo Palmieri --- driver/modern_bpf/helpers/store/auxmap_store_params.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/driver/modern_bpf/helpers/store/auxmap_store_params.h b/driver/modern_bpf/helpers/store/auxmap_store_params.h index 2544f72a0a..ba9846dd86 100644 --- a/driver/modern_bpf/helpers/store/auxmap_store_params.h +++ b/driver/modern_bpf/helpers/store/auxmap_store_params.h @@ -595,7 +595,8 @@ static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map * BPF_CORE_READ_INTO(&ipv4_remote, sk, __sk_common.skc_daddr); BPF_CORE_READ_INTO(&port_remote, sk, __sk_common.skc_dport); - /* Fallback to userspace struct if address info from kernel is NULL*/ + /* Kernel doesn't always fill sk->__sk_common in sendto and sendmsg syscalls (as in the case of an UDP connection). + * We fallback to the address from userspace when the kernel-provided address is NULL */ if (port_remote == 0 && usrsockaddr != NULL) { struct sockaddr_in usrsockaddr_in = {}; @@ -646,7 +647,8 @@ static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map * BPF_CORE_READ_INTO(&ipv6_remote, sk, __sk_common.skc_v6_daddr); BPF_CORE_READ_INTO(&port_remote, sk, __sk_common.skc_dport); - /* Fallback to userspace struct if address info from kernel is NULL*/ + /* Kernel doesn't always fill sk->__sk_common in sendto and sendmsg syscalls (as in the case of an UDP connection). + * We fallback to the address from userspace when the kernel-provided address is NULL */ if (port_remote == 0 && usrsockaddr != NULL) { struct sockaddr_in6 usrsockaddr_in6 = {}; From b1415cb5d6e6cacd48aa41193185f5e164ff8ace Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Tue, 13 Feb 2024 12:25:22 +0100 Subject: [PATCH 3/4] fix(modern_bpf): null destination address in sendmsg syscall Signed-off-by: Gianmatteo Palmieri --- .../events/syscall_dispatched_events/sendmsg.bpf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c index 41f3e42eef..230a6459c9 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendmsg.bpf.c @@ -45,7 +45,10 @@ int BPF_PROG(sendmsg_e, */ if(socket_fd >= 0) { - auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, NULL); + struct sockaddr *usrsockaddr; + struct msghdr *msg = (struct msghdr*)msghdr_pointer; + BPF_CORE_READ_USER_INTO(&usrsockaddr, msg, msg_name); + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, usrsockaddr); } else { From 59f8cd983176a8c74696ab4d557f141b98949672 Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Tue, 13 Feb 2024 16:07:32 +0100 Subject: [PATCH 4/4] new(test): add sendto and sendmg udp connection tests Signed-off-by: Gianmatteo Palmieri --- .../syscall_enter_suite/sendmsg_e.cpp | 74 +++++++++++++++++++ .../syscall_enter_suite/sendto_e.cpp | 57 ++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/test/drivers/test_suites/syscall_enter_suite/sendmsg_e.cpp b/test/drivers/test_suites/syscall_enter_suite/sendmsg_e.cpp index f51cce35c1..4768695fce 100644 --- a/test/drivers/test_suites/syscall_enter_suite/sendmsg_e.cpp +++ b/test/drivers/test_suites/syscall_enter_suite/sendmsg_e.cpp @@ -75,4 +75,78 @@ TEST(SyscallEnter, sendmsgE) evt_test->assert_num_params_pushed(3); } + +TEST(SyscallEnter, sendmsgE_udp) +{ + auto evt_test = get_syscall_event_test(__NR_sendmsg, ENTER_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t client_socket_fd = 0; + int32_t server_socket_fd = 0; + sockaddr_in client_addr = {0}; + sockaddr_in server_addr = {0}; + evt_test->connect_ipv4_udp_client_to_server(&client_socket_fd, &client_addr, &server_socket_fd, &server_addr); + + /* Send a message to the server */ + struct msghdr send_msg; + struct iovec iov[3]; + memset(&send_msg, 0, sizeof(send_msg)); + memset(iov, 0, sizeof(iov)); + send_msg.msg_name = (sockaddr*)&server_addr; + send_msg.msg_namelen = sizeof(server_addr); + char sent_data_1[FIRST_MESSAGE_LEN] = "hey! there is a first message here."; + char sent_data_2[SECOND_MESSAGE_LEN] = "hey! there is a second message here."; + char sent_data_3[THIRD_MESSAGE_LEN] = "hey! there is a third message here."; + iov[0].iov_base = sent_data_1; + iov[0].iov_len = sizeof(sent_data_1); + iov[1].iov_base = sent_data_2; + iov[1].iov_len = sizeof(sent_data_2); + iov[2].iov_base = sent_data_3; + iov[2].iov_len = sizeof(sent_data_3); + send_msg.msg_iov = iov; + send_msg.msg_iovlen = 3; + uint32_t sendmsg_flags = 0; + + assert_syscall_state(SYSCALL_SUCCESS, "sendmsg (client)", syscall(__NR_sendmsg, client_socket_fd, &send_msg, sendmsg_flags), NOT_EQUAL, -1); + + /* Cleaning phase */ + syscall(__NR_shutdown, server_socket_fd, 2); + syscall(__NR_shutdown, client_socket_fd, 2); + syscall(__NR_close, server_socket_fd); + syscall(__NR_close, client_socket_fd); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: fd (type: PT_FD) */ + evt_test->assert_numeric_param(1, (int64_t)client_socket_fd); + + /* Parameter 2: size (type: PT_UINT32)*/ + evt_test->assert_numeric_param(2, (uint32_t)FULL_MESSAGE_LEN); + + /* Parameter 3: addr (type: PT_SOCKADDR)*/ + /* The client performs a `sendmsg` to the server so the src_ipv4 is the client one. */ + evt_test->assert_tuple_inet_param(3, PPM_AF_INET, IPV4_CLIENT, IPV4_SERVER, IPV4_PORT_CLIENT_STRING, IPV4_PORT_SERVER_STRING); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(3); +} #endif diff --git a/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp b/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp index fa2ddcc2aa..ae6002b961 100644 --- a/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp +++ b/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp @@ -58,4 +58,61 @@ TEST(SyscallEnter, sendtoE) evt_test->assert_num_params_pushed(3); } + +TEST(SyscallEnter, sendtoE_udp) +{ + auto evt_test = get_syscall_event_test(__NR_sendto, ENTER_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t client_socket_fd = 0; + int32_t server_socket_fd = 0; + sockaddr_in client_addr = {0}; + sockaddr_in server_addr = {0}; + evt_test->connect_ipv4_udp_client_to_server(&client_socket_fd, &client_addr, &server_socket_fd, &server_addr); + + /* Send a message to the server */ + char sent_data[FULL_MESSAGE_LEN] = FULL_MESSAGE; + uint32_t sendto_flags = 0; + assert_syscall_state(SYSCALL_SUCCESS, "sendto (client)", syscall(__NR_sendto, client_socket_fd, sent_data, sizeof(sent_data), sendto_flags, (sockaddr*)&server_addr, sizeof(server_addr)), NOT_EQUAL, -1); + + /* Cleaning phase */ + syscall(__NR_shutdown, server_socket_fd, 2); + syscall(__NR_shutdown, client_socket_fd, 2); + syscall(__NR_close, server_socket_fd); + syscall(__NR_close, client_socket_fd); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: fd (type: PT_FD) */ + evt_test->assert_numeric_param(1, (int64_t)client_socket_fd); + + /* Parameter 2: size (type: PT_UINT32)*/ + evt_test->assert_numeric_param(2, (uint32_t)FULL_MESSAGE_LEN); + + /* Parameter 3: addr (type: PT_SOCKADDR)*/ + /* The client performs a `sendto` to the server so the src_ipv4 is the client one. */ + evt_test->assert_tuple_inet_param(3, PPM_AF_INET, IPV4_CLIENT, IPV4_SERVER, IPV4_PORT_CLIENT_STRING, IPV4_PORT_SERVER_STRING); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(3); +} #endif