From b467d6dc75624880af91c35cb083c2bf71cfd3b2 Mon Sep 17 00:00:00 2001 From: Leonardo Di Giovanna Date: Thu, 2 Jan 2025 17:35:27 +0100 Subject: [PATCH 1/2] new: extend SEND_X and SENDTO_X Signed-off-by: Leonardo Di Giovanna --- driver/SCHEMA_VERSION | 2 +- driver/bpf/fillers.h | 210 ++++++++++----- driver/event_table.c | 26 +- driver/fillers_table.c | 2 +- .../syscall_dispatched_events/send.bpf.c | 34 ++- .../syscall_dispatched_events/sendto.bpf.c | 57 ++-- driver/ppm_events.c | 2 +- driver/ppm_fillers.c | 244 ++++++++++++------ driver/ppm_fillers.h | 1 + test/drivers/event_class/event_class.cpp | 7 +- .../actions_suite/dynamic_snaplen.cpp | 177 +++++++++++-- .../test_suites/actions_suite/ia32.cpp.in | 13 +- .../syscall_enter_suite/sendto_e.cpp | 4 +- .../test_suites/syscall_exit_suite/send_x.cpp | 8 +- .../syscall_exit_suite/sendto_x.cpp | 130 ++++++++-- .../engines/savefile/converter.cpp | 192 +++++++++++++- test/libsinsp_e2e/udp_client_server.cpp | 17 +- test/libsinsp_e2e/unix_client_server.cpp | 7 +- .../engine/savefile/converter/table.cpp | 17 +- userspace/libscap/scap.h | 2 +- userspace/libscap/scap_event.c | 2 + userspace/libsinsp/parsers.cpp | 78 +++--- .../libsinsp/test/parsers/parse_send.cpp | 69 +++++ .../libsinsp/test/parsers/parse_sendto.cpp | 69 +++++ .../test/scap_files/converter_tests.cpp | 57 +++- 25 files changed, 1131 insertions(+), 296 deletions(-) create mode 100644 userspace/libsinsp/test/parsers/parse_send.cpp create mode 100644 userspace/libsinsp/test/parsers/parse_sendto.cpp diff --git a/driver/SCHEMA_VERSION b/driver/SCHEMA_VERSION index 40c341bdcd..7c69a55dbb 100644 --- a/driver/SCHEMA_VERSION +++ b/driver/SCHEMA_VERSION @@ -1 +1 @@ -3.6.0 +3.7.0 diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 74365f647b..b61cf62c6c 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -1529,101 +1529,179 @@ FILLER(sys_getsockopt_x, true) { return bpf_push_u32_to_ring(data, optlen); } -static __always_inline int f_sys_send_e_common(struct filler_data *data, int fd) { - unsigned long val; +FILLER(sys_send_e, true) { int res; - /* - * fd - */ - res = bpf_push_s64_to_ring(data, (int64_t)fd); + /* Parameter 1: fd (type: PT_FD) */ + int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0); + res = bpf_push_s64_to_ring(data, fd); CHECK_RES(res); - /* - * size - */ - val = bpf_syscall_get_argument(data, 2); - res = bpf_push_u32_to_ring(data, val); - - return res; + /* Parameter 2: size (type: PT_UINT32) */ + uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2); + return bpf_push_u32_to_ring(data, size); } -FILLER(sys_send_e, true) { - /* - * Push the common params to the ring - */ - int fd = bpf_syscall_get_argument(data, 0); - return f_sys_send_e_common(data, fd); -} +FILLER(sys_send_x, true) { + /* Parameter 1: res (type: PT_ERRNO) */ + long retval = bpf_syscall_get_retval(data->ctx); + int res = bpf_push_s64_to_ring(data, retval); + CHECK_RES(res); -FILLER(sys_sendto_e, true) { - struct sockaddr __user *usrsockaddr; - unsigned long val; - long size = 0; - int err = 0; - int res; - int fd; + /* Extract fd and size syscall parameters */ + int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0); + uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2); - /* - * Push the common params to the ring + /* Parameter 2: data (type: PT_BYTEBUF) */ + /* If the syscall doesn't fail we use the return value as `size` + * otherwise we need to rely on the syscall parameter provided by the user. */ - fd = bpf_syscall_get_argument(data, 0); - res = f_sys_send_e_common(data, fd); + unsigned long sent_data_pointer = bpf_syscall_get_argument(data, 1); + unsigned long bytes_to_read = retval > 0 ? retval : size; + data->fd = fd; + res = __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER); CHECK_RES(res); - /* - * Get the address - */ - val = bpf_syscall_get_argument(data, 4); - usrsockaddr = (struct sockaddr __user *)val; + /* Parameter 3: fd (type: PT_FD) */ + res = bpf_push_s64_to_ring(data, fd); + CHECK_RES(res); - /* - * Get the address len - */ - val = bpf_syscall_get_argument(data, 5); + /* Parameter 4: size (type: PT_UINT32) */ + res = bpf_push_u32_to_ring(data, size); + CHECK_RES(res); - if(usrsockaddr && val != 0) { - /* - * Copy the address - */ - err = bpf_addr_to_kernel(usrsockaddr, val, (struct sockaddr *)data->tmp_scratch); - if(err >= 0) { - /* - * Convert the fd into socket endpoint information - */ - size = bpf_fd_to_socktuple(data, - fd, - (struct sockaddr *)data->tmp_scratch, - val, - true, - false, - data->tmp_scratch + sizeof(struct sockaddr_storage)); - } + if(retval < 0) { + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + return bpf_push_empty_param(data); } - /* - * Copy the endpoint info into the ring - */ + /* Convert the fd into socket endpoint information */ + char *tmp_area = data->tmp_scratch + sizeof(struct sockaddr_storage); + uint16_t tuple_size = bpf_fd_to_socktuple(data, fd, NULL, 0, false, false, tmp_area); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ data->curarg_already_on_frame = true; - res = bpf_val_to_ring_len(data, 0, size); + return bpf_val_to_ring_len(data, 0, tuple_size); +} - return res; +FILLER(sys_sendto_e, true) { + /* Parameter 1: fd (type: PT_FD) */ + int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0); + int res = bpf_push_s64_to_ring(data, fd); + CHECK_RES(res); + + /* Parameter 2: size (type: PT_UINT32) */ + uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2); + res = bpf_push_u32_to_ring(data, size); + CHECK_RES(res); + + /* Get the address */ + struct sockaddr __user *usrsockaddr = + (struct sockaddr __user *)bpf_syscall_get_argument(data, 4); + + /* Get the address len */ + unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 5); + + /* Evaluate socktuple, leveraging the user-provided sockaddr if possible */ + char *tmp_area = data->tmp_scratch + sizeof(struct sockaddr_storage); + uint32_t tuple_size = 0; + bool tuple_extracted = false; + if(usrsockaddr != NULL && usrsockaddr_len != 0) { + /* Copy the address into kernel memory */ + struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch; + res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr); + if(likely(res >= 0)) { + /* Convert the fd into socket endpoint information */ + tuple_size = bpf_fd_to_socktuple(data, + fd, + ksockaddr, + usrsockaddr_len, + true, + false, + tmp_area); + tuple_extracted = true; + } + } + + if(!tuple_extracted) { + /* Try to extract socktuple from kernel */ + tuple_size = bpf_fd_to_socktuple(data, fd, NULL, 0, false, false, tmp_area); + } + + /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ + data->curarg_already_on_frame = true; + return bpf_val_to_ring_len(data, 0, tuple_size); } -FILLER(sys_send_x, true) { +FILLER(sys_sendto_x, true) { /* Parameter 1: res (type: PT_ERRNO) */ long retval = bpf_syscall_get_retval(data->ctx); int res = bpf_push_s64_to_ring(data, retval); CHECK_RES(res); + /* Extract fd and size syscall parameters */ + int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0); + uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ /* If the syscall doesn't fail we use the return value as `size` * otherwise we need to rely on the syscall parameter provided by the user. */ - unsigned long bytes_to_read = retval > 0 ? retval : bpf_syscall_get_argument(data, 2); unsigned long sent_data_pointer = bpf_syscall_get_argument(data, 1); - data->fd = bpf_syscall_get_argument(data, 0); - return __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER); + unsigned long bytes_to_read = retval > 0 ? retval : size; + data->fd = fd; + res = __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER); + CHECK_RES(res); + + /* Parameter 3: fd (type: PT_FD) */ + res = bpf_push_s64_to_ring(data, fd); + CHECK_RES(res); + + /* Parameter 4: size (type: PT_UINT32) */ + res = bpf_push_u32_to_ring(data, size); + CHECK_RES(res); + + if(retval < 0) { + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + return bpf_push_empty_param(data); + } + + /* Get the address */ + struct sockaddr __user *usrsockaddr = + (struct sockaddr __user *)bpf_syscall_get_argument(data, 4); + + /* Get the address len */ + unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 5); + + /* Evaluate socktuple, leveraging the user-provided sockaddr if possible */ + char *tmp_area = data->tmp_scratch + sizeof(struct sockaddr_storage); + uint32_t tuple_size = 0; + bool tuple_extracted = false; + if(usrsockaddr != NULL && usrsockaddr_len != 0) { + /* Copy the address into kernel memory */ + struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch; + res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr); + if(likely(res >= 0)) { + /* Convert the fd into socket endpoint information */ + tuple_size = bpf_fd_to_socktuple(data, + fd, + ksockaddr, + usrsockaddr_len, + true, + false, + tmp_area); + tuple_extracted = true; + } + } + + if(!tuple_extracted) { + /* Try to extract socktuple from kernel */ + tuple_size = bpf_fd_to_socktuple(data, fd, NULL, 0, false, false, tmp_area); + } + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + data->curarg_already_on_frame = true; + return bpf_val_to_ring_len(data, 0, tuple_size); } FILLER(sys_execve_e, true) { diff --git a/driver/event_table.c b/driver/event_table.c index 5ccd42c6c3..2e483963e0 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -219,26 +219,36 @@ const struct ppm_event_info g_event_info[] = { {"queuepct", PT_UINT8, PF_DEC}}}, [PPME_SOCKET_SEND_E] = {"send", EC_IO_WRITE | EC_SYSCALL, - EF_USES_FD | EF_WRITES_TO_FD, + EF_USES_FD | EF_WRITES_TO_FD | EF_TMP_CONVERTER_MANAGED, 2, {{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC}}}, [PPME_SOCKET_SEND_X] = {"send", EC_IO_WRITE | EC_SYSCALL, - EF_USES_FD | EF_WRITES_TO_FD, - 2, - {{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}}, + EF_USES_FD | EF_WRITES_TO_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}, + {"tuple", PT_SOCKTUPLE, PF_NA}}}, [PPME_SOCKET_SENDTO_E] = {"sendto", EC_IO_WRITE | EC_SYSCALL, - EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE, + EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE | + EF_TMP_CONVERTER_MANAGED, 3, {{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC}, {"tuple", PT_SOCKTUPLE, PF_NA}}}, [PPME_SOCKET_SENDTO_X] = {"sendto", EC_IO_WRITE | EC_SYSCALL, - EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE, - 2, - {{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}}, + EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE | + 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}, + {"tuple", PT_SOCKTUPLE, PF_NA}}}, [PPME_SOCKET_RECV_E] = {"recv", EC_IO_READ | EC_SYSCALL, EF_USES_FD | EF_READS_FROM_FD, diff --git a/driver/fillers_table.c b/driver/fillers_table.c index 8146671724..41318acfb1 100644 --- a/driver/fillers_table.c +++ b/driver/fillers_table.c @@ -45,7 +45,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = { [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)}, - [PPME_SOCKET_SENDTO_X] = {FILLER_REF(sys_send_x)}, + [PPME_SOCKET_SENDTO_X] = {FILLER_REF(sys_sendto_x)}, [PPME_SOCKET_RECV_E] = {FILLER_REF(sys_autofill), 2, APT_SOCK, {{0}, {2}}}, [PPME_SOCKET_RECV_X] = {FILLER_REF(sys_recv_x)}, [PPME_SOCKET_RECVFROM_E] = {FILLER_REF(sys_recvfrom_e)}, diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/send.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/send.bpf.c index 1324783f36..530b0fe545 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/send.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/send.bpf.c @@ -29,8 +29,8 @@ int BPF_PROG(send_e, struct pt_regs *regs, long id) { /*=============================== COLLECT PARAMETERS ===========================*/ /* Parameter 1: fd (type: PT_FD) */ - int32_t fd = (int32_t)args[0]; - ringbuf__store_s64(&ringbuf, (int64_t)fd); + int64_t fd = (int32_t)args[0]; + ringbuf__store_s64(&ringbuf, fd); /* Parameter 2: size (type: PT_UINT32) */ uint32_t size = (uint32_t)args[2]; @@ -62,16 +62,23 @@ int BPF_PROG(send_x, struct pt_regs *regs, long ret) { auxmap__store_s64_param(auxmap, ret); /* Collect parameters at the beginning to manage socketcalls */ - unsigned long args[3] = {0}; - extract__network_args(args, 3, regs); + unsigned long args[5] = {0}; + extract__network_args(args, 5, regs); dynamic_snaplen_args snaplen_args = { .only_port_range = false, .evt_type = PPME_SOCKET_SEND_X, }; - int64_t bytes_to_read = ret > 0 ? ret : args[2]; uint16_t snaplen = maps__get_snaplen(); apply_dynamic_snaplen(regs, &snaplen, &snaplen_args); + + /* Extract size syscall parameter */ + uint32_t size = (uint32_t)args[2]; + + /* If the syscall doesn't fail we use the return value as `size` + * otherwise we need to rely on the syscall parameter provided by the user */ + int64_t bytes_to_read = ret > 0 ? ret : (int64_t)size; + if((int64_t)snaplen > bytes_to_read) { snaplen = bytes_to_read; } @@ -80,6 +87,23 @@ int BPF_PROG(send_x, struct pt_regs *regs, long ret) { unsigned long sent_data_pointer = args[1]; auxmap__store_bytebuf_param(auxmap, sent_data_pointer, snaplen, USER); + /* Parameter 3: fd (type: PT_FD) */ + int64_t fd = (int32_t)args[0]; + auxmap__store_s64_param(auxmap, fd); + + /* Parameter 4: size (type: PT_UINT32) */ + auxmap__store_u32_param(auxmap, size); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + if(ret >= 0) { + struct sockaddr *usrsockaddr = (struct sockaddr *)args[4]; + /* Notice: the following will push an empty parameter if + * something goes wrong (e.g.: fd not valid) */ + auxmap__store_socktuple_param(auxmap, fd, OUTBOUND, NULL); + } else { + auxmap__store_empty_param(auxmap); + } + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); 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 e4b0cb7711..d0c31cb2a2 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,26 +25,24 @@ int BPF_PROG(sendto_e, struct pt_regs *regs, long id) { extract__network_args(args, 5, regs); /* Parameter 1: fd (type: PT_FD) */ - int32_t socket_fd = (int32_t)args[0]; - auxmap__store_s64_param(auxmap, (int64_t)socket_fd); + int64_t socket_fd = (int32_t)args[0]; + auxmap__store_s64_param(auxmap, socket_fd); /* Parameter 2: size (type: PT_UINT32) */ uint32_t size = (uint32_t)args[2]; auxmap__store_u32_param(auxmap, size); - /* Parameter 3: tuple (type: PT_SOCKTUPLE)*/ + /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ /* TODO: Here we don't know if this fd is a socket or not, - * since we are in the enter event and the syscall could fail. - * This shouldn't be a problem since if it is not a socket fd - * the `bpf_probe_read()` call we fail. Probably we have to move it - * in the exit event. + * since we are in the enter event and the syscall could fail. + * This shouldn't be a problem since if it is not a socket fd + * the `bpf_probe_read()` call will fail. Probably we have to move it + * in the exit event. */ - if(socket_fd >= 0) { - struct sockaddr *usrsockaddr = (struct sockaddr *)args[4]; - auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, usrsockaddr); - } else { - auxmap__store_empty_param(auxmap); - } + struct sockaddr *usrsockaddr = (struct sockaddr *)args[4]; + /* Notice: the following will push an empty parameter if + * something goes wrong (e.g.: fd not valid) */ + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, usrsockaddr); /*=============================== COLLECT PARAMETERS ===========================*/ @@ -74,19 +72,23 @@ int BPF_PROG(sendto_x, struct pt_regs *regs, long ret) { auxmap__store_s64_param(auxmap, ret); /* Collect parameters at the beginning to manage socketcalls */ - unsigned long args[3] = {0}; - extract__network_args(args, 3, regs); + unsigned long args[5] = {0}; + extract__network_args(args, 5, regs); - /* If the syscall doesn't fail we use the return value as `size` - * otherwise we need to rely on the syscall parameter provided by the user. - */ dynamic_snaplen_args snaplen_args = { .only_port_range = false, .evt_type = PPME_SOCKET_SENDTO_X, }; - int64_t bytes_to_read = ret > 0 ? ret : args[2]; uint16_t snaplen = maps__get_snaplen(); apply_dynamic_snaplen(regs, &snaplen, &snaplen_args); + + /* Extract size syscall parameter */ + uint32_t size = (uint32_t)args[2]; + + /* If the syscall doesn't fail we use the return value as `size` + * otherwise we need to rely on the syscall parameter provided by the user. */ + int64_t bytes_to_read = ret > 0 ? ret : (int64_t)size; + if((int64_t)snaplen > bytes_to_read) { snaplen = bytes_to_read; } @@ -95,6 +97,23 @@ int BPF_PROG(sendto_x, struct pt_regs *regs, long ret) { unsigned long sent_data_pointer = args[1]; auxmap__store_bytebuf_param(auxmap, sent_data_pointer, snaplen, USER); + /* Parameter 3: fd (type: PT_FD) */ + int64_t socket_fd = (int32_t)args[0]; + auxmap__store_s64_param(auxmap, socket_fd); + + /* Parameter 4: size (type: PT_UINT32) */ + auxmap__store_u32_param(auxmap, size); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + if(ret >= 0) { + struct sockaddr *usrsockaddr = (struct sockaddr *)args[4]; + /* Notice: the following will push an empty parameter if + * something goes wrong (e.g.: fd not valid) */ + auxmap__store_socktuple_param(auxmap, socket_fd, OUTBOUND, usrsockaddr); + } else { + auxmap__store_empty_param(auxmap); + } + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/ppm_events.c b/driver/ppm_events.c index 23c7ecf1c6..393bcd9dbe 100644 --- a/driver/ppm_events.c +++ b/driver/ppm_events.c @@ -978,7 +978,7 @@ uint16_t pack_addr(struct sockaddr *usrsockaddr, /* * Convert a connection tuple into our tuple representation and copy it to - * targetbuf + * targetbuf. Return the tuple size in case of success; 0 otherwise. */ uint16_t fd_to_socktuple(int fd, struct sockaddr *usrsockaddr, diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 7abc11d79d..267b282290 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -2251,130 +2251,224 @@ int f_sys_accept_x(struct event_filler_arguments *args) { return add_sentinel(args); } -static int f_sys_send_e_common(struct event_filler_arguments *args, int *fd) { +int f_sys_send_e(struct event_filler_arguments *args) { int res; - unsigned long size; unsigned long val; - int32_t tmp_fd = 0; + int64_t fd; + uint32_t size; - /* - * fd - */ + /* Parameter 1: fd (type: PT_FD) */ syscall_get_arguments_deprecated(args, 0, 1, &val); - tmp_fd = (int32_t)val; - res = val_to_ring(args, (int64_t)tmp_fd, 0, false, 0); + fd = (int64_t)(int32_t)val; + res = val_to_ring(args, fd, 0, false, 0); CHECK_RES(res); - *fd = val; - - /* - * size - */ - syscall_get_arguments_deprecated(args, 2, 1, &size); - + /* Parameter 2: size (type: PT_UINT32) */ + syscall_get_arguments_deprecated(args, 2, 1, &val); + size = (uint32_t)val; res = val_to_ring(args, size, 0, false, 0); CHECK_RES(res); - return PPM_SUCCESS; + return add_sentinel(args); } -int f_sys_send_e(struct event_filler_arguments *args) { +int f_sys_send_x(struct event_filler_arguments *args) { int res; - int fd; + int64_t retval; + unsigned long val; + int64_t fd; + uint32_t size; + unsigned long sent_data_pointer, bytes_to_read; + char *targetbuf = args->str_storage; + uint16_t tuple_size; - res = f_sys_send_e_common(args, &fd); + /* 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); + CHECK_RES(res); - if(likely(res == PPM_SUCCESS)) + /* Extract fd and size syscall parameters */ + syscall_get_arguments_deprecated(args, 0, 1, &val); + fd = (int64_t)(int32_t)val; + syscall_get_arguments_deprecated(args, 2, 1, &val); + size = (uint32_t)val; + + /* Parameter 2: data (type: PT_BYTEBUF) */ + /* If the syscall doesn't fail we use the return value as `size` + * otherwise we need to rely on the syscall parameter provided by the user. + */ + syscall_get_arguments_deprecated(args, 1, 1, &sent_data_pointer); + bytes_to_read = retval > 0 ? retval : (unsigned long)size; + args->fd = (int)fd; + args->enforce_snaplen = true; + res = val_to_ring(args, sent_data_pointer, bytes_to_read, true, 0); + CHECK_RES(res); + + /* Parameter 3: fd (type: PT_FD) */ + res = val_to_ring(args, fd, 0, false, 0); + CHECK_RES(res); + + /* Parameter 4: size (type: PT_UINT32) */ + res = val_to_ring(args, size, 0, false, 0); + CHECK_RES(res); + + if(retval < 0) { + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + res = push_empty_param(args); + CHECK_RES(res); return add_sentinel(args); - return res; + } + + /* Convert the fd into socket endpoint information */ + tuple_size = fd_to_socktuple((int)fd, NULL, 0, false, false, targetbuf, STR_STORAGE_SIZE); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + res = val_to_ring(args, (uint64_t)(unsigned long)targetbuf, tuple_size, false, 0); + CHECK_RES(res); + + return add_sentinel(args); } int f_sys_sendto_e(struct event_filler_arguments *args) { - unsigned long val; int res; - uint16_t size = 0; - char *targetbuf = args->str_storage; - int fd; + unsigned long val; + int64_t fd; + uint32_t size; struct sockaddr __user *usrsockaddr; + unsigned long usrsockaddr_len; struct sockaddr_storage address; - int err = 0; + struct sockaddr *ksockaddr = NULL; + unsigned long sockaddr_len = 0; + bool use_sockaddr = false; + char *targetbuf = args->str_storage; + uint16_t tuple_size = 0; - *targetbuf = 250; + /* Parameter 1: fd (type: PT_FD) */ + syscall_get_arguments_deprecated(args, 0, 1, &val); + fd = (int64_t)(int32_t)val; + res = val_to_ring(args, fd, 0, false, 0); + CHECK_RES(res); - /* - * Push the common params to the ring - */ - res = f_sys_send_e_common(args, &fd); + /* Parameter 2: size (type: PT_UINT32) */ + syscall_get_arguments_deprecated(args, 2, 1, &val); + size = (uint32_t)val; + res = val_to_ring(args, size, 0, false, 0); CHECK_RES(res); - /* - * Get the address - */ + /* Get the address */ syscall_get_arguments_deprecated(args, 4, 1, &val); - usrsockaddr = (struct sockaddr __user *)val; - /* - * Get the address len - */ - syscall_get_arguments_deprecated(args, 5, 1, &val); + /* Get the address len */ + syscall_get_arguments_deprecated(args, 5, 1, &usrsockaddr_len); - if(usrsockaddr != NULL && val != 0) { - /* - * Copy the address - */ - err = addr_to_kernel(usrsockaddr, val, (struct sockaddr *)&address); - if(likely(err >= 0)) { - /* - * Convert the fd into socket endpoint information - */ - size = fd_to_socktuple(fd, - (struct sockaddr *)&address, - val, - true, - false, - targetbuf, - STR_STORAGE_SIZE); + if(usrsockaddr != NULL && usrsockaddr_len != 0) { + /* Copy the address into kernel memory */ + res = addr_to_kernel(usrsockaddr, usrsockaddr_len, (struct sockaddr *)&address); + if(likely(res >= 0)) { + ksockaddr = (struct sockaddr *)&address; + sockaddr_len = usrsockaddr_len; + use_sockaddr = true; } } - /* - * Copy the endpoint info into the ring - */ - res = val_to_ring(args, (uint64_t)(unsigned long)targetbuf, size, false, 0); + /* Convert the fd into socket endpoint information */ + tuple_size = fd_to_socktuple((int)fd, + ksockaddr, + sockaddr_len, + use_sockaddr, + false, + targetbuf, + STR_STORAGE_SIZE); + + /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ + res = val_to_ring(args, (uint64_t)(unsigned long)targetbuf, tuple_size, false, 0); CHECK_RES(res); return add_sentinel(args); } -int f_sys_send_x(struct event_filler_arguments *args) { - unsigned long val; +int f_sys_sendto_x(struct event_filler_arguments *args) { int res; int64_t retval; - unsigned long bufsize; - - /* - * Retrieve the FD. It will be used for dynamic snaplen calculation. - */ - syscall_get_arguments_deprecated(args, 0, 1, &val); - - args->fd = (int)val; + unsigned long val; + int64_t fd; + uint32_t size; + unsigned long sent_data_pointer, bytes_to_read; + struct sockaddr __user *usrsockaddr; + unsigned long usrsockaddr_len; + struct sockaddr_storage address; + struct sockaddr *ksockaddr = NULL; + unsigned long sockaddr_len = 0; + bool use_sockaddr = false; + char *targetbuf = args->str_storage; + uint16_t tuple_size = 0; /* Parameter 1: res (type: PT_ERRNO) */ - retval = (int64_t)(long)syscall_get_return_value(current, args->regs); + retval = (int64_t)syscall_get_return_value(current, args->regs); res = val_to_ring(args, retval, 0, false, 0); CHECK_RES(res); + /* Extract fd and size syscall parameters */ + syscall_get_arguments_deprecated(args, 0, 1, &val); + fd = (int64_t)(int32_t)val; + syscall_get_arguments_deprecated(args, 2, 1, &val); + size = (uint32_t)val; + + /* Parameter 2: data (type: PT_BYTEBUF) */ /* If the syscall doesn't fail we use the return value as `size` * otherwise we need to rely on the syscall parameter provided by the user. */ - syscall_get_arguments_deprecated(args, 2, 1, &val); - bufsize = retval > 0 ? retval : val; + syscall_get_arguments_deprecated(args, 1, 1, &sent_data_pointer); + bytes_to_read = retval > 0 ? retval : (unsigned long)size; + args->fd = (int)fd; + args->enforce_snaplen = true; + res = val_to_ring(args, sent_data_pointer, bytes_to_read, true, 0); + CHECK_RES(res); - syscall_get_arguments_deprecated(args, 1, 1, &val); + /* Parameter 3: fd (type: PT_FD) */ + res = val_to_ring(args, fd, 0, false, 0); + CHECK_RES(res); - args->enforce_snaplen = true; - res = val_to_ring(args, val, bufsize, true, 0); + /* Parameter 4: size (type: PT_UINT32) */ + res = val_to_ring(args, size, 0, false, 0); + CHECK_RES(res); + + if(retval < 0) { + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + res = push_empty_param(args); + CHECK_RES(res); + return add_sentinel(args); + } + + /* Get the address */ + syscall_get_arguments_deprecated(args, 4, 1, &val); + usrsockaddr = (struct sockaddr __user *)val; + + /* Get the address len */ + syscall_get_arguments_deprecated(args, 5, 1, &usrsockaddr_len); + + if(usrsockaddr != NULL && usrsockaddr_len != 0) { + /* Copy the address into kernel memory */ + res = addr_to_kernel(usrsockaddr, usrsockaddr_len, (struct sockaddr *)&address); + if(likely(res >= 0)) { + ksockaddr = (struct sockaddr *)&address; + sockaddr_len = usrsockaddr_len; + use_sockaddr = true; + } + } + + /* Convert the fd into socket endpoint information */ + tuple_size = fd_to_socktuple((int)fd, + ksockaddr, + sockaddr_len, + use_sockaddr, + false, + targetbuf, + STR_STORAGE_SIZE); + + /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ + res = val_to_ring(args, (uint64_t)(unsigned long)targetbuf, tuple_size, false, 0); CHECK_RES(res); return add_sentinel(args); diff --git a/driver/ppm_fillers.h b/driver/ppm_fillers.h index 95a7d14441..0a1cb77003 100644 --- a/driver/ppm_fillers.h +++ b/driver/ppm_fillers.h @@ -40,6 +40,7 @@ or GPL2.txt for full copies of the license. FN(sys_send_e) \ FN(sys_send_x) \ FN(sys_sendto_e) \ + FN(sys_sendto_x) \ FN(sys_sendmsg_e) \ FN(sys_sendmsg_x) \ FN(sys_sendmmsg_x) \ diff --git a/test/drivers/event_class/event_class.cpp b/test/drivers/event_class/event_class.cpp index 3a8f45d561..6fa9bc1cfd 100644 --- a/test/drivers/event_class/event_class.cpp +++ b/test/drivers/event_class/event_class.cpp @@ -1440,7 +1440,8 @@ void event_test::assert_param_len_ge(uint16_t expected_size) { void event_test::assert_address_family(uint8_t desired_family, int starting_index) { uint8_t family = (uint8_t)(m_event_params[m_current_param].valptr[starting_index]); - ASSERT_EQ(family, desired_family) << VALUE_NOT_CORRECT << m_current_param << std::endl; + ASSERT_EQ(family, desired_family) + << VALUE_NOT_CORRECT << m_current_param << " (address family)" << std::endl; } void event_test::assert_ipv4_string(const char* desired_ipv4, int starting_index, direction dir) { @@ -1467,10 +1468,10 @@ void event_test::assert_port_string(const char* desired_port, int starting_index if(dir == DEST) { ASSERT_STREQ(port_string.c_str(), desired_port) - << VALUE_NOT_CORRECT << m_current_param << "(dest port)" << std::endl; + << VALUE_NOT_CORRECT << m_current_param << " (dest port)" << std::endl; } else { ASSERT_STREQ(port_string.c_str(), desired_port) - << VALUE_NOT_CORRECT << m_current_param << "(source port)" << std::endl; + << VALUE_NOT_CORRECT << m_current_param << " (source port)" << std::endl; } } diff --git a/test/drivers/test_suites/actions_suite/dynamic_snaplen.cpp b/test/drivers/test_suites/actions_suite/dynamic_snaplen.cpp index e8cf15993d..b10e9c38c1 100644 --- a/test/drivers/test_suites/actions_suite/dynamic_snaplen.cpp +++ b/test/drivers/test_suites/actions_suite/dynamic_snaplen.cpp @@ -73,7 +73,7 @@ TEST(Actions, dynamic_snaplen_negative_fd) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)errno_value); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ /* We expect the default snaplen since we cannot enable the dynamic snaplen logic */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); @@ -246,12 +246,23 @@ TEST(Actions, dynamic_snaplen_HTTP) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ - evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, buf, data_len); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_partial_HTTP_OPT) { @@ -338,12 +349,23 @@ TEST(Actions, dynamic_snaplen_partial_HTTP_OPT) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_HTTP_TRACE) { @@ -429,12 +451,23 @@ TEST(Actions, dynamic_snaplen_HTTP_TRACE) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ - evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, buf, data_len); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_MYSQL) { @@ -523,12 +556,23 @@ TEST(Actions, dynamic_snaplen_MYSQL) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ - evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, buf, data_len); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + std::to_string(PPM_PORT_MYSQL).c_str(), + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_not_MYSQL) { @@ -615,12 +659,23 @@ TEST(Actions, dynamic_snaplen_not_MYSQL) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + std::to_string(PPM_PORT_MYSQL).c_str(), + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_POSTGRES) { @@ -709,12 +764,23 @@ TEST(Actions, dynamic_snaplen_POSTGRES) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ - evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, buf, data_len); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + std::to_string(PPM_PORT_POSTGRES).c_str(), + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_not_POSTGRES) { @@ -801,12 +867,23 @@ TEST(Actions, dynamic_snaplen_not_POSTGRES) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + std::to_string(PPM_PORT_POSTGRES).c_str(), + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_MONGO) { @@ -893,12 +970,23 @@ TEST(Actions, dynamic_snaplen_MONGO) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_not_MONGO) { @@ -985,12 +1073,23 @@ TEST(Actions, dynamic_snaplen_not_MONGO) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_statsd_port) { @@ -1084,12 +1183,23 @@ TEST(Actions, dynamic_snaplen_statsd_port) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ - evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN * 2); + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, buf, data_len); + + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(Actions, dynamic_snaplen_no_statsd_port) { @@ -1183,12 +1293,23 @@ TEST(Actions, dynamic_snaplen_no_statsd_port) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)data_len); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, buf, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, data_len); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } #endif #endif diff --git a/test/drivers/test_suites/actions_suite/ia32.cpp.in b/test/drivers/test_suites/actions_suite/ia32.cpp.in index a5ebbfdf41..cd2ce47e12 100644 --- a/test/drivers/test_suites/actions_suite/ia32.cpp.in +++ b/test/drivers/test_suites/actions_suite/ia32.cpp.in @@ -769,9 +769,20 @@ TEST(Actions, ia32_socketcall_sendto) /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, NO_SNAPLEN_MESSAGE, NO_SNAPLEN_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)NO_SNAPLEN_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== 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_enter_suite/sendto_e.cpp b/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp index edb7d8513e..5f2cfb3ae0 100644 --- a/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp +++ b/test/drivers/test_suites/syscall_enter_suite/sendto_e.cpp @@ -31,10 +31,10 @@ TEST(SyscallEnter, sendtoE_ipv4_tcp) { /*=============================== ASSERT PARAMETERS ===========================*/ - /* Parameter 2: size (type: PT_UINT32)*/ + /* Parameter 2: size (type: PT_UINT32) */ evt_test->assert_numeric_param(2, (uint32_t)SHORT_MESSAGE_LEN); - /* Parameter 3: tuple (type: PT_SOCKTUPLE)*/ + /* Parameter 3: tuple (type: PT_SOCKTUPLE) */ evt_test->assert_tuple_inet_param(3, PPM_AF_INET, IPV4_CLIENT, diff --git a/test/drivers/test_suites/syscall_exit_suite/send_x.cpp b/test/drivers/test_suites/syscall_exit_suite/send_x.cpp index fef1db7bab..7d736daef8 100644 --- a/test/drivers/test_suites/syscall_exit_suite/send_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/send_x.cpp @@ -39,8 +39,14 @@ TEST(SyscallExit, sendX_fail) { /* 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)mock_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(5); } #endif diff --git a/test/drivers/test_suites/syscall_exit_suite/sendto_x.cpp b/test/drivers/test_suites/syscall_exit_suite/sendto_x.cpp index 1c9aeb5c78..bfe81f977e 100644 --- a/test/drivers/test_suites/syscall_exit_suite/sendto_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/sendto_x.cpp @@ -35,12 +35,23 @@ TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_by_snaplen) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)SHORT_MESSAGE_LEN); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, SHORT_MESSAGE, SHORT_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)SHORT_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_tcp_message_truncated_by_snaplen) { @@ -75,9 +86,20 @@ TEST(SyscallExit, sendtoX_ipv4_tcp_message_truncated_by_snaplen) { /* Parameter 2: data (type: PT_BYTEBUF)*/ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_fullcapture_port) { @@ -121,12 +143,22 @@ TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_fullcapture_port) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)LONG_MESSAGE_LEN); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, LONG_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_DNS_snaplen) { @@ -166,12 +198,23 @@ TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_DNS_snaplen) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)LONG_MESSAGE_LEN); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, LONG_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + std::to_string(PPM_PORT_DNS).c_str()); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv6_tcp_message_not_truncated_fullcapture_port) { @@ -218,9 +261,20 @@ TEST(SyscallExit, sendtoX_ipv6_tcp_message_not_truncated_fullcapture_port) { /* Parameter 2: data (type: PT_BYTEBUF)*/ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, LONG_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_fullcapture_port_NULL_sockaddr) { @@ -263,12 +317,23 @@ TEST(SyscallExit, sendtoX_ipv4_tcp_message_not_truncated_fullcapture_port_NULL_s /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)LONG_MESSAGE_LEN); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, LONG_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } /*=============================== UDP ===========================*/ @@ -304,9 +369,20 @@ TEST(SyscallExit, sendtoX_ipv4_udp_message_not_truncated_by_snaplen) { /* Parameter 2: data (type: PT_BYTEBUF)*/ evt_test->assert_bytebuf_param(2, SHORT_MESSAGE, SHORT_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)SHORT_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_udp_message_truncated_by_snaplen) { @@ -341,9 +417,20 @@ TEST(SyscallExit, sendtoX_ipv4_udp_message_truncated_by_snaplen) { /* Parameter 2: data (type: PT_BYTEBUF)*/ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, DEFAULT_SNAPLEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_ipv4_udp_message_not_truncated_fullcapture_port) { @@ -389,9 +476,20 @@ TEST(SyscallExit, sendtoX_ipv4_udp_message_not_truncated_fullcapture_port) { /* Parameter 2: data (type: PT_BYTEBUF)*/ evt_test->assert_bytebuf_param(2, LONG_MESSAGE, LONG_MESSAGE_LEN); + /* Parameter 4: size (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)LONG_MESSAGE_LEN); + + /* Parameter 5: tuple (type: PT_SOCKTUPLE) */ + evt_test->assert_tuple_inet_param(5, + PPM_AF_INET, + IPV4_CLIENT, + IPV4_SERVER, + IPV4_PORT_CLIENT_STRING, + IPV4_PORT_SERVER_STRING); + /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } // We cannot call a sendto without a destination address in UDP. Errno: 89 err_message: Destination @@ -443,7 +541,7 @@ TEST(SyscallExit, sendtoX_fail) { /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } TEST(SyscallExit, sendtoX_empty) { @@ -485,12 +583,12 @@ TEST(SyscallExit, sendtoX_empty) { /* Parameter 1: res (type: PT_ERRNO) */ evt_test->assert_numeric_param(1, (int64_t)errno_value); - /* Parameter 2: data (type: PT_BYTEBUF)*/ + /* Parameter 2: data (type: PT_BYTEBUF) */ evt_test->assert_empty_param(2); /*=============================== ASSERT PARAMETERS ===========================*/ - evt_test->assert_num_params_pushed(2); + evt_test->assert_num_params_pushed(5); } #endif /* __NR_sendmsg */ diff --git a/test/libscap/test_suites/engines/savefile/converter.cpp b/test/libscap/test_suites/engines/savefile/converter.cpp index 22b99d5841..9bc66d170a 100644 --- a/test/libscap/test_suites/engines/savefile/converter.cpp +++ b/test/libscap/test_suites/engines/savefile/converter.cpp @@ -18,13 +18,13 @@ limitations under the License. TEST_F(convert_event_test, conversion_not_needed) { uint64_t ts = 12; int64_t tid = 25; - const char data[] = "hello world"; + constexpr char data[] = "hello"; auto evt = create_safe_scap_event(ts, tid, PPME_CONTAINER_JSON_2_E, 1, - scap_const_sized_buffer{&data, strlen(data) + 1}); + scap_const_sized_buffer{data, sizeof(data)}); assert_single_conversion_failure(evt); } @@ -49,7 +49,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_READ_X_to_4_params_no_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char read_buf[] = "hello"; // Defaulted to 0 int64_t fd = 0; @@ -78,7 +78,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_READ_X_to_4_params_with_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char read_buf[] = "hello"; int64_t fd = 25; uint32_t size = 36; @@ -127,7 +127,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_PREAD_X_to_4_params_no_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char read_buf[] = "hello"; // Defaulted to 0 int64_t fd = 0; @@ -158,7 +158,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_PREAD_X_to_4_params_with_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t read_buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char read_buf[] = "hello"; int64_t fd = 25; uint32_t size = 36; uint64_t pos = 7; @@ -379,7 +379,7 @@ TEST_F(convert_event_test, PPME_SOCKET_ACCEPT_X_to_PPME_SOCKET_ACCEPT_5_X) { int64_t tid = 25; int64_t fd = 25; - char tuple[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char tuple[] = "tuple"; uint8_t queuepct = 3; // Defaulted to 0 @@ -435,7 +435,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_WRITE_X_to_4_params_no_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char buf[] = "hello"; // Defaulted to 0 int64_t fd = 0; @@ -464,7 +464,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_WRITE_X_to_4_params_with_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char buf[] = "hello"; int64_t fd = 25; uint32_t size = 36; @@ -513,7 +513,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_PWRITE_X_to_4_params_no_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char buf[] = "hello"; // Defaulted to 0 int64_t fd = 0; @@ -544,7 +544,7 @@ TEST_F(convert_event_test, PPME_SYSCALL_PWRITE_X_to_4_params_with_enter) { int64_t tid = 25; int64_t res = 89; - uint8_t buf[] = {'h', 'e', 'l', 'l', 'o'}; + constexpr char buf[] = "hello"; int64_t fd = 25; uint32_t size = 36; uint64_t pos = 7; @@ -572,3 +572,173 @@ TEST_F(convert_event_test, PPME_SYSCALL_PWRITE_X_to_4_params_with_enter) { size, pos)); } + +//////////////////////////// +// SEND +//////////////////////////// + +TEST_F(convert_event_test, PPME_SOCKET_SEND_E_store) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t fd = 25; + uint32_t size = 5; + auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_SEND_E, 2, fd, size); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); +} + +TEST_F(convert_event_test, PPME_SOCKET_SEND_X_to_5_params_no_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + constexpr char data[] = "hello"; + + // Defaulted + int64_t fd = 0; + uint32_t size = 0; + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SEND_X, + 2, + res, + scap_const_sized_buffer{data, sizeof(data)}), + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SEND_X, + 5, + res, + scap_const_sized_buffer{data, sizeof(data)}, + fd, + size, + scap_const_sized_buffer{nullptr, 0})); +} + +TEST_F(convert_event_test, PPME_SOCKET_SEND_X_to_5_params_with_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + int64_t fd = 25; + constexpr char data[] = "hello"; + constexpr int32_t size = sizeof(data); + + // After the first conversion we should have the storage + auto evt = create_safe_scap_event(ts, tid, PPME_SOCKET_SEND_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_SOCKET_SEND_X, + 2, + res, + scap_const_sized_buffer{data, size}), + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SEND_X, + 5, + res, + scap_const_sized_buffer{data, size}, + fd, + size, + scap_const_sized_buffer{nullptr, 0})); +} + +//////////////////////////// +// SENDTO +//////////////////////////// + +TEST_F(convert_event_test, PPME_SOCKET_SENDTO_E_store) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t fd = 25; + uint32_t size = 5; + constexpr char tuple[] = "tuple"; + auto evt = create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_E, + 3, + fd, + size, + scap_const_sized_buffer{tuple, sizeof(tuple)}); + assert_single_conversion_skip(evt); + assert_event_storage_presence(evt); +} + +TEST_F(convert_event_test, PPME_SOCKET_SENDTO_X_to_5_params_no_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + constexpr char data[] = "hello"; + constexpr int32_t data_size = sizeof(data); + + // Defaulted + int64_t fd = 0; + uint32_t size = 0; + + assert_single_conversion_success( + conversion_result::CONVERSION_COMPLETED, + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_X, + 2, + res, + scap_const_sized_buffer{data, data_size}), + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_X, + 5, + res, + scap_const_sized_buffer{data, data_size}, + fd, + size, + scap_const_sized_buffer{nullptr, 0})); +} + +TEST_F(convert_event_test, PPME_SOCKET_SENDTO_X_to_5_params_with_enter) { + uint64_t ts = 12; + int64_t tid = 25; + + int64_t res = 89; + int64_t fd = 25; + constexpr char data[] = "hello"; + constexpr int32_t size = sizeof(data); + char tuple[] = "tuple"; + + // After the first conversion we should have the storage + auto evt = create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_E, + 3, + fd, + size, + scap_const_sized_buffer{tuple, sizeof(tuple)}); + 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_SENDTO_X, + 2, + res, + scap_const_sized_buffer{data, size}), + create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_X, + 5, + res, + scap_const_sized_buffer{data, size}, + fd, + size, + scap_const_sized_buffer{tuple, sizeof(tuple)})); +} diff --git a/test/libsinsp_e2e/udp_client_server.cpp b/test/libsinsp_e2e/udp_client_server.cpp index dc1e4a9586..3196a13aad 100644 --- a/test/libsinsp_e2e/udp_client_server.cpp +++ b/test/libsinsp_e2e/udp_client_server.cpp @@ -647,7 +647,6 @@ TEST_F(sys_call_test, udp_client_server_sendmsg) { std::string dst_port; if(type == PPME_SOCKET_RECVMSG_X) { - std::cout << e->get_param_value_str("tuple") << std::endl; parse_tuple(e->get_param_value_str("tuple"), src_addr, src_port, dst_addr, dst_port); EXPECT_EQ(udps.server_address(), src_addr); @@ -781,15 +780,11 @@ TEST_F(sys_call_test, udp_client_server_fd_name_changed) { bool use_sendmsg = false, recvmsg_twobufs = false, use_connect = false; // This test only needs to count events. We want to - // see 7 events, representing the following: - // - The servers bind()ing their sockets to their server ports. + // see 6 events, representing the following: + // - The first server bind()ing their sockets to its server port. + // - The second server bind()ing their sockets to its server port. // - the udp client sending to the first server. // - the first udp server receiving from the udp client - // - the udp client receiving the echoed response from the first udp server. - // This results in an event, even though this fd has already - // been used between the server and client, because this - // recvfrom sets the client side port as a result of - // the recvfrom(). // - the udp client sending to the second server // - the second udp server receiving from the udp client // @@ -800,7 +795,7 @@ TEST_F(sys_call_test, udp_client_server_fd_name_changed) { // - the udp client receiving the second echo back from the second server. This is because // the client side port was already set from the communication with the first server. - run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 7); + run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 6); } TEST_F(sys_call_test, udp_client_server_connect_fd_name_changed) { @@ -816,7 +811,7 @@ TEST_F(sys_call_test, udp_client_server_connect_fd_name_changed) { TEST_F(sys_call_test, udp_client_server_sendmsg_fd_name_changed) { bool use_sendmsg = true, recvmsg_twobufs = false, use_connect = false; - run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 7); + run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 6); } TEST_F(sys_call_test, udp_client_server_multiple_connect_name_changed) { @@ -883,7 +878,7 @@ TEST_F(sys_call_test, udp_client_server_multiple_connect_name_changed) { TEST_F(sys_call_test, udp_client_server_sendmsg_2buf_fd_name_changed) { bool use_sendmsg = true, recvmsg_twobufs = true, use_connect = false; - run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 7); + run_fd_name_changed_test(use_sendmsg, recvmsg_twobufs, use_connect, m_tid_filter, 6); } TEST_F(sys_call_test, statsd_client_snaplen) { diff --git a/test/libsinsp_e2e/unix_client_server.cpp b/test/libsinsp_e2e/unix_client_server.cpp index 481ea62b48..6d57dc7e73 100644 --- a/test/libsinsp_e2e/unix_client_server.cpp +++ b/test/libsinsp_e2e/unix_client_server.cpp @@ -192,13 +192,12 @@ TEST_F(sys_call_test, unix_client_server) { // // 32bit (and s390x) uses send() and recv(), while 64bit - // uses sendto() and recvfrom() and sets the address to NULL + // uses sendto() and recvfrom(). recvfrom() sets address to NULL. // if(evt->get_type() == PPME_SOCKET_SEND_E || evt->get_type() == PPME_SOCKET_RECV_E || evt->get_type() == PPME_SOCKET_SENDTO_E || evt->get_type() == PPME_SOCKET_RECVFROM_E) { - if(((evt->get_type() == PPME_SOCKET_RECVFROM_X) || - (evt->get_type() == PPME_SOCKET_RECVFROM_X)) && - (evt->get_param_value_str("tuple") != "")) { + if(evt->get_type() == PPME_SOCKET_RECVFROM_E && + evt->get_param_value_str("tuple") != "") { EXPECT_EQ("NULL", evt->get_param_value_str("tuple")); } diff --git a/userspace/libscap/engine/savefile/converter/table.cpp b/userspace/libscap/engine/savefile/converter/table.cpp index a1d25ec768..57b77f2617 100644 --- a/userspace/libscap/engine/savefile/converter/table.cpp +++ b/userspace/libscap/engine/savefile/converter/table.cpp @@ -82,4 +82,19 @@ const std::unordered_map g_conversion_table = { .instrs({{C_INSTR_FROM_ENTER, 0}, {C_INSTR_FROM_ENTER, 1}, {C_INSTR_FROM_ENTER, 2}})}, -}; + /*====================== SEND ======================*/ + {conversion_key{PPME_SOCKET_SEND_E, 2}, conversion_info().action(C_ACTION_STORE)}, + {conversion_key{PPME_SOCKET_SEND_X, 2}, + conversion_info() + .action(C_ACTION_ADD_PARAMS) + .instrs({{C_INSTR_FROM_ENTER, 0}, + {C_INSTR_FROM_ENTER, 1}, + {C_INSTR_FROM_DEFAULT, 0}})}, + /*====================== SENDTO ======================*/ + {conversion_key{PPME_SOCKET_SENDTO_E, 3}, conversion_info().action(C_ACTION_STORE)}, + {conversion_key{PPME_SOCKET_SENDTO_X, 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/scap.h b/userspace/libscap/scap.h index 9550bc2e46..84004458ec 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, 6, 0) +#define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(3, 7, 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 9e388f374f..02e6f1b3bb 100644 --- a/userspace/libscap/scap_event.c +++ b/userspace/libscap/scap_event.c @@ -537,6 +537,8 @@ int get_exit_event_fd_location(ppm_event_code etype) { case PPME_SOCKET_BIND_X: case PPME_SYSCALL_WRITE_X: case PPME_SYSCALL_PWRITE_X: + case PPME_SOCKET_SEND_X: + case PPME_SOCKET_SENDTO_X: location = 2; break; default: diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index f6212bcc04..59ab44b423 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -79,12 +79,6 @@ void sinsp_parser::process_event(sinsp_evt *evt) { // Route the event to the proper function // switch(etype) { - case PPME_SOCKET_SENDTO_E: - if((evt->get_fd_info() == nullptr) && (evt->get_tinfo() != nullptr)) { - infer_sendto_fdinfo(evt); - } - - // FALLTHRU case PPME_SYSCALL_OPEN_E: case PPME_SYSCALL_CREAT_E: case PPME_SYSCALL_OPENAT_E: @@ -2647,19 +2641,21 @@ inline void sinsp_parser::infer_sendto_fdinfo(sinsp_evt *const evt) { return; } - const uint32_t FILE_DESCRIPTOR_PARAM = 0; - const uint32_t SOCKET_TUPLE_PARAM = 2; + const uint32_t FILE_DESCRIPTOR_PARAM = 2; + const uint32_t SOCKET_TUPLE_PARAM = 4; const sinsp_evt_param *parinfo = nullptr; - ASSERT(evt->get_param_info(FILE_DESCRIPTOR_PARAM)->type == PT_FD); - int64_t fd = evt->get_param(FILE_DESCRIPTOR_PARAM)->as(); - - if(fd < 0) { - // Call to sendto() with an invalid file descriptor + int64_t retval = evt->get_syscall_return_value(); + if(retval < 0) { + // Call to sendto() failed so we cannot trust parameters provided by the user. return; } + ASSERT(evt->get_param_info(FILE_DESCRIPTOR_PARAM)->type == PT_FD); + int64_t fd = evt->get_param(FILE_DESCRIPTOR_PARAM)->as(); + ASSERT(fd >= 0); + parinfo = evt->get_param(SOCKET_TUPLE_PARAM); const char addr_family = *((char *)parinfo->m_val); @@ -3675,21 +3671,24 @@ void sinsp_parser::parse_rw_exit(sinsp_evt *evt) { return; } - // - // Extract the return value - // - retval = evt->get_syscall_return_value(); + if((etype == PPME_SOCKET_SEND_X || etype == PPME_SOCKET_SENDTO_X) && + evt->get_fd_info() == nullptr && evt->get_tinfo() != nullptr) { + infer_sendto_fdinfo(evt); + } if(evt->get_fd_info() == NULL) { return; } + // + // Extract the return value + // + retval = evt->get_syscall_return_value(); + // // If the operation was successful, validate that the fd exists // if(retval >= 0) { - uint16_t etype = evt->get_type(); - if(evt->get_fd_info()->m_type == SCAP_FD_IPV4_SOCK || evt->get_fd_info()->m_type == SCAP_FD_IPV6_SOCK) { evt->get_fd_info()->set_socket_connected(); @@ -3831,32 +3830,30 @@ void sinsp_parser::parse_rw_exit(sinsp_evt *evt) { } else { uint32_t datalen; - int32_t tupleparam = -1; - if(etype == PPME_SOCKET_SENDTO_X || etype == PPME_SOCKET_SENDMSG_X) { - tupleparam = 2; - } else if(etype == PPME_SOCKET_SENDMMSG_X) { - tupleparam = 4; - } - - if(tupleparam != -1 && + if((etype == PPME_SOCKET_SEND_X || etype == PPME_SOCKET_SENDTO_X || + etype == PPME_SOCKET_SENDMSG_X || etype == PPME_SOCKET_SENDMMSG_X) && (evt->get_fd_info()->m_name.length() == 0 || !evt->get_fd_info()->is_tcp_socket())) { // - // sendto contains tuple info in the enter event. + // send, sendto and sendmmsg contain tuple info in the exit event while sendmsg + // contains them into enter event. // If the fd still doesn't contain tuple info (because the socket is a datagram one // or because some event was lost), add it here. // - if(etype == PPME_SOCKET_SENDMMSG_X) { - // sendmmsg has the tuple as part of the exit event, so - // we trick the parser to read it from this event. - enter_evt = evt; - } else if(!retrieve_enter_event(enter_evt, evt)) { - return; + sinsp_evt *src_evt; + int32_t tupleparam = -1; + if(etype == PPME_SOCKET_SENDMSG_X) { + if(!retrieve_enter_event(enter_evt, evt)) { + return; + } + src_evt = enter_evt; + tupleparam = 2; + } else { // PPME_SOCKET_SEND_X, PPME_SOCKET_SENDTO_X or PPME_SOCKET_SENDMMSG_X + src_evt = evt; + tupleparam = 4; } - if(update_fd(evt, enter_evt->get_param(tupleparam))) { - const char *parstr; - + if(update_fd(evt, src_evt->get_param(tupleparam))) { scap_fd_type fdtype = evt->get_fd_info()->m_type; if(fdtype == SCAP_FD_IPV4_SOCK || fdtype == SCAP_FD_IPV6_SOCK) { @@ -3880,10 +3877,11 @@ void sinsp_parser::parse_rw_exit(sinsp_evt *evt) { evt->get_fd_info()->m_name = &evt->get_paramstr_storage()[0]; } else { + const char *parstr; evt->get_fd_info()->m_name = - enter_evt->get_param_as_str(tupleparam, - &parstr, - sinsp_evt::PF_SIMPLE); + src_evt->get_param_as_str(tupleparam, + &parstr, + sinsp_evt::PF_SIMPLE); } } } diff --git a/userspace/libsinsp/test/parsers/parse_send.cpp b/userspace/libsinsp/test/parsers/parse_send.cpp new file mode 100644 index 0000000000..1652128815 --- /dev/null +++ b/userspace/libsinsp/test/parsers/parse_send.cpp @@ -0,0 +1,69 @@ + +// 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 + +// Compile out this test if test_utils helpers are not defined. +#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(__APPLE__) +TEST_F(sinsp_with_test_input, SEND_success) { + add_default_init_thread(); + open_inspector(); + + int64_t return_value = 55; + const std::string data{"hello"}; + uint32_t data_buff_size = data.size(); + int64_t fd = 25; + sockaddr_in client_sockaddr = + test_utils::fill_sockaddr_in(DEFAULT_CLIENT_PORT, DEFAULT_IPV4_CLIENT_STRING); + sockaddr_in server_sockaddr = + test_utils::fill_sockaddr_in(DEFAULT_SERVER_PORT, DEFAULT_IPV4_SERVER_STRING); + const std::vector tuple = + test_utils::pack_socktuple(reinterpret_cast(&client_sockaddr), + reinterpret_cast(&server_sockaddr)); + const auto evt = add_event_advance_ts(increasing_ts(), + INIT_TID, + PPME_SOCKET_SEND_X, + 5, + return_value, + scap_const_sized_buffer{data.c_str(), data_buff_size}, + fd, + data_buff_size, + scap_const_sized_buffer{tuple.data(), tuple.size()}); + + // Check that the returned value is as expected. + ASSERT_EQ(evt->get_param_by_name("res")->as(), return_value); + + // Check that `get_param_value_str` returns the correct sent data. + ASSERT_EQ(evt->get_param_value_str("data"), data); + + // Check that `get_fd_info()->m_fd` returns the correct socket fd. + ASSERT_EQ(evt->get_param_by_name("fd")->as(), fd); + + // Check that the data size is as expected. + ASSERT_EQ(evt->get_param_by_name("size")->as(), data_buff_size); + + // Check that fd info associated with the event are as expected. + auto fdinfo = evt->get_fd_info(); + ASSERT_TRUE(fdinfo); + ASSERT_EQ(fdinfo->m_name, DEFAULT_IPV4_FDNAME); + + // Check that fd info associated with the thread are as expected. + auto init_tinfo = m_inspector.get_thread_ref(INIT_TID, false).get(); + ASSERT_TRUE(init_tinfo); + fdinfo = init_tinfo->get_fd(fd); + ASSERT_TRUE(fdinfo); + ASSERT_EQ(fdinfo->m_name, DEFAULT_IPV4_FDNAME); +} +#endif diff --git a/userspace/libsinsp/test/parsers/parse_sendto.cpp b/userspace/libsinsp/test/parsers/parse_sendto.cpp new file mode 100644 index 0000000000..520818e4e3 --- /dev/null +++ b/userspace/libsinsp/test/parsers/parse_sendto.cpp @@ -0,0 +1,69 @@ + +// 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 + +// Compile out this test if test_utils helpers are not defined. +#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(__APPLE__) +TEST_F(sinsp_with_test_input, SENDTO_success) { + add_default_init_thread(); + open_inspector(); + + int64_t return_value = 55; + const std::string data{"hello"}; + uint32_t data_buff_size = data.size(); + int64_t fd = 25; + sockaddr_in client_sockaddr = + test_utils::fill_sockaddr_in(DEFAULT_CLIENT_PORT, DEFAULT_IPV4_CLIENT_STRING); + sockaddr_in server_sockaddr = + test_utils::fill_sockaddr_in(DEFAULT_SERVER_PORT, DEFAULT_IPV4_SERVER_STRING); + const std::vector tuple = + test_utils::pack_socktuple(reinterpret_cast(&client_sockaddr), + reinterpret_cast(&server_sockaddr)); + const auto evt = add_event_advance_ts(increasing_ts(), + INIT_TID, + PPME_SOCKET_SENDTO_X, + 5, + return_value, + scap_const_sized_buffer{data.c_str(), data_buff_size}, + fd, + data_buff_size, + scap_const_sized_buffer{tuple.data(), tuple.size()}); + + // Check that the returned value is as expected. + ASSERT_EQ(evt->get_param_by_name("res")->as(), return_value); + + // Check that `get_param_value_str` returns the correct sent data. + ASSERT_EQ(evt->get_param_value_str("data"), data); + + // Check that `get_fd_info()->m_fd` returns the correct socket fd. + ASSERT_EQ(evt->get_param_by_name("fd")->as(), fd); + + // Check that the data size is as expected. + ASSERT_EQ(evt->get_param_by_name("size")->as(), data_buff_size); + + // Check that fd info associated with the event are as expected. + auto fdinfo = evt->get_fd_info(); + ASSERT_TRUE(fdinfo); + ASSERT_EQ(fdinfo->m_name, DEFAULT_IPV4_FDNAME); + + // Check that fd info associated with the thread are as expected. + auto init_tinfo = m_inspector.get_thread_ref(INIT_TID, false).get(); + ASSERT_TRUE(init_tinfo); + fdinfo = init_tinfo->get_fd(fd); + ASSERT_TRUE(fdinfo); + ASSERT_EQ(fdinfo->m_name, DEFAULT_IPV4_FDNAME); +} +#endif diff --git a/userspace/libsinsp/test/scap_files/converter_tests.cpp b/userspace/libsinsp/test/scap_files/converter_tests.cpp index cd491490e1..858c4ca35f 100644 --- a/userspace/libsinsp/test/scap_files/converter_tests.cpp +++ b/userspace/libsinsp/test/scap_files/converter_tests.cpp @@ -21,7 +21,7 @@ limitations under the License. // 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"` +// `sudo sysdig -r <> -d "evt.num=<>" -p "ts=%evt.rawtime, tid=%thread.tid, args=%evt.args"` //////////////////////////// // READ @@ -245,3 +245,58 @@ TEST_F(scap_file_test, write_x_check_final_converted_event) { //////////////////////////// // We don't have scap-files with PWRITE events. Add it if we face a failure. + +//////////////////////////// +// SEND +//////////////////////////// + +// We don't have scap-files with SEND events. Add it if we face a failure. + +//////////////////////////// +// SENDTO +//////////////////////////// + +TEST_F(scap_file_test, sendto_e_same_number_of_events) { + open_filename("kexec_arm64.scap"); + assert_num_event_type(PPME_SOCKET_SENDTO_E, 162); +} + +TEST_F(scap_file_test, sendto_x_same_number_of_events) { + open_filename("kexec_arm64.scap"); + assert_num_event_type(PPME_SOCKET_SENDTO_X, 162); +} + +TEST_F(scap_file_test, sendto_x_check_final_converted_event) { + open_filename("kexec_arm64.scap"); + + // Inside the scap-file the event `857230` is the following: + // - type=PPME_SOCKET_SENDTO_X + // - ts=1687966733172651252 + // - tid=114093 + // - args=res=17 data="\x11\x0\x0\x0\x16\x0\x1\x3\x1\x0\x0\x0\x0\x0\x0\x0" + // + // And its corresponding enter event `857231` is the following: + // - type=PPME_SOCKET_SENDTO_E + // - ts=1687966733172634128 + // - tid=114093 + // - args=fd=22() size=17 tuple=NULL + // + // Let's see the new PPME_SOCKET_SENDTO_X event! + + uint64_t ts = 1687966733172651252; + int64_t tid = 114093; + int64_t res = 17; + + constexpr char data[] = "\x11\x0\x0\x0\x16\x0\x1\x3\x1\x0\x0\x0\x0\x0\x0\x0"; + constexpr uint32_t size = sizeof(data); + int64_t fd = 22; + assert_event_presence(create_safe_scap_event(ts, + tid, + PPME_SOCKET_SENDTO_X, + 5, + res, + scap_const_sized_buffer{data, size}, + fd, + size, + scap_const_sized_buffer{nullptr, 0})); +} From 60d75c5a6b412788eebec20301a6a30b95636af2 Mon Sep 17 00:00:00 2001 From: Leonardo Di Giovanna Date: Thu, 2 Jan 2025 18:34:58 +0100 Subject: [PATCH 2/2] test(sinsp/scap_files): add accept events conversion tests Signed-off-by: Leonardo Di Giovanna --- userspace/libsinsp/parsers.cpp | 4 +- .../test/scap_files/converter_tests.cpp | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index 59ab44b423..87e33d375a 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -3672,9 +3672,9 @@ void sinsp_parser::parse_rw_exit(sinsp_evt *evt) { } if((etype == PPME_SOCKET_SEND_X || etype == PPME_SOCKET_SENDTO_X) && - evt->get_fd_info() == nullptr && evt->get_tinfo() != nullptr) { + evt->get_fd_info() == nullptr && evt->get_tinfo() != nullptr) { infer_sendto_fdinfo(evt); - } + } if(evt->get_fd_info() == NULL) { return; diff --git a/userspace/libsinsp/test/scap_files/converter_tests.cpp b/userspace/libsinsp/test/scap_files/converter_tests.cpp index 858c4ca35f..ab651df6eb 100644 --- a/userspace/libsinsp/test/scap_files/converter_tests.cpp +++ b/userspace/libsinsp/test/scap_files/converter_tests.cpp @@ -17,6 +17,7 @@ limitations under the License. */ +#include #include // Use `sudo sysdig -r -S -q` to check the number of events in the scap file. @@ -200,6 +201,64 @@ TEST_F(scap_file_test, listen_x_check_final_converted_event) { create_safe_scap_event(ts, tid, PPME_SOCKET_LISTEN_X, 3, res, fd, backlog)); } +//////////////////////////// +// ACCEPT +//////////////////////////// + +TEST_F(scap_file_test, accept_e_same_number_of_events) { + open_filename("scap_2013.scap"); + assert_num_event_type(PPME_SOCKET_ACCEPT_E, 3817); +} + +TEST_F(scap_file_test, accept_x_same_number_of_events) { + open_filename("scap_2013.scap"); + assert_num_event_type(PPME_SOCKET_ACCEPT_5_X, 3816); +} + +// Compile out this test if test_utils helpers are not defined. +#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(__APPLE__) +TEST_F(scap_file_test, accept_x_check_final_converted_event) { + open_filename("scap_2013.scap"); + + // Inside the scap-file the event `519217` is the following: + // - type=PPME_SOCKET_ACCEPT_X, + // - ts=1380933088302022447 + // - tid=43625 + // - args=fd=13(<4t>127.0.0.1:38873->127.0.0.1:80) tuple=127.0.0.1:38873->127.0.0.1:80 + // queuepct=37 queuepct=37 + // + // And its corresponding enter event `519211` is the following: + // - type=PPME_SOCKET_ACCEPT_E + // - ts=1380933088302013474 + // - tid=43625 + // - args= + // + // Let's see the new PPME_SOCKET_ACCEPT_5_X event! + + uint64_t ts = 1380933088302022447; + int64_t tid = 43625; + int64_t fd = 13; + sockaddr_in client_sockaddr = test_utils::fill_sockaddr_in(38873, "127.0.0.1"); + sockaddr_in server_sockaddr = test_utils::fill_sockaddr_in(80, "127.0.0.1"); + const std::vector tuple = + test_utils::pack_socktuple(reinterpret_cast(&client_sockaddr), + reinterpret_cast(&server_sockaddr)); + int32_t queuepct = 37; + int32_t queuelen = 0; + int32_t queuemax = 0; + assert_event_presence( + create_safe_scap_event(ts, + tid, + PPME_SOCKET_ACCEPT_5_X, + 5, + fd, + scap_const_sized_buffer{tuple.data(), tuple.size()}, + queuepct, + queuelen, + queuemax)); +} +#endif + //////////////////////////// // WRITE ////////////////////////////