Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix(modern_bpf): null destination address in sendto and sendmsg syscalls #1687

Merged
merged 4 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 22 additions & 1 deletion driver/modern_bpf/helpers/store/auxmap_store_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -594,6 +595,16 @@ 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);

/* 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 = {};
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
Expand Down Expand Up @@ -636,6 +647,16 @@ 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);

/* 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 = {};
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ int BPF_PROG(sendmsg_e,
*/
if(socket_fd >= 0)
{
auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND);
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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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
{
Expand Down
74 changes: 74 additions & 0 deletions test/drivers/test_suites/syscall_enter_suite/sendmsg_e.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
57 changes: 57 additions & 0 deletions test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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