diff --git a/driver/modern_bpf/helpers/base/maps_getters.h b/driver/modern_bpf/helpers/base/maps_getters.h index d38fef7edeb..9802fd78db2 100644 --- a/driver/modern_bpf/helpers/base/maps_getters.h +++ b/driver/modern_bpf/helpers/base/maps_getters.h @@ -62,6 +62,21 @@ static __always_inline uint16_t maps__get_statsd_port() return g_settings.statsd_port; } +static __always_inline uint16_t maps__get_scap_pid() +{ + return g_settings.scap_pid; +} + +static __always_inline void* maps__get_socket_file_ops() +{ + return g_settings.socket_file_ops; +} + +static __always_inline void maps__set_socket_file_ops(void* value) +{ + g_settings.socket_file_ops = value; +} + /*=============================== SETTINGS ===========================*/ /*=============================== KERNEL CONFIGS ===========================*/ diff --git a/driver/modern_bpf/helpers/extract/extract_from_kernel.h b/driver/modern_bpf/helpers/extract/extract_from_kernel.h index 456b5ba43b1..2d385b25d0a 100644 --- a/driver/modern_bpf/helpers/extract/extract_from_kernel.h +++ b/driver/modern_bpf/helpers/extract/extract_from_kernel.h @@ -244,8 +244,24 @@ static __always_inline struct file *extract__file_struct_from_fd(int32_t file_de if(file_descriptor >= 0) { struct file **fds = NULL; + struct fdtable *fdt = NULL; + int max_fds = 0; + struct task_struct *task = get_current_task(); - BPF_CORE_READ_INTO(&fds, task, files, fdt, fd); + BPF_CORE_READ_INTO(&fdt, task, files, fdt); + if(unlikely(fdt == NULL)) + { + return NULL; + } + + // Try a bound check to avoid reading out of bounds. + BPF_CORE_READ_INTO(&max_fds, fdt, max_fds); + if(unlikely(file_descriptor >= max_fds)) + { + return NULL; + } + + BPF_CORE_READ_INTO(&fds, fdt, fd); if(fds != NULL) { bpf_probe_read_kernel(&f, sizeof(struct file *), &fds[file_descriptor]); @@ -1127,3 +1143,23 @@ static __always_inline bool extract__exe_writable(struct task_struct *task, stru return false; } + +/** + * @brief Return a socket pointer from a file pointer. + * @param file pointer to the file struct. + */ +static __always_inline struct socket* get_sock_from_file(struct file *file) +{ + if(file == NULL) + { + return NULL; + } + + struct file_operations *fop = (struct file_operations *)BPF_CORE_READ(file, f_op); + if(fop != maps__get_socket_file_ops()) + { + // We are not a socket. + return NULL; + } + return (struct socket*)BPF_CORE_READ(file, private_data); +} diff --git a/driver/modern_bpf/helpers/store/auxmap_store_params.h b/driver/modern_bpf/helpers/store/auxmap_store_params.h index 17e682f430e..d8a1942695b 100644 --- a/driver/modern_bpf/helpers/store/auxmap_store_params.h +++ b/driver/modern_bpf/helpers/store/auxmap_store_params.h @@ -664,7 +664,12 @@ static __always_inline void auxmap__store_socktuple_param(struct auxiliary_map * /* Get the socket family directly from the socket */ uint16_t socket_family = 0; struct file *file = extract__file_struct_from_fd(socket_fd); - struct socket *socket = BPF_CORE_READ(file, private_data); + struct socket *socket = get_sock_from_file(file); + if(socket == NULL) + { + auxmap__store_empty_param(auxmap); + return; + } struct sock *sk = BPF_CORE_READ(socket, sk); BPF_CORE_READ_INTO(&socket_family, sk, __sk_common.skc_family); @@ -1437,12 +1442,12 @@ static __always_inline void apply_dynamic_snaplen(struct pt_regs *regs, uint16_t } struct file *file = extract__file_struct_from_fd(socket_fd); - struct socket *socket = BPF_CORE_READ(file, private_data); - struct sock *sk = BPF_CORE_READ(socket, sk); - if(!sk) + struct socket *socket = get_sock_from_file(file); + if(socket == NULL) { return; } + struct sock *sk = BPF_CORE_READ(socket, sk); uint16_t port_local = 0; uint16_t port_remote = 0; 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 ee7fc5a56b4..7a775e0764c 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 @@ -86,15 +86,17 @@ int BPF_PROG(accept_x, * new one. */ int32_t sockfd = (int32_t)args[0]; - struct file *file = NULL; - file = extract__file_struct_from_fd(sockfd); - struct socket *socket = BPF_CORE_READ(file, private_data); - struct sock *sk = BPF_CORE_READ(socket, sk); - BPF_CORE_READ_INTO(&queuelen, sk, sk_ack_backlog); - BPF_CORE_READ_INTO(&queuemax, sk, sk_max_ack_backlog); - if(queuelen && queuemax) + struct file *file = extract__file_struct_from_fd(sockfd); + struct socket *socket = get_sock_from_file(file); + if(socket != NULL) { - queuepct = (uint8_t)((uint64_t)queuelen * 100 / queuemax); + struct sock *sk = BPF_CORE_READ(socket, sk); + BPF_CORE_READ_INTO(&queuelen, sk, sk_ack_backlog); + BPF_CORE_READ_INTO(&queuemax, sk, sk_max_ack_backlog); + if(queuelen && queuemax) + { + queuepct = (uint8_t)((uint64_t)queuelen * 100 / queuemax); + } } } else 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 67003794dae..8045cbfe74e 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 @@ -90,15 +90,17 @@ int BPF_PROG(accept4_x, * new one. */ int32_t sockfd = (int32_t)args[0]; - struct file *file = NULL; - file = extract__file_struct_from_fd(sockfd); - struct socket *socket = BPF_CORE_READ(file, private_data); - struct sock *sk = BPF_CORE_READ(socket, sk); - BPF_CORE_READ_INTO(&queuelen, sk, sk_ack_backlog); - BPF_CORE_READ_INTO(&queuemax, sk, sk_max_ack_backlog); - if(queuelen && queuemax) + struct file *file = extract__file_struct_from_fd(sockfd); + struct socket *socket = get_sock_from_file(file); + if(socket != NULL) { - queuepct = (uint8_t)((uint64_t)queuelen * 100 / queuemax); + struct sock *sk = BPF_CORE_READ(socket, sk); + BPF_CORE_READ_INTO(&queuelen, sk, sk_ack_backlog); + BPF_CORE_READ_INTO(&queuemax, sk, sk_max_ack_backlog); + if(queuelen && queuemax) + { + queuepct = (uint8_t)((uint64_t)queuelen * 100 / queuemax); + } } } else diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socket.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socket.bpf.c index 1e890cb0999..476dffb0c29 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socket.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socket.bpf.c @@ -73,6 +73,23 @@ int BPF_PROG(socket_x, /* Parameter 1: res (type: PT_ERRNO)*/ ringbuf__store_s64(&ringbuf, ret); + /* Just called once by our scap process */ + if(ret >= 0 && maps__get_socket_file_ops() == NULL) + { + struct task_struct *task = get_current_task(); + pid_t tgid = extract__task_xid_nr(task, PIDTYPE_TGID); + /* it means that scap is performing the calibration */ + if(tgid == maps__get_scap_pid()) + { + struct file *f = extract__file_struct_from_fd(ret); + if(f) + { + struct file_operations *f_op = (struct file_operations *)BPF_CORE_READ(f, f_op); + maps__set_socket_file_ops((void*)f_op); + } + } + } + /*=============================== COLLECT PARAMETERS ===========================*/ ringbuf__submit_event(&ringbuf); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socketpair.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socketpair.bpf.c index bf270f0c5b7..1c418f02dc2 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socketpair.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/socketpair.bpf.c @@ -91,10 +91,13 @@ int BPF_PROG(socketpair_x, /* Get source and peer. */ struct file *file = extract__file_struct_from_fd((int32_t)fds[0]); - struct socket *socket = BPF_CORE_READ(file, private_data); - BPF_CORE_READ_INTO(&source, socket, sk); - struct unix_sock *us = (struct unix_sock *)source; - BPF_CORE_READ_INTO(&peer, us, peer); + struct socket *socket = get_sock_from_file(file); + if(socket != NULL) + { + BPF_CORE_READ_INTO(&source, socket, sk); + struct unix_sock *us = (struct unix_sock *)source; + BPF_CORE_READ_INTO(&peer, us, peer); + } } /* Parameter 2: fd1 (type: PT_FD) */ diff --git a/driver/modern_bpf/shared_definitions/struct_definitions.h b/driver/modern_bpf/shared_definitions/struct_definitions.h index a4a0d009d58..085963632d8 100644 --- a/driver/modern_bpf/shared_definitions/struct_definitions.h +++ b/driver/modern_bpf/shared_definitions/struct_definitions.h @@ -33,6 +33,8 @@ struct capture_settings uint16_t fullcapture_port_range_start; /* first interesting port */ uint16_t fullcapture_port_range_end; /* last interesting port */ uint16_t statsd_port; /* port for statsd metrics */ + int32_t scap_pid; /* pid of the scap process */ + void *socket_file_ops; /* pointer to the file_operations struct of the socket file */ }; /** diff --git a/userspace/libpman/include/libpman.h b/userspace/libpman/include/libpman.h index fa279c50031..745c9b89d5b 100644 --- a/userspace/libpman/include/libpman.h +++ b/userspace/libpman/include/libpman.h @@ -373,6 +373,27 @@ extern "C" */ void pman_set_statsd_port(uint16_t statsd_port); + /** + * @brief Set scap pid for socket calibration logic. + * + * @param scap_pid port number. + */ + void pman_set_scap_pid(int32_t scap_pid); + + /** + * @brief Get the pointer to the file_operations struct of the socket file. + * + * @param socket_file_ops pointer to the file_operations struct of the socket file. + */ + void* pman_get_socket_file_ops(); + + /** + * @brief Set the pointer to the file_operations struct of the socket file. + * + * @param socket_file_ops pointer to the file_operations struct of the socket file. + */ + void pman_set_socket_file_ops(void* socket_file_ops); + /** * @brief Get API version to check it a runtime. * diff --git a/userspace/libpman/src/maps.c b/userspace/libpman/src/maps.c index 861975f344e..46a0fb72505 100644 --- a/userspace/libpman/src/maps.c +++ b/userspace/libpman/src/maps.c @@ -105,6 +105,21 @@ void pman_set_statsd_port(uint16_t statsd_port) g_state.skel->bss->g_settings.statsd_port = statsd_port; } +void pman_set_scap_pid(int32_t scap_pid) +{ + g_state.skel->bss->g_settings.scap_pid = scap_pid; +} + +void* pman_get_socket_file_ops() +{ + return g_state.skel->bss->g_settings.socket_file_ops; +} + +void pman_set_socket_file_ops(void* socket_file_ops) +{ + g_state.skel->bss->g_settings.socket_file_ops = socket_file_ops; +} + void pman_mark_single_64bit_syscall(int intersting_syscall_id, bool interesting) { g_state.skel->bss->g_64bit_interesting_syscalls_table[intersting_syscall_id] = interesting; diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c index 50826401e53..6c30fce71d2 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c @@ -18,6 +18,7 @@ limitations under the License. #include #include #include +#include #define SCAP_HANDLE_T struct modern_bpf_engine #include @@ -30,6 +31,7 @@ limitations under the License. #include #include #include +#include static struct modern_bpf_engine* scap_modern_bpf__alloc_engine(scap_t* main_handle, char* lasterr_ptr) { @@ -164,6 +166,31 @@ int32_t scap_modern_bpf__stop_capture(struct scap_engine_handle engine) return pman_enforce_sc_set(NULL); } +static int32_t calibrate_socket_file_ops(struct scap_engine_handle engine) +{ + /* We just need to enable the socket syscall for the socket calibration */ + engine.m_handle->curr_sc_set.ppm_sc[PPM_SC_SOCKET] = 1; + if(scap_modern_bpf__start_capture(engine) != SCAP_SUCCESS) + { + return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to start the capture for the socket calibration"); + } + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if(fd == -1) + { + return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to create a socket for the calibration"); + } + close(fd); + + /* We need to stop the capture */ + if(scap_modern_bpf__stop_capture(engine) != SCAP_SUCCESS) + { + return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to stop the capture after the calibration"); + } + + return SCAP_SUCCESS; +} + int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) { int ret = 0; @@ -211,8 +238,11 @@ int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) return ret; } - /* Store interesting sc codes */ - memcpy(&engine.m_handle->curr_sc_set, &oargs->ppm_sc_of_interest, sizeof(interesting_ppm_sc_set)); + /* Set the scap_pid for the socket calibration */ + pman_set_scap_pid(getpid()); + + /* Set the initial value to NULL */ + pman_set_socket_file_ops(NULL); /* Set the boot time */ uint64_t boot_time = 0; @@ -222,6 +252,23 @@ int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) } pman_set_boot_time(boot_time); + /* Calibrate the socket at init time */ + int rc = calibrate_socket_file_ops(engine); + if(rc != SCAP_SUCCESS) + { + return rc; + } + + /* If the socket is calibrated this should be not NULL */ + if(pman_get_socket_file_ops() == NULL) + { + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "unable to calibrate the socket in ebpf."); + return SCAP_FAILURE; + } + + /* Store interesting sc codes */ + memcpy(&engine.m_handle->curr_sc_set, &oargs->ppm_sc_of_interest, sizeof(interesting_ppm_sc_set)); + engine.m_handle->m_api_version = pman_get_probe_api_ver(); engine.m_handle->m_schema_version = pman_get_probe_schema_ver();