diff --git a/driver/main.c b/driver/main.c index a5d87cf782..0cadd0ec8b 100644 --- a/driver/main.c +++ b/driver/main.c @@ -919,6 +919,12 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if(put_user(PPM_SCHEMA_CURRENT_VERSION, out)) ret = -EINVAL; goto cleanup_ioctl_nolock; + } else if (cmd == PPM_IOCTL_GET_TPMASK) { + u32 __user *out = (u32 __user *) arg; + ret = 0; + if(put_user(g_tracepoints_attached, out)) + ret = -EINVAL; + goto cleanup_ioctl_nolock; } mutex_lock(&g_consumer_mutex); diff --git a/driver/ppm_events_public.h b/driver/ppm_events_public.h index 5fb5340215..8cda2d5b18 100644 --- a/driver/ppm_events_public.h +++ b/driver/ppm_events_public.h @@ -1741,6 +1741,7 @@ struct ppm_evt_hdr { #define PPM_IOCTL_GET_API_VERSION _IO(PPM_IOCTL_MAGIC, 24) #define PPM_IOCTL_GET_SCHEMA_VERSION _IO(PPM_IOCTL_MAGIC, 25) #define PPM_IOCTL_MANAGE_TP _IO(PPM_IOCTL_MAGIC, 26) +#define PPM_IOCTL_GET_TPMASK _IO(PPM_IOCTL_MAGIC, 27) #endif // CYGWING_AGENT extern const struct ppm_name_value socket_families[]; diff --git a/userspace/libscap/engine/bpf/bpf.h b/userspace/libscap/engine/bpf/bpf.h index 3352991d60..ffea0febce 100644 --- a/userspace/libscap/engine/bpf/bpf.h +++ b/userspace/libscap/engine/bpf/bpf.h @@ -31,16 +31,22 @@ limitations under the License. #define BPF_MAPS_MAX 32 +struct bpf_prog { + int fd; + int efd; + char name[NAME_MAX]; +}; + struct bpf_engine { struct scap_device_set m_dev_set; size_t m_ncpus; char* m_lasterr; - int m_bpf_prog_fds[BPF_PROGS_MAX]; + struct bpf_prog m_bpf_progs[BPF_PROGS_MAX]; int m_bpf_prog_cnt; - int m_bpf_event_fd[BPF_PROGS_MAX]; int m_bpf_map_fds[BPF_MAPS_MAX]; int m_bpf_prog_array_map_idx; + char m_filepath[PATH_MAX]; }; #define SCAP_HANDLE_T struct bpf_engine diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 29fedda9d9..c95c310fb1 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -494,6 +494,7 @@ static int32_t load_tracepoint(struct bpf_engine* handle, const char *event, str return SCAP_FAILURE; } + const char *full_event = event; if(memcmp(event, "raw_tracepoint/", sizeof("raw_tracepoint/") - 1) == 0) { raw_tp = true; @@ -547,7 +548,9 @@ static int32_t load_tracepoint(struct bpf_engine* handle, const char *event, str return SCAP_FAILURE; } - handle->m_bpf_prog_fds[handle->m_bpf_prog_cnt++] = fd; + handle->m_bpf_progs[handle->m_bpf_prog_cnt].fd = fd; + strncpy(handle->m_bpf_progs[handle->m_bpf_prog_cnt].name, full_event, NAME_MAX); + handle->m_bpf_prog_cnt++; if(memcmp(event, "filler/", sizeof("filler/") - 1) == 0) { @@ -645,7 +648,7 @@ static int32_t load_tracepoint(struct bpf_engine* handle, const char *event, str // by this point m_bpf_prog_cnt has already been checked for // being inbounds, so this is safe. - handle->m_bpf_event_fd[handle->m_bpf_prog_cnt - 1] = efd; + handle->m_bpf_progs[handle->m_bpf_prog_cnt - 1].efd = efd; return SCAP_SUCCESS; } @@ -663,7 +666,7 @@ static bool is_tp_enabled(interesting_tp_set *tp_of_interest, const char *shname } static int32_t load_bpf_file( - struct bpf_engine *handle, const char *path, + struct bpf_engine *handle, uint64_t *api_version_p, uint64_t *schema_version_p, scap_open_args *oargs) @@ -697,11 +700,11 @@ static int32_t load_bpf_file( return SCAP_FAILURE; } - int program_fd = open(path, O_RDONLY, 0); + int program_fd = open(handle->m_filepath, O_RDONLY, 0); if(program_fd < 0) { char buf[SCAP_LASTERR_SIZE]; - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't open BPF probe '%s': %s", path, scap_strerror_r(buf, errno)); + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't open BPF probe '%s': %s", handle->m_filepath, scap_strerror_r(buf, errno)); return SCAP_FAILURE; } @@ -826,9 +829,21 @@ static int32_t load_bpf_file( { if(is_tp_enabled(&(oargs->tp_of_interest), shname)) { - if(load_tracepoint(handle, shname, data->d_buf, data->d_size) != SCAP_SUCCESS) + bool already_attached = false; + for (int i = 0; i < handle->m_bpf_prog_cnt && !already_attached; i++) + { + if (strcmp(handle->m_bpf_progs[i].name, shname) == 0) + { + already_attached = true; + } + } + + if (!already_attached) { - goto cleanup; + if(load_tracepoint(handle, shname, data->d_buf, data->d_size) != SCAP_SUCCESS) + { + goto cleanup; + } } } } @@ -1257,6 +1272,19 @@ int32_t scap_bpf_enable_tracers_capture(struct scap_engine_handle engine) return SCAP_SUCCESS; } +static void close_prog(struct bpf_prog *prog) +{ + if(prog->efd > 0) + { + close(prog->efd); + } + if(prog->fd > 0) + { + close(prog->fd); + } + memset(prog, 0, sizeof(*prog)); +} + int32_t scap_bpf_close(struct scap_engine_handle engine) { struct bpf_engine *handle = engine.m_handle; @@ -1266,22 +1294,9 @@ int32_t scap_bpf_close(struct scap_engine_handle engine) devset_free(devset); - for(j = 0; j < sizeof(handle->m_bpf_event_fd) / sizeof(handle->m_bpf_event_fd[0]); ++j) + for(j = 0; j < sizeof(handle->m_bpf_progs) / sizeof(handle->m_bpf_progs[0]); ++j) { - if(handle->m_bpf_event_fd[j] > 0) - { - close(handle->m_bpf_event_fd[j]); - handle->m_bpf_event_fd[j] = 0; - } - } - - for(j = 0; j < sizeof(handle->m_bpf_prog_fds) / sizeof(handle->m_bpf_prog_fds[0]); ++j) - { - if(handle->m_bpf_prog_fds[j] > 0) - { - close(handle->m_bpf_prog_fds[j]); - handle->m_bpf_prog_fds[j] = 0; - } + close_prog(&handle->m_bpf_progs[j]); } for(j = 0; j < sizeof(handle->m_bpf_map_fds) / sizeof(handle->m_bpf_map_fds[0]); ++j) @@ -1422,7 +1437,8 @@ int32_t scap_bpf_load( return SCAP_FAILURE; } - if(load_bpf_file(handle, bpf_probe, api_version_p, schema_version_p, oargs) != SCAP_SUCCESS) + snprintf(handle->m_filepath, PATH_MAX, "%s", bpf_probe); + if(load_bpf_file(handle, api_version_p, schema_version_p, oargs) != SCAP_SUCCESS) { return SCAP_FAILURE; } @@ -1621,13 +1637,64 @@ static int32_t unsupported_config(struct scap_engine_handle engine, const char* return SCAP_FAILURE; } +static int32_t scap_bpf_handle_tp_mask(struct scap_engine_handle engine, uint32_t op, uint32_t tp) +{ + struct bpf_engine *handle = engine.m_handle; + + int prg_idx = -1; + for (int i = 0; i < handle->m_bpf_prog_cnt; i++) + { + const tp_values val = tp_from_name(handle->m_bpf_progs[i].name); + if (val == tp) + { + prg_idx = i; + break; + } + } + + // We want to unload a never loaded tracepoint + if (prg_idx == -1 && op != SCAP_TPMASK_SET) + { + return SCAP_SUCCESS; + } + // We want to load an already loaded tracepoint + if (prg_idx >= 0 && op != SCAP_TPMASK_UNSET) + { + return SCAP_SUCCESS; + } + + if (op == SCAP_TPMASK_UNSET) + { + // Algo: + // Close the event and tracepoint fds, + // reduce number of prog cnt + // move left remaining array elements + // reset last array element + close_prog(&handle->m_bpf_progs[prg_idx]); + handle->m_bpf_prog_cnt--; + size_t byte_size = (handle->m_bpf_prog_cnt - prg_idx) * sizeof(handle->m_bpf_progs[prg_idx]); + if (byte_size > 0) + { + memmove(&handle->m_bpf_progs[prg_idx], &handle->m_bpf_progs[prg_idx + 1], byte_size); + } + memset(&handle->m_bpf_progs[handle->m_bpf_prog_cnt], 0, sizeof(handle->m_bpf_progs[handle->m_bpf_prog_cnt])); + return SCAP_SUCCESS; + } + + uint64_t api_version_p; + uint64_t schema_version_p; + scap_open_args oargs = {0}; + oargs.tp_of_interest.tp[tp] = 1; + return load_bpf_file(handle, &api_version_p, &schema_version_p, &oargs); +} + static int32_t scap_bpf_handle_event_mask(struct scap_engine_handle engine, uint32_t op, uint32_t ppm_sc) { int32_t ret = SCAP_SUCCESS; switch(op) { case SCAP_EVENTMASK_ZERO: - for(int ppm_sc = 0; ppm_sc < PPM_SC_MAX && ret==SCAP_SUCCESS; ppm_sc++) + for(ppm_sc = 0; ppm_sc < PPM_SC_MAX && ret==SCAP_SUCCESS; ppm_sc++) { ret = update_interesting_syscalls_map(engine, SCAP_EVENTMASK_UNSET, ppm_sc); } @@ -1668,6 +1735,8 @@ static int32_t configure(struct scap_engine_handle engine, enum scap_setting set return scap_bpf_set_snaplen(engine, arg1); case SCAP_EVENTMASK: return scap_bpf_handle_event_mask(engine, arg1, arg2); + case SCAP_TPMASK: + return scap_bpf_handle_tp_mask(engine, arg1, arg2); case SCAP_DYNAMIC_SNAPLEN: if(arg1 == 0) { diff --git a/userspace/libscap/engine/kmod/scap_kmod.c b/userspace/libscap/engine/kmod/scap_kmod.c index 07fb940469..ca118637b8 100644 --- a/userspace/libscap/engine/kmod/scap_kmod.c +++ b/userspace/libscap/engine/kmod/scap_kmod.c @@ -124,7 +124,46 @@ static int32_t enforce_into_kmod_buffer_bytes_dim(scap_t *handle, unsigned long } -/// TODO: we need to pass directly the system syscall number not the `ppm_sc` here. +int32_t scap_kmod_handle_tp_mask(struct scap_engine_handle engine, uint32_t op, uint32_t tp) +{ + struct scap_device_set *devset = &engine.m_handle->m_dev_set; + + uint32_t curr_set; + if(ioctl(devset->m_devs[0].m_fd, PPM_IOCTL_GET_TPMASK, &curr_set)) + { + snprintf(engine.m_handle->m_lasterr, SCAP_LASTERR_SIZE, + "%s(%d) failed", + __FUNCTION__, op); + ASSERT(false); + return SCAP_FAILURE; + } + + uint32_t new_set; + if (op == SCAP_TPMASK_SET) + { + new_set = curr_set | (1 << tp); + } + else + { + new_set = curr_set & ~(1 << tp); + } + if(new_set == curr_set) + { + return SCAP_SUCCESS; + } + + if(ioctl(devset->m_devs[0].m_fd, PPM_IOCTL_MANAGE_TP, new_set)) + { + snprintf(engine.m_handle->m_lasterr, SCAP_LASTERR_SIZE, + "%s(%d) failed for tpmask %d", + __FUNCTION__, op, new_set); + ASSERT(false); + return SCAP_FAILURE; + } + return SCAP_SUCCESS; +} + +/// TODO: it would be better to pass directly the system syscall number not the `ppm_sc` here. int32_t scap_kmod_handle_event_mask(struct scap_engine_handle engine, uint32_t op, uint32_t ppm_sc) { struct scap_device_set *devset = &engine.m_handle->m_dev_set; @@ -371,19 +410,10 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs) } /* Set interesting Tracepoints */ - uint32_t tp_of_interest = 0; for (int i = 0; i < TP_VAL_MAX; i++) { - if (oargs->tp_of_interest.tp[i]) - { - tp_of_interest |= (1 << i); - } - } - if(ioctl(devset->m_devs[0].m_fd, PPM_IOCTL_MANAGE_TP, tp_of_interest)) - { - strncpy(handle->m_lasterr, "PPM_IOCTL_MANAGE_TP failed", SCAP_LASTERR_SIZE); - ASSERT(false); - return SCAP_FAILURE; + uint32_t op = oargs->tp_of_interest.tp[i] ? SCAP_TPMASK_SET : SCAP_TPMASK_UNSET; + scap_kmod_handle_tp_mask(engine, op, i); } return SCAP_SUCCESS; @@ -729,6 +759,8 @@ static int32_t configure(struct scap_engine_handle engine, enum scap_setting set return scap_kmod_set_snaplen(engine, arg1); case SCAP_EVENTMASK: return scap_kmod_handle_event_mask(engine, arg1, arg2); + case SCAP_TPMASK: + return scap_kmod_handle_tp_mask(engine, arg1, arg2); case SCAP_DYNAMIC_SNAPLEN: if(arg1 == 0) { diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c index a4a1766484..ca0ce8c98b 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c @@ -29,56 +29,103 @@ limitations under the License. /*=============================== UTILS ===============================*/ -static int32_t attach_interesting_tracepoints(bool* tp_array) +static int32_t update_single_tp_of_interest(int tp, bool interesting) { int ret = SCAP_SUCCESS; - if(tp_array == NULL) - { - return SCAP_FAILURE; - } - - for(int tp = 0; tp < TP_VAL_MAX && ret == SCAP_SUCCESS; tp++) + switch(tp) { - /* If the tracepoint is not interesting, continue */ - if(!tp_array[tp]) + case SYS_ENTER: + if (interesting) { - continue; + ret = pman_attach_syscall_enter_dispatcher(); } - - switch(tp) + else { - case SYS_ENTER: - ret = pman_attach_syscall_enter_dispatcher(); - break; + ret = pman_detach_syscall_enter_dispatcher(); + } + break; - case SYS_EXIT: + case SYS_EXIT: + if (interesting) + { ret = pman_attach_syscall_exit_dispatcher(); - break; - - case SCHED_PROC_EXIT: + } + else + { + ret = pman_detach_syscall_exit_dispatcher(); + } + break; + case SCHED_PROC_EXIT: + if (interesting) + { ret = pman_attach_sched_proc_exit(); - break; + } + else + { + ret = pman_detach_sched_proc_exit(); + } + break; - case SCHED_SWITCH: + case SCHED_SWITCH: + if (interesting) + { ret = pman_attach_sched_switch(); - break; + } + else + { + ret = pman_detach_sched_switch(); + } + break; - case SCHED_PROC_EXEC: #ifdef CAPTURE_SCHED_PROC_EXEC + case SCHED_PROC_EXEC: + if (interesting) + { ret = pman_attach_sched_proc_exec(); + } + else + { + ret = pman_detach_sched_proc_exec(); + } + break; #endif - break; - case SCHED_PROC_FORK: #ifdef CAPTURE_SCHED_PROC_FORK + case SCHED_PROC_FORK: + if (interesting) + { ret = pman_attach_sched_proc_fork(); + } + else + { + ret = pman_detach_sched_proc_fork(); + } + break; #endif - break; - default: - /* Do nothing right now. */ - break; + default: + /* Do nothing right now. */ + break; + } + return ret; +} + +static int32_t attach_interesting_tracepoints(bool* tp_array) +{ + int ret = SCAP_SUCCESS; + if(tp_array == NULL) + { + return SCAP_FAILURE; + } + + for(int tp = 0; tp < TP_VAL_MAX && ret == SCAP_SUCCESS; tp++) + { + /* If the tracepoint is not interesting, continue */ + if(!tp_array[tp]) + { + continue; } + ret = update_single_tp_of_interest(tp, true); } return ret; } @@ -168,6 +215,8 @@ static int32_t scap_modern_bpf__configure(struct scap_engine_handle engine, enum pman_clean_all_64bit_interesting_syscalls(); } return SCAP_SUCCESS; + case SCAP_TPMASK: + return update_single_tp_of_interest(arg2, arg1 == SCAP_TPMASK_SET); case SCAP_DYNAMIC_SNAPLEN: /* Not supported */ return SCAP_SUCCESS; diff --git a/userspace/libscap/engine/udig/scap_udig.c b/userspace/libscap/engine/udig/scap_udig.c index e7c771831d..64cc97c631 100644 --- a/userspace/libscap/engine/udig/scap_udig.c +++ b/userspace/libscap/engine/udig/scap_udig.c @@ -826,6 +826,7 @@ static int32_t configure(struct scap_engine_handle engine, enum scap_setting set case SCAP_SNAPLEN: return udig_set_snaplen(engine, arg1); case SCAP_EVENTMASK: + case SCAP_TPMASK: case SCAP_DYNAMIC_SNAPLEN: case SCAP_STATSD_PORT: case SCAP_FULLCAPTURE_PORT_RANGE: diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index cea361b284..4adc180cf8 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -1458,6 +1458,13 @@ static int32_t scap_handle_eventmask(scap_t* handle, uint32_t op, uint32_t ppm_s break; } + if (ppm_sc >= PPM_SC_MAX) + { + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "%s(%d) wrong param", __FUNCTION__, ppm_sc); + ASSERT(false); + return SCAP_FAILURE; + } + if(handle->m_vtable) { return handle->m_vtable->configure(handle->m_engine, SCAP_EVENTMASK, op, ppm_sc); @@ -1479,6 +1486,50 @@ int32_t scap_set_eventmask(scap_t* handle, uint32_t ppm_sc, bool enabled) { return(scap_handle_eventmask(handle, enabled ? SCAP_EVENTMASK_SET : SCAP_EVENTMASK_UNSET, ppm_sc)); } +static int32_t scap_handle_tpmask(scap_t* handle, uint32_t op, uint32_t tp) +{ + switch(op) + { + case SCAP_TPMASK_SET: + case SCAP_TPMASK_UNSET: + break; + + default: + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "%s(%d) internal error", __FUNCTION__, op); + ASSERT(false); + return SCAP_FAILURE; + break; + } + + if (tp >= TP_VAL_MAX) + { + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "%s(%d) wrong param", __FUNCTION__, tp); + ASSERT(false); + return SCAP_FAILURE; + } + + if(handle->m_vtable) + { + return handle->m_vtable->configure(handle->m_engine, SCAP_TPMASK, op, tp); + } +#if !defined(HAS_CAPTURE) || defined(_WIN32) + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "tpmask not supported on %s", PLATFORM_NAME); + return SCAP_FAILURE; +#else + if (handle == NULL) + { + return SCAP_FAILURE; + } + + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "manipulating tpmask not supported on this scap mode"); + return SCAP_FAILURE; +#endif // HAS_CAPTURE +} + +int32_t scap_set_tpmask(scap_t* handle, uint32_t tp, bool enabled) { + return(scap_handle_tpmask(handle, enabled ? SCAP_TPMASK_SET : SCAP_TPMASK_UNSET, tp)); +} + uint32_t scap_event_get_dump_flags(scap_t* handle) { if(handle->m_vtable->savefile_ops) diff --git a/userspace/libscap/scap.def b/userspace/libscap/scap.def index e8daf0951f..c9976ea14e 100644 --- a/userspace/libscap/scap.def +++ b/userspace/libscap/scap.def @@ -38,7 +38,7 @@ EXPORTS scap_get_readfile_offset scap_clear_eventmask scap_set_eventmask - scap_unset_eventmask + scap_set_tpmask scap_number_of_bytes_to_write scap_event_get_dump_flags scap_enable_dynamic_snaplen diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index e385e0d586..25703bd8ed 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -972,6 +972,16 @@ int32_t scap_clear_eventmask(scap_t* handle); */ int32_t scap_set_eventmask(scap_t* handle, uint32_t ppm_sc, bool enabled); +/*! + \brief Set the tp into the tpmask so that + users can attach the related tracepoint. + + \param handle Handle to the capture instance. + \param tp id (example SYS_ENTER) + \note This function can only be called for live captures. +*/ +int32_t scap_set_tpmask(scap_t* handle, uint32_t tp, bool enabled); + /*! \brief Get the root directory of the system. This usually changes diff --git a/userspace/libscap/scap_vtable.h b/userspace/libscap/scap_vtable.h index 10c3035395..1ef54d5dd1 100644 --- a/userspace/libscap/scap_vtable.h +++ b/userspace/libscap/scap_vtable.h @@ -43,6 +43,11 @@ enum scap_eventmask_op { SCAP_EVENTMASK_UNSET = 0x7307, //< disable an event }; +enum scap_tpmask_op { + SCAP_TPMASK_SET = 0x8306, //< enable a tp + SCAP_TPMASK_UNSET = 0x8307, //< disable a tp +}; + /** * @brief settings configurable for scap engines */ @@ -64,7 +69,7 @@ enum scap_setting { */ SCAP_SNAPLEN, /** - * @brief enable/disable individual events + * @brief enable/disable individual syscalls * arg1: scap_eventmask_op * arg2: event id (ignored for SCAP_EVENTMASK_ZERO) */ @@ -85,6 +90,12 @@ enum scap_setting { * arg1: statsd port */ SCAP_STATSD_PORT, + /** + * @brief enable/disable individual tracepoints + * arg1: scap_tpmask_op + * arg2: tp id + */ + SCAP_TPMASK, }; struct scap_savefile_vtable { diff --git a/userspace/libsinsp/CMakeLists.txt b/userspace/libsinsp/CMakeLists.txt index 8d5fe3a9af..62e973c441 100644 --- a/userspace/libsinsp/CMakeLists.txt +++ b/userspace/libsinsp/CMakeLists.txt @@ -120,7 +120,8 @@ set(SINSP_SOURCES value_parser.cpp user.cpp gvisor_config.cpp - sinsp_ppm_sc.cpp) + sinsp_ppm_sc.cpp + sinsp_tp.cpp) if(WITH_CHISEL) list(APPEND SINSP_SOURCES diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 8503b93e91..08932b117c 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -450,81 +450,6 @@ void sinsp::set_import_users(bool import_users) m_usergroup_manager.m_import_users = import_users; } -std::unordered_set sinsp::enforce_sinsp_state_tp(std::unordered_set tp_of_interest) -{ - std::vector minimum_tracepoints(TP_VAL_MAX, 0); - - /* Should never happen but just to be sure. */ - if(scap_get_modifies_state_tracepoints(minimum_tracepoints.data()) != SCAP_SUCCESS) - { - throw sinsp_exception("'minimum_tracepoints' is an unexpected NULL vector!"); - } - - for(int tp = 0; tp < TP_VAL_MAX; tp++) - { - if(minimum_tracepoints[tp]) - { - tp_of_interest.insert(tp); - } - } - return tp_of_interest; -} - -std::unordered_set sinsp::get_tp_names(const std::unordered_set& tp_set) -{ - std::unordered_set tp_names_set; - for(const auto& it : tp_set) - { - std::string tp_name = tp_names[it]; - tp_names_set.insert(tp_name); - } - return tp_names_set; -} - -void sinsp::fill_ppm_sc_of_interest(scap_open_args *oargs, const std::unordered_set &ppm_sc_of_interest) -{ - for (int i = 0; i < PPM_SC_MAX; i++) - { - /* If the set is empty, fallback to all interesting syscalls */ - if (ppm_sc_of_interest.empty()) - { - oargs->ppm_sc_of_interest.ppm_sc[i] = true; - } - else - { - oargs->ppm_sc_of_interest.ppm_sc[i] = ppm_sc_of_interest.find(i) != ppm_sc_of_interest.end(); - } - } -} - -void sinsp::fill_tp_of_interest(scap_open_args *oargs, const std::unordered_set &tp_of_interest) -{ - for(int i = 0; i < TP_VAL_MAX; i++) - { - /* If the set is empty, fallback to all interesting tracepoints */ - if (tp_of_interest.empty()) - { - oargs->tp_of_interest.tp[i] = true; - } - else - { - oargs->tp_of_interest.tp[i] = tp_of_interest.find(i) != tp_of_interest.end(); - } - } -} - -std::unordered_set sinsp::get_all_tp() -{ - std::unordered_set ppm_tp_array; - - for(uint32_t tp = 0; tp < TP_VAL_MAX; tp++) - { - ppm_tp_array.insert(tp); - } - - return ppm_tp_array; -} - /*=============================== OPEN METHODS ===============================*/ void sinsp::open_common(scap_open_args* oargs) diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index 1f803aa988..6509bb5190 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -922,6 +922,18 @@ class SINSP_PUBLIC sinsp : public capture_stats_source, public wmi_handle_source /*=============================== Tracepoint set related ===============================*/ + /*! + \brief Mark desired tracepoint as (un)interesting, attaching or detaching it. + This method receives a `tp` code. You can find the available + `enum tp_values` in `driver/ppm_tp.h`. + Please note that this method must be called when the inspector is already open to + modify at runtime the interesting tracepoint set. + + WARNING: playing with this API could break `libsinsp` state collection, this is only + useful in advanced cases where the client needs to know what it is doing! + */ + void mark_tp_of_interest(uint32_t tp, bool enabled = true); + /*! \brief Get all the available tracepoints. */ diff --git a/userspace/libsinsp/sinsp_ppm_sc.cpp b/userspace/libsinsp/sinsp_ppm_sc.cpp index 7ada9468dd..5ec2bbe23a 100644 --- a/userspace/libsinsp/sinsp_ppm_sc.cpp +++ b/userspace/libsinsp/sinsp_ppm_sc.cpp @@ -17,6 +17,22 @@ limitations under the License. #include +void sinsp::fill_ppm_sc_of_interest(scap_open_args *oargs, const std::unordered_set &ppm_sc_of_interest) +{ + for (int i = 0; i < PPM_SC_MAX; i++) + { + /* If the set is empty, fallback to all interesting syscalls */ + if (ppm_sc_of_interest.empty()) + { + oargs->ppm_sc_of_interest.ppm_sc[i] = true; + } + else + { + oargs->ppm_sc_of_interest.ppm_sc[i] = ppm_sc_of_interest.find(i) != ppm_sc_of_interest.end(); + } + } +} + void sinsp::mark_ppm_sc_of_interest(uint32_t ppm_sc, bool enable) { /* This API must be used only after the initialization phase. */ diff --git a/userspace/libsinsp/sinsp_tp.cpp b/userspace/libsinsp/sinsp_tp.cpp new file mode 100644 index 0000000000..3a6906fafa --- /dev/null +++ b/userspace/libsinsp/sinsp_tp.cpp @@ -0,0 +1,91 @@ +/* +Copyright (C) 2022 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 + +void sinsp::fill_tp_of_interest(scap_open_args *oargs, const std::unordered_set &tp_of_interest) +{ + for(int i = 0; i < TP_VAL_MAX; i++) + { + /* If the set is empty, fallback to all interesting tracepoints */ + if (tp_of_interest.empty()) + { + oargs->tp_of_interest.tp[i] = true; + } + else + { + oargs->tp_of_interest.tp[i] = tp_of_interest.find(i) != tp_of_interest.end(); + } + } +} + +void sinsp::mark_tp_of_interest(uint32_t tp, bool enable) +{ + /* This API must be used only after the initialization phase. */ + if (!m_inited) + { + throw sinsp_exception("you cannot use this method before opening the inspector!"); + } + int ret = scap_set_tpmask(m_h, tp, enable); + if (ret != SCAP_SUCCESS) + { + throw sinsp_exception(scap_getlasterr(m_h)); + } +} + +std::unordered_set sinsp::enforce_sinsp_state_tp(std::unordered_set tp_of_interest) +{ + std::vector minimum_tracepoints(TP_VAL_MAX, 0); + + /* Should never happen but just to be sure. */ + if(scap_get_modifies_state_tracepoints(minimum_tracepoints.data()) != SCAP_SUCCESS) + { + throw sinsp_exception("'minimum_tracepoints' is an unexpected NULL vector!"); + } + + for(int tp = 0; tp < TP_VAL_MAX; tp++) + { + if(minimum_tracepoints[tp]) + { + tp_of_interest.insert(tp); + } + } + return tp_of_interest; +} + +std::unordered_set sinsp::get_all_tp() +{ + std::unordered_set ppm_tp_array; + + for(uint32_t tp = 0; tp < TP_VAL_MAX; tp++) + { + ppm_tp_array.insert(tp); + } + + return ppm_tp_array; +} + +std::unordered_set sinsp::get_tp_names(const std::unordered_set& tp_set) +{ + std::unordered_set tp_names_set; + for(const auto& it : tp_set) + { + std::string tp_name = tp_names[it]; + tp_names_set.insert(tp_name); + } + return tp_names_set; +}