diff --git a/driver/API_VERSION b/driver/API_VERSION index 227cea2156..4a36342fca 100644 --- a/driver/API_VERSION +++ b/driver/API_VERSION @@ -1 +1 @@ -2.0.0 +3.0.0 diff --git a/driver/bpf/plumbing_helpers.h b/driver/bpf/plumbing_helpers.h index 336267ed8f..51e3b4ab19 100644 --- a/driver/bpf/plumbing_helpers.h +++ b/driver/bpf/plumbing_helpers.h @@ -528,9 +528,9 @@ static __always_inline void reset_tail_ctx(struct scap_bpf_per_cpu_state *state, static __always_inline void call_filler(void *ctx, void *stack_ctx, enum ppm_event_type evt_type, - struct scap_bpf_settings *settings, enum syscall_flags drop_flags) { + struct scap_bpf_settings *settings; const struct ppm_event_entry *filler_info; struct scap_bpf_per_cpu_state *state; unsigned long long pid; @@ -543,6 +543,10 @@ static __always_inline void call_filler(void *ctx, if (!state) return; + settings = get_bpf_settings(); + if (!settings) + return; + if (!acquire_local_state(state)) return; diff --git a/driver/bpf/probe.c b/driver/bpf/probe.c index 1bc7130914..045ff69102 100644 --- a/driver/bpf/probe.c +++ b/driver/bpf/probe.c @@ -36,7 +36,6 @@ int bpf_##event(struct type *ctx) BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args) { const struct syscall_evt_pair *sc_evt; - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; int drop_flags; long id; @@ -50,18 +49,11 @@ BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args) return 0; enabled = is_syscall_interesting(id); - if (enabled == false) + if (!enabled) { return 0; } - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - sc_evt = get_syscall_info(id); if (!sc_evt) return 0; @@ -75,7 +67,7 @@ BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args) } #ifdef BPF_SUPPORTS_RAW_TRACEPOINTS - call_filler(ctx, ctx, evt_type, settings, drop_flags); + call_filler(ctx, ctx, evt_type, drop_flags); #else /* Duplicated here to avoid verifier madness */ struct sys_enter_args stack_ctx; @@ -84,7 +76,7 @@ BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args) if (stash_args(stack_ctx.args)) return 0; - call_filler(ctx, &stack_ctx, evt_type, settings, drop_flags); + call_filler(ctx, &stack_ctx, evt_type, drop_flags); #endif return 0; } @@ -92,7 +84,6 @@ BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args) BPF_PROBE("raw_syscalls/", sys_exit, sys_exit_args) { const struct syscall_evt_pair *sc_evt; - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; int drop_flags; long id; @@ -106,18 +97,11 @@ BPF_PROBE("raw_syscalls/", sys_exit, sys_exit_args) return 0; enabled = is_syscall_interesting(id); - if (enabled == false) + if (!enabled) { return 0; } - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - sc_evt = get_syscall_info(id); if (!sc_evt) return 0; @@ -130,13 +114,12 @@ BPF_PROBE("raw_syscalls/", sys_exit, sys_exit_args) drop_flags = UF_ALWAYS_DROP; } - call_filler(ctx, ctx, evt_type, settings, drop_flags); + call_filler(ctx, ctx, evt_type, drop_flags); return 0; } BPF_PROBE("sched/", sched_process_exit, sched_process_exit_args) { - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; struct task_struct *task; unsigned int flags; @@ -147,53 +130,30 @@ BPF_PROBE("sched/", sched_process_exit, sched_process_exit_args) if (flags & PF_KTHREAD) return 0; - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - evt_type = PPME_PROCEXIT_1_E; - call_filler(ctx, ctx, evt_type, settings, UF_NEVER_DROP); + call_filler(ctx, ctx, evt_type, UF_NEVER_DROP); return 0; } BPF_PROBE("sched/", sched_switch, sched_switch_args) { - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - evt_type = PPME_SCHEDSWITCH_6_E; - call_filler(ctx, ctx, evt_type, settings, 0); + call_filler(ctx, ctx, evt_type, 0); return 0; } #ifdef CAPTURE_PAGE_FAULTS static __always_inline int bpf_page_fault(struct page_fault_args *ctx) { - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - evt_type = PPME_PAGE_FAULT_E; - call_filler(ctx, ctx, evt_type, settings, UF_ALWAYS_DROP); + call_filler(ctx, ctx, evt_type, UF_ALWAYS_DROP); return 0; } @@ -210,19 +170,11 @@ BPF_PROBE("exceptions/", page_fault_kernel, page_fault_args) BPF_PROBE("signal/", signal_deliver, signal_deliver_args) { - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - evt_type = PPME_SIGNALDELIVER_E; - call_filler(ctx, ctx, evt_type, settings, UF_ALWAYS_DROP); + call_filler(ctx, ctx, evt_type, UF_ALWAYS_DROP); return 0; } @@ -230,18 +182,10 @@ BPF_PROBE("signal/", signal_deliver, signal_deliver_args) __bpf_section(TP_NAME "sched/sched_process_fork") int bpf_sched_process_fork(struct sched_process_fork_args *ctx) { - struct scap_bpf_settings *settings; enum ppm_event_type evt_type; struct sys_stash_args args; unsigned long *argsp; - settings = get_bpf_settings(); - if (!settings) - return 0; - - if (!settings->capture_enabled) - return 0; - argsp = __unstash_args(ctx->parent_pid); if (!argsp) return 0; @@ -269,13 +213,6 @@ BPF_PROBE("sched/", sched_process_exec, sched_process_exec_args) return 0; } - /* Check if the capture is enabled. */ - settings = get_bpf_settings(); - if(!(settings && settings->capture_enabled)) - { - return 0; - } - /* Reset the tail context in the CPU state map. */ uint32_t cpu = bpf_get_smp_processor_id(); struct scap_bpf_per_cpu_state * state = get_local_state(cpu); @@ -283,6 +220,12 @@ BPF_PROBE("sched/", sched_process_exec, sched_process_exec_args) { return 0; } + + settings = get_bpf_settings(); + if(!settings) + { + return 0; + } uint64_t ts = settings->boot_time + bpf_ktime_get_boot_ns(); reset_tail_ctx(state, event_type, ts); ++state->n_evts; @@ -313,13 +256,6 @@ int bpf_sched_process_fork(struct sched_process_fork_raw_args *ctx) return 0; } - /* Check if the capture is enabled. */ - settings = get_bpf_settings(); - if(!(settings && settings->capture_enabled)) - { - return 0; - } - /* Reset the tail context in the CPU state map. */ uint32_t cpu = bpf_get_smp_processor_id(); struct scap_bpf_per_cpu_state * state = get_local_state(cpu); @@ -327,6 +263,12 @@ int bpf_sched_process_fork(struct sched_process_fork_raw_args *ctx) { return 0; } + + settings = get_bpf_settings(); + if(!settings) + { + return 0; + } uint64_t ts = settings->boot_time + bpf_ktime_get_boot_ns(); reset_tail_ctx(state, event_type, ts); ++state->n_evts; diff --git a/driver/bpf/types.h b/driver/bpf/types.h index 9c91be2351..e5d584617d 100644 --- a/driver/bpf/types.h +++ b/driver/bpf/types.h @@ -234,7 +234,6 @@ struct scap_bpf_settings { void *socket_file_ops; uint32_t snaplen; uint32_t sampling_ratio; - bool capture_enabled; bool do_dynamic_snaplen; bool dropping_mode; bool is_dropping; diff --git a/driver/main.c b/driver/main.c index 0cadd0ec8b..8dede0b79a 100644 --- a/driver/main.c +++ b/driver/main.c @@ -86,6 +86,8 @@ MODULE_AUTHOR("the Falco authors"); #define _PAGE_ENC 0 #endif +#define TP_VAL_INTERNAL TP_VAL_MAX + struct ppm_device { dev_t dev; struct cdev cdev; @@ -136,17 +138,19 @@ struct event_data_t { */ static int ppm_open(struct inode *inode, struct file *filp); static int ppm_release(struct inode *inode, struct file *filp); -static int force_tp_set(u32 new_tp_set, u32 max_val); +static int force_tp_set(struct ppm_consumer_t *consumer, u32 new_tp_set); static long ppm_ioctl(struct file *f, unsigned int cmd, unsigned long arg); static int ppm_mmap(struct file *filp, struct vm_area_struct *vma); static int record_event_consumer(struct ppm_consumer_t *consumer, enum ppm_event_type event_type, enum syscall_flags drop_flags, nanoseconds ns, - struct event_data_t *event_datap); + struct event_data_t *event_datap, + tp_values tp_type); static void record_event_all_consumers(enum ppm_event_type event_type, enum syscall_flags drop_flags, - struct event_data_t *event_datap); + struct event_data_t *event_datap, + tp_values tp_type); static int init_ring_buffer(struct ppm_ring_buffer_context *ring, unsigned long buffer_bytes_dim); static void free_ring_buffer(struct ppm_ring_buffer_context *ring); static void reset_ring_buffer(struct ppm_ring_buffer_context *ring); @@ -177,7 +181,8 @@ TRACEPOINT_PROBE(signal_deliver_probe, int sig, struct siginfo *info, struct k_s /* tracepoints `page_fault_user/kernel` don't exist on some architectures.*/ #ifdef CAPTURE_PAGE_FAULTS -TRACEPOINT_PROBE(page_fault_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code); +TRACEPOINT_PROBE(page_fault_user_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code); +TRACEPOINT_PROBE(page_fault_kern_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code); #endif #ifdef CAPTURE_SCHED_PROC_FORK @@ -209,6 +214,7 @@ static const struct file_operations g_ppm_fops = { LIST_HEAD(g_consumer_list); static DEFINE_MUTEX(g_consumer_mutex); static u32 g_tracepoints_attached; // list of attached tracepoints; bitmask using ppm_tp.h enum +static u32 g_tracepoints_refs[TP_VAL_MAX]; static unsigned long g_buffer_bytes_dim = DEFAULT_BUFFER_BYTES_DIM; // dimension of a single per-CPU buffer in bytes. #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) static struct tracepoint *tp_sys_enter; @@ -296,6 +302,27 @@ static void compat_unregister_trace(void *func, const char *probename, struct tr #endif } +static void set_consumer_tracepoints(struct ppm_consumer_t *consumer, u32 tp_set) +{ + int i; + int bits_processed; + + vpr_info("consumer %p | requested tp set: %d\n", consumer->consumer_id, tp_set); + bits_processed = force_tp_set(consumer, tp_set); + for(i = 0; i < bits_processed; i++) + { + if (tp_set & (1 << i)) + { + consumer->tracepoints_attached |= 1 << i; + } + else + { + consumer->tracepoints_attached &= ~(1 << i); + } + } + vpr_info("consumer %p | set tp set: %d\n", consumer->consumer_id, consumer->tracepoints_attached); +} + static struct ppm_consumer_t *ppm_find_consumer(struct task_struct *consumer_id) { struct ppm_consumer_t *el = NULL; @@ -327,6 +354,9 @@ static void check_remove_consumer(struct ppm_consumer_t *consumer, int remove_fr if (open_rings == 0) { pr_info("deallocating consumer %p\n", consumer->consumer_id); + // Clean up tracepoints references for this consumer + set_consumer_tracepoints(consumer, 0); + if (remove_from_list) { list_del_rcu(&consumer->node); synchronize_rcu(); @@ -349,7 +379,6 @@ static void check_remove_consumer(struct ppm_consumer_t *consumer, int remove_fr static int ppm_open(struct inode *inode, struct file *filp) { int ret; - u32 val; int in_list = false; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) int ring_no = iminor(filp->f_path.dentry->d_inode); @@ -395,8 +424,10 @@ static int ppm_open(struct inode *inode, struct file *filp) goto cleanup_open; } + consumer->id = num_consumers; consumer->consumer_id = consumer_id; consumer->buffer_bytes_dim = g_buffer_bytes_dim; + consumer->tracepoints_attached = 0; /* * Initialize the ring buffers array @@ -498,26 +529,9 @@ static int ppm_open(struct inode *inode, struct file *filp) reset_ring_buffer(ring); ring->open = true; - if (g_tracepoints_attached == 0) { - pr_info("starting capture\n"); - - /* - * Enable the tracepoints - */ - val = (1 << TP_VAL_MAX) - 1; - ret = force_tp_set(val, TP_VAL_MAX); - if (ret != 0) - { - goto err_tp_set; - } - } - ret = 0; goto cleanup_open; -err_tp_set: - ring->open = false; - err_init_ring_buffer: check_remove_consumer(consumer, in_list); @@ -529,7 +543,6 @@ static int ppm_open(struct inode *inode, struct file *filp) static int ppm_release(struct inode *inode, struct file *filp) { - int cpu; int ret; struct ppm_ring_buffer_context *ring; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) @@ -562,8 +575,6 @@ static int ppm_release(struct inode *inode, struct file *filp) goto cleanup_release; } - ring->capture_enabled = false; - vpr_info("closing ring %d, consumer:%p evt:%llu, dr_buf:%llu, dr_buf_clone_fork_e:%llu, dr_buf_clone_fork_x:%llu, dr_buf_execve_e:%llu, dr_buf_execve_x:%llu, dr_buf_connect_e:%llu, dr_buf_connect_x:%llu, dr_buf_open_e:%llu, dr_buf_open_x:%llu, dr_buf_dir_file_e:%llu, dr_buf_dir_file_x:%llu, dr_buf_other_e:%llu, dr_buf_other_x:%llu, dr_pf:%llu, pr:%llu, cs:%llu\n", ring_no, consumer_id, @@ -589,29 +600,6 @@ static int ppm_release(struct inode *inode, struct file *filp) check_remove_consumer(consumer, true); - /* - * The last closed device stops event collection - */ - if (list_empty(&g_consumer_list)) { - if (g_tracepoints_attached != 0) { - pr_info("no more consumers, stopping capture\n"); - - force_tp_set(0, TP_VAL_MAX); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) - tracepoint_synchronize_unregister(); -#endif - - /* - * Reset tracepoint counter - */ - for_each_possible_cpu(cpu) { - per_cpu(g_n_tracepoint_hit, cpu) = 0; - } - } else { - ASSERT(false); - } - } - ret = 0; cleanup_release: @@ -634,26 +622,49 @@ static int compat_set_tracepoint(void *func, const char *probename, struct trace return ret; } -static int force_tp_set(u32 new_tp_set, u32 max_val) +static int force_tp_set(struct ppm_consumer_t *consumer, u32 new_tp_set) { u32 idx; u32 new_val; u32 curr_val; - int ret = 0; - - if (new_tp_set == g_tracepoints_attached) - { - // ok already equal - return ret; - } + int cpu; + int ret; - for(idx = 0; idx < max_val && ret == 0; idx++) + ret = 0; + for(idx = 0; idx < TP_VAL_MAX && ret == 0; idx++) { new_val = new_tp_set & (1 << idx); curr_val = g_tracepoints_attached & (1 << idx); + if(new_val == curr_val) { - // no change needed + if (new_val) + { + // If enable is requested, set ref bit + g_tracepoints_refs[idx] |= 1 << consumer->id; + } + else + { + // If disable is requested, unset ref bit + g_tracepoints_refs[idx] &= ~(1 << consumer->id); + } + // no change needed, we just update the refs + continue; + } + + if (new_val && g_tracepoints_refs[idx] != 0) + { + // we are not the first to request this tp; + // set ref bit and continue + g_tracepoints_refs[idx] |= 1 << consumer->id; + continue; + } + + if (!new_val && g_tracepoints_refs[idx] != (1 << consumer->id)) + { + // we are not the last to unrequest this tp; + // unset ref bit and continue + g_tracepoints_refs[idx] &= ~(1 << consumer->id); continue; } @@ -707,13 +718,13 @@ static int force_tp_set(u32 new_tp_set, u32 max_val) case PAGE_FAULT_USER: if (!g_fault_tracepoint_disabled) { - ret = compat_set_tracepoint(page_fault_probe, tp_names[idx], tp_page_fault_user, new_val); + ret = compat_set_tracepoint(page_fault_user_probe, tp_names[idx], tp_page_fault_user, new_val); } break; case PAGE_FAULT_KERN: if (!g_fault_tracepoint_disabled) { - ret = compat_set_tracepoint(page_fault_probe, tp_names[idx], tp_page_fault_kernel, new_val); + ret = compat_set_tracepoint(page_fault_kern_probe, tp_names[idx], tp_page_fault_kernel, new_val); } break; #endif @@ -742,6 +753,8 @@ static int force_tp_set(u32 new_tp_set, u32 max_val) if (ret == 0) { g_tracepoints_attached |= 1 << idx; + g_tracepoints_refs[idx] |= 1 << consumer->id; + vpr_info("attached tracepoint %s\n", tp_names[idx]); } else { @@ -753,6 +766,8 @@ static int force_tp_set(u32 new_tp_set, u32 max_val) if (ret == 0) { g_tracepoints_attached &= ~(1 << idx); + g_tracepoints_refs[idx] &= ~(1 << consumer->id); + vpr_info("detached tracepoint %s\n", tp_names[idx]); } else { @@ -761,14 +776,21 @@ static int force_tp_set(u32 new_tp_set, u32 max_val) } } - if (ret != 0) + if (g_tracepoints_attached == 0) { - // Error: reset first idx-1 bits to 0. - // This means that we are requesting to unregister first - // idx-1 tracepoints, that are the succedeed ones before the error. - force_tp_set(0, idx - 1); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) + tracepoint_synchronize_unregister(); +#endif + + /* + * Reset tracepoint counter + */ + for_each_possible_cpu(cpu) + { + per_cpu(g_n_tracepoint_hit, cpu) = 0; + } } - return ret; + return idx; } static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -919,12 +941,6 @@ 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); @@ -937,50 +953,6 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } switch (cmd) { - case PPM_IOCTL_DISABLE_CAPTURE: - { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) - int ring_no = iminor(filp->f_path.dentry->d_inode); -#else - int ring_no = iminor(filp->f_dentry->d_inode); -#endif - struct ppm_ring_buffer_context *ring = per_cpu_ptr(consumer->ring_buffers, ring_no); - - if (!ring) { - ASSERT(false); - ret = -ENODEV; - goto cleanup_ioctl; - } - - ring->capture_enabled = false; - - vpr_info("PPM_IOCTL_DISABLE_CAPTURE for ring %d, consumer %p\n", ring_no, consumer_id); - - ret = 0; - goto cleanup_ioctl; - } - case PPM_IOCTL_ENABLE_CAPTURE: - { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) - int ring_no = iminor(filp->f_path.dentry->d_inode); -#else - int ring_no = iminor(filp->f_dentry->d_inode); -#endif - struct ppm_ring_buffer_context *ring = per_cpu_ptr(consumer->ring_buffers, ring_no); - - if (!ring) { - ASSERT(false); - ret = -ENODEV; - goto cleanup_ioctl; - } - - ring->capture_enabled = true; - - vpr_info("PPM_IOCTL_ENABLE_CAPTURE for ring %d, consumer %p\n", ring_no, consumer_id); - - ret = 0; - goto cleanup_ioctl; - } case PPM_IOCTL_DISABLE_DROPPING_MODE: { struct event_data_t event_data; @@ -999,7 +971,7 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) event_data.event_info.context_data.sched_prev = (void *)DEI_DISABLE_DROPPING; event_data.event_info.context_data.sched_next = (void *)0; - record_event_consumer(consumer, PPME_SCAPEVENT_E, UF_NEVER_DROP, ppm_nsecs(), &event_data); + record_event_consumer(consumer, PPME_SCAPEVENT_E, UF_NEVER_DROP, ppm_nsecs(), &event_data, TP_VAL_INTERNAL); ret = 0; goto cleanup_ioctl; @@ -1198,7 +1170,16 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case PPM_IOCTL_MANAGE_TP: { - ret = force_tp_set((u32)arg, TP_VAL_MAX); + set_consumer_tracepoints(consumer, (u32)arg); + ret = 0; + goto cleanup_ioctl; + } + case PPM_IOCTL_GET_TPMASK: + { + u32 __user *out = (u32 __user *)arg; + ret = 0; + if(put_user(consumer->tracepoints_attached, out)) + ret = -EINVAL; goto cleanup_ioctl; } default: @@ -1480,7 +1461,7 @@ static inline void record_drop_e(struct ppm_consumer_t *consumer, { struct event_data_t event_data = {0}; - if (record_event_consumer(consumer, PPME_DROP_E, UF_NEVER_DROP, ns, &event_data) == 0) { + if (record_event_consumer(consumer, PPME_DROP_E, UF_NEVER_DROP, ns, &event_data, TP_VAL_INTERNAL) == 0) { consumer->need_to_insert_drop_e = 1; } else { if (consumer->need_to_insert_drop_e == 1 && !(drop_flags & UF_ATOMIC)) { @@ -1638,7 +1619,7 @@ static inline void record_drop_x(struct ppm_consumer_t *consumer, { struct event_data_t event_data = {0}; - if (record_event_consumer(consumer, PPME_DROP_X, UF_NEVER_DROP, ns, &event_data) == 0) { + if (record_event_consumer(consumer, PPME_DROP_X, UF_NEVER_DROP, ns, &event_data, TP_VAL_INTERNAL) == 0) { consumer->need_to_insert_drop_x = 1; } else { if (consumer->need_to_insert_drop_x == 1 && !(drop_flags & UF_ATOMIC)) { @@ -1760,14 +1741,15 @@ static inline int drop_event(struct ppm_consumer_t *consumer, static void record_event_all_consumers(enum ppm_event_type event_type, enum syscall_flags drop_flags, - struct event_data_t *event_datap) + struct event_data_t *event_datap, + tp_values tp_type) { struct ppm_consumer_t *consumer; nanoseconds ns = ppm_nsecs(); rcu_read_lock(); list_for_each_entry_rcu(consumer, &g_consumer_list, node) { - record_event_consumer(consumer, event_type, drop_flags, ns, event_datap); + record_event_consumer(consumer, event_type, drop_flags, ns, event_datap, tp_type); } rcu_read_unlock(); } @@ -1779,7 +1761,8 @@ static int record_event_consumer(struct ppm_consumer_t *consumer, enum ppm_event_type event_type, enum syscall_flags drop_flags, nanoseconds ns, - struct event_data_t *event_datap) + struct event_data_t *event_datap, + tp_values tp_type) { int res = 0; size_t event_size = 0; @@ -1796,6 +1779,11 @@ static int record_event_consumer(struct ppm_consumer_t *consumer, int32_t cbres = PPM_SUCCESS; int cpu; + if (tp_type < TP_VAL_INTERNAL && !(consumer->tracepoints_attached & (1 << tp_type))) + { + return res; + } + if (!test_bit(event_type, consumer->events_mask)) return res; @@ -1821,11 +1809,6 @@ static int record_event_consumer(struct ppm_consumer_t *consumer, ASSERT(ring); ring_info = ring->info; - if (!ring->capture_enabled) { - put_cpu(); - return res; - } - ring_info->n_evts++; if (event_datap->category == PPMC_CONTEXT_SWITCH && event_datap->event_info.context_data.sched_prev != NULL) { if (event_type != PPME_SCAPEVENT_E && event_type != PPME_CPU_HOTPLUG_E) { @@ -2211,9 +2194,9 @@ TRACEPOINT_PROBE(syscall_enter_probe, struct pt_regs *regs, long id) event_data.compat = compat; if (used) - record_event_all_consumers(type, drop_flags, &event_data); + record_event_all_consumers(type, drop_flags, &event_data, SYS_ENTER); else - record_event_all_consumers(PPME_GENERIC_E, UF_ALWAYS_DROP, &event_data); + record_event_all_consumers(PPME_GENERIC_E, UF_ALWAYS_DROP, &event_data, SYS_ENTER); } } @@ -2277,9 +2260,9 @@ TRACEPOINT_PROBE(syscall_exit_probe, struct pt_regs *regs, long ret) event_data.compat = compat; if (used) - record_event_all_consumers(type, drop_flags, &event_data); + record_event_all_consumers(type, drop_flags, &event_data, SYS_EXIT); else - record_event_all_consumers(PPME_GENERIC_X, UF_ALWAYS_DROP, &event_data); + record_event_all_consumers(PPME_GENERIC_X, UF_ALWAYS_DROP, &event_data, SYS_EXIT); } } @@ -2309,7 +2292,7 @@ TRACEPOINT_PROBE(syscall_procexit_probe, struct task_struct *p) event_data.event_info.context_data.sched_prev = p; event_data.event_info.context_data.sched_next = p; - record_event_all_consumers(PPME_PROCEXIT_1_E, UF_NEVER_DROP, &event_data); + record_event_all_consumers(PPME_PROCEXIT_1_E, UF_NEVER_DROP, &event_data, SCHED_PROC_EXIT); } #include @@ -2337,7 +2320,7 @@ TRACEPOINT_PROBE(sched_switch_probe, bool preempt, struct task_struct *prev, str * Need to indicate ATOMIC (i.e. interrupt) context to avoid the event * handler calling printk() and potentially deadlocking the system. */ - record_event_all_consumers(PPME_SCHEDSWITCH_6_E, UF_USED | UF_ATOMIC, &event_data); + record_event_all_consumers(PPME_SCHEDSWITCH_6_E, UF_USED | UF_ATOMIC, &event_data, SCHED_SWITCH); } #endif @@ -2366,12 +2349,12 @@ TRACEPOINT_PROBE(signal_deliver_probe, int sig, struct siginfo *info, struct k_s event_data.event_info.signal_data.info = info; event_data.event_info.signal_data.ka = ka; - record_event_all_consumers(PPME_SIGNALDELIVER_E, UF_USED | UF_ALWAYS_DROP, &event_data); + record_event_all_consumers(PPME_SIGNALDELIVER_E, UF_USED | UF_ALWAYS_DROP, &event_data, SIGNAL_DELIVER); } #endif #ifdef CAPTURE_PAGE_FAULTS -TRACEPOINT_PROBE(page_fault_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code) +static void page_fault_probe(unsigned long address, struct pt_regs *regs, unsigned long error_code, tp_values tp_type) { struct event_data_t event_data; @@ -2392,7 +2375,17 @@ TRACEPOINT_PROBE(page_fault_probe, unsigned long address, struct pt_regs *regs, event_data.event_info.fault_data.regs = regs; event_data.event_info.fault_data.error_code = error_code; - record_event_all_consumers(PPME_PAGE_FAULT_E, UF_ALWAYS_DROP, &event_data); + record_event_all_consumers(PPME_PAGE_FAULT_E, UF_ALWAYS_DROP, &event_data, tp_type); +} + +TRACEPOINT_PROBE(page_fault_user_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code) +{ + return page_fault_probe(address, regs, error_code, PAGE_FAULT_USER); +} + +TRACEPOINT_PROBE(page_fault_kern_probe, unsigned long address, struct pt_regs *regs, unsigned long error_code) +{ + return page_fault_probe(address, regs, error_code, PAGE_FAULT_KERN); } #endif @@ -2410,7 +2403,7 @@ TRACEPOINT_PROBE(sched_proc_exec_probe, struct task_struct *p, pid_t old_pid, st } event_data.category = PPMC_SCHED_PROC_EXEC; - record_event_all_consumers(PPME_SYSCALL_EXECVE_19_X, UF_NEVER_DROP, &event_data); + record_event_all_consumers(PPME_SYSCALL_EXECVE_19_X, UF_NEVER_DROP, &event_data, SCHED_PROC_EXEC); } #endif @@ -2426,12 +2419,12 @@ TRACEPOINT_PROBE(sched_proc_fork_probe, struct task_struct *parent, struct task_ */ if(unlikely(current->flags & PF_KTHREAD)) { - return; + return; } event_data.category = PPMC_SCHED_PROC_FORK; event_data.event_info.sched_proc_fork_data.child = child; - record_event_all_consumers(PPME_SYSCALL_CLONE_20_X, UF_NEVER_DROP, &event_data); + record_event_all_consumers(PPME_SYSCALL_CLONE_20_X, UF_NEVER_DROP, &event_data, SCHED_PROC_FORK); } #endif @@ -2511,7 +2504,6 @@ static void reset_ring_buffer(struct ppm_ring_buffer_context *ring) * see ppm_open */ ring->open = false; - ring->capture_enabled = false; ring->info->head = 0; ring->info->tail = 0; ring->nevents = 0; @@ -2689,7 +2681,7 @@ static int do_cpu_callback(unsigned long cpu, long sd_action) event_data.category = PPMC_CONTEXT_SWITCH; event_data.event_info.context_data.sched_prev = (void *)cpu; event_data.event_info.context_data.sched_next = (void *)sd_action; - record_event_all_consumers(PPME_CPU_HOTPLUG_E, UF_NEVER_DROP, &event_data); + record_event_all_consumers(PPME_CPU_HOTPLUG_E, UF_NEVER_DROP, &event_data, TP_VAL_INTERNAL); } return 0; } @@ -2872,10 +2864,12 @@ int scap_init(void) register_cpu_notifier(&cpu_notifier); #endif - /* - * All ok. Final initializations. - */ + // Initialize globals g_tracepoints_attached = 0; + for (j = 0; j < TP_VAL_MAX; j++) + { + g_tracepoints_refs[j] = 0; + } return 0; diff --git a/driver/modern_bpf/helpers/base/maps_getters.h b/driver/modern_bpf/helpers/base/maps_getters.h index 3b4125fcf8..e25fef3a27 100644 --- a/driver/modern_bpf/helpers/base/maps_getters.h +++ b/driver/modern_bpf/helpers/base/maps_getters.h @@ -21,11 +21,6 @@ static __always_inline u64 maps__get_boot_time() return g_settings.boot_time; } -static __always_inline bool maps__get_capture_flag() -{ - return g_settings.capture_enabled; -} - static __always_inline uint32_t maps__get_snaplen() { return g_settings.snaplen; diff --git a/driver/modern_bpf/helpers/interfaces/attached_programs.h b/driver/modern_bpf/helpers/interfaces/attached_programs.h deleted file mode 100644 index 9a6e9b0c77..0000000000 --- a/driver/modern_bpf/helpers/interfaces/attached_programs.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2022 The Falco Authors. - * - * This file is dual licensed under either the MIT or GPL 2. See MIT.txt - * or GPL2.txt for full copies of the license. - */ - -#pragma once - -#include - -static __always_inline bool attached_programs__capture_enabled() -{ - return maps__get_capture_flag(); -} diff --git a/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c b/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c index 2407f17709..21c8dd8d33 100644 --- a/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c +++ b/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c @@ -6,7 +6,6 @@ */ #include -#include /* From linux tree: /include/trace/events/syscall.h * TP_PROTO(struct pt_regs *regs, long id), @@ -27,11 +26,6 @@ int BPF_PROG(sys_enter, return 0; } - if(!attached_programs__capture_enabled()) - { - return 0; - } - /* Right now, drops all ia32 syscalls. */ if(syscalls_dispatcher__check_32bit_syscalls()) { diff --git a/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c b/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c index ab4f3b1215..e693ade107 100644 --- a/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c +++ b/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c @@ -6,7 +6,6 @@ */ #include -#include /* From linux tree: /include/trace/events/syscall.h * TP_PROTO(struct pt_regs *regs, long ret), @@ -29,11 +28,6 @@ int BPF_PROG(sys_exit, return 0; } - if(!attached_programs__capture_enabled()) - { - return 0; - } - if(syscalls_dispatcher__check_32bit_syscalls()) { return 0; diff --git a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c index b761a6f9e0..cb78715e2a 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c @@ -6,7 +6,6 @@ */ #include -#include /* From linux tree: /include/trace/events/sched.h * TP_PROTO(struct task_struct *p, pid_t old_pid, @@ -19,11 +18,6 @@ int BPF_PROG(sched_p_exec, struct task_struct *p, pid_t old_pid, struct linux_binprm *bprm) { - if(!attached_programs__capture_enabled()) - { - return 0; - } - struct task_struct *task = get_current_task(); uint32_t flags = 0; READ_TASK_FIELD_INTO(&flags, task, flags); diff --git a/driver/modern_bpf/programs/attached/events/sched_process_exit.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_exit.bpf.c index f5984e373c..2f998a726b 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_exit.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_exit.bpf.c @@ -1,5 +1,4 @@ #include -#include #include /* From linux tree: /include/trace/events/sched.h @@ -9,11 +8,6 @@ SEC("tp_btf/sched_process_exit") int BPF_PROG(sched_proc_exit, struct task_struct *task) { - if(!attached_programs__capture_enabled()) - { - return 0; - } - uint32_t flags = 0; READ_TASK_FIELD_INTO(&flags, task, flags); diff --git a/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c index bac5f982fc..97cf186fcb 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c @@ -6,7 +6,6 @@ */ #include -#include /* From linux tree: /include/trace/events/sched.h * TP_PROTO(struct task_struct *parent, @@ -19,11 +18,6 @@ SEC("tp_btf/sched_process_fork") int BPF_PROG(sched_p_fork, struct task_struct *parent, struct task_struct *child) { - if(!attached_programs__capture_enabled()) - { - return 0; - } - struct task_struct *task = get_current_task(); uint32_t flags = 0; READ_TASK_FIELD_INTO(&flags, task, flags); diff --git a/driver/modern_bpf/programs/attached/events/sched_switch.bpf.c b/driver/modern_bpf/programs/attached/events/sched_switch.bpf.c index d496e904a6..a80d9e925d 100644 --- a/driver/modern_bpf/programs/attached/events/sched_switch.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_switch.bpf.c @@ -1,5 +1,4 @@ #include -#include /* From linux tree: /include/linux/events/sched.h * TP_PROTO(bool preempt, struct task_struct *prev, @@ -10,11 +9,6 @@ int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { - if(!attached_programs__capture_enabled()) - { - return 0; - } - /// TODO: we could avoid switches from kernel threads to kernel threads (?). struct ringbuf_struct ringbuf; diff --git a/driver/modern_bpf/shared_definitions/struct_definitions.h b/driver/modern_bpf/shared_definitions/struct_definitions.h index 5dd3d36ef5..5bec415bfa 100644 --- a/driver/modern_bpf/shared_definitions/struct_definitions.h +++ b/driver/modern_bpf/shared_definitions/struct_definitions.h @@ -23,7 +23,6 @@ */ struct capture_settings { - bool capture_enabled; /* communicate if the capture is enabled or not. */ uint64_t boot_time; /* boot time. */ uint32_t snaplen; /* we use it when we want to read a maximum size from a event and no more. */ }; diff --git a/driver/ppm.h b/driver/ppm.h index fb87784a6d..b71cf1722c 100644 --- a/driver/ppm.h +++ b/driver/ppm.h @@ -43,7 +43,6 @@ typedef u64 nanoseconds; struct ppm_ring_buffer_context { bool cpu_online; bool open; - bool capture_enabled; struct ppm_ring_buffer_info *info; char *buffer; #ifndef WDIG @@ -58,6 +57,7 @@ struct ppm_ring_buffer_context { #ifndef UDIG struct ppm_consumer_t { + unsigned int id; // numeric id for the consumer (ie: registration index) struct task_struct *consumer_id; #ifdef __percpu struct ppm_ring_buffer_context __percpu *ring_buffers; @@ -78,6 +78,7 @@ struct ppm_consumer_t { uint16_t statsd_port; unsigned long buffer_bytes_dim; /* Every consumer will have its per-CPU buffer dim in bytes. */ DECLARE_BITMAP(events_mask, PPM_EVENT_MAX); + u32 tracepoints_attached; }; #endif // UDIG diff --git a/driver/ppm_events_public.h b/driver/ppm_events_public.h index 0e30892085..b2180c4d01 100644 --- a/driver/ppm_events_public.h +++ b/driver/ppm_events_public.h @@ -1787,8 +1787,8 @@ struct ppm_evt_hdr { */ #ifndef CYGWING_AGENT #define PPM_IOCTL_MAGIC 's' -#define PPM_IOCTL_DISABLE_CAPTURE _IO(PPM_IOCTL_MAGIC, 0) -#define PPM_IOCTL_ENABLE_CAPTURE _IO(PPM_IOCTL_MAGIC, 1) +// #define PPM_IOCTL_DISABLE_CAPTURE _IO(PPM_IOCTL_MAGIC, 0) Support dropped +// #define PPM_IOCTL_ENABLE_CAPTURE _IO(PPM_IOCTL_MAGIC, 1) Support dropped #define PPM_IOCTL_DISABLE_DROPPING_MODE _IO(PPM_IOCTL_MAGIC, 2) #define PPM_IOCTL_ENABLE_DROPPING_MODE _IO(PPM_IOCTL_MAGIC, 3) #define PPM_IOCTL_SET_SNAPLEN _IO(PPM_IOCTL_MAGIC, 4) diff --git a/test/modern_bpf/event_class/event_class.cpp b/test/modern_bpf/event_class/event_class.cpp index 247ea3933f..113bf5fced 100644 --- a/test/modern_bpf/event_class/event_class.cpp +++ b/test/modern_bpf/event_class/event_class.cpp @@ -88,71 +88,64 @@ event_test::~event_test() * Cleaning phase. */ - /* 1 - disable the capture of all events. */ - pman_disable_capture(); + /* + * NOTE: we always expect disable_capture to be manually called, + * just like enable_capture is. + */ - /* 2 - clean all the ring_buffers until they are empty. */ + /* 1 - clean all the ring_buffers until they are empty. */ clear_ring_buffers(); - /* 3 - clean all interesting syscalls. */ + /* 2 - clean all interesting syscalls. */ mark_all_64bit_syscalls_as_uninteresting(); - - /* 4 - detach all generic tracepoints attached to the kernel - * apart from syscall dispatchers. - */ - pman_detach_sched_proc_exit(); - pman_detach_sched_switch(); -#ifdef CAPTURE_SCHED_PROC_EXEC - pman_detach_sched_proc_exec(); -#endif -#ifdef CAPTURE_SCHED_PROC_FORK - pman_detach_sched_proc_fork(); -#endif } /* This constructor must be used with generic tracepoints * that must attach a dedicated BPF program into the kernel. */ -event_test::event_test(ppm_event_type event_type) +event_test::event_test(ppm_event_type event_type): + m_tp_set(TP_VAL_MAX, 0) { m_current_param = 0; m_event_type = event_type; - switch(event_type) + + switch(m_event_type) { case PPME_PROCEXIT_1_E: - pman_attach_sched_proc_exit(); + m_tp_set[SCHED_PROC_EXIT] = 1; break; - case PPME_SCHEDSWITCH_6_E: - pman_attach_sched_switch(); + m_tp_set[SCHED_SWITCH] = 1; break; - case PPME_SYSCALL_EXECVE_19_X: #ifdef CAPTURE_SCHED_PROC_EXEC - pman_attach_sched_proc_exec(); + m_tp_set[SCHED_PROC_EXEC] = 1; #endif break; - case PPME_SYSCALL_CLONE_20_X: #ifdef CAPTURE_SCHED_PROC_FORK - pman_attach_sched_proc_fork(); + m_tp_set[SCHED_PROC_FORK] = 1; #endif break; default: std::cout << " Unable to find the correct BPF program to attach" << std::endl; + break; } } /* This constructor must be used with syscalls events */ -event_test::event_test(int syscall_id, int event_direction) +event_test::event_test(int syscall_id, int event_direction): + m_tp_set(TP_VAL_MAX, 0) { if(event_direction == ENTER_EVENT) { + m_tp_set[SYS_ENTER] = 1; m_event_type = g_syscall_table[syscall_id].enter_event_type; } else { + m_tp_set[SYS_EXIT] = 1; m_event_type = g_syscall_table[syscall_id].exit_event_type; } @@ -165,10 +158,15 @@ event_test::event_test(int syscall_id, int event_direction) /* This constructor must be used with syscalls events when you * want to enable all syscalls. */ -event_test::event_test() +event_test::event_test(): + m_tp_set(TP_VAL_MAX, 0) { m_current_param = 0; + /* Enable only syscall tracepoints */ + m_tp_set[SYS_ENTER] = 1; + m_tp_set[SYS_EXIT] = 1; + for(int sys_num = 0; sys_num < SYSCALL_TABLE_SIZE; sys_num++) { mark_single_64bit_syscall_as_interesting(sys_num); @@ -187,7 +185,8 @@ void event_test::mark_all_64bit_syscalls_as_uninteresting() void event_test::enable_capture() { - pman_enable_capture(); + pman_enable_capture((bool*)m_tp_set.data()); + clear_ring_buffers(); } void event_test::disable_capture() diff --git a/test/modern_bpf/event_class/event_class.h b/test/modern_bpf/event_class/event_class.h index fb9b39cb59..01ff459979 100644 --- a/test/modern_bpf/event_class/event_class.h +++ b/test/modern_bpf/event_class/event_class.h @@ -21,6 +21,7 @@ extern "C" #include #include #include +#include } struct param @@ -536,6 +537,7 @@ class event_test struct ppm_evt_hdr* m_event_header; /* header of the event. */ uint32_t m_event_len; /* total event length. */ uint32_t m_current_param; /* current param that we are analyzing in a single assert method. */ + std::vector m_tp_set; /* Set of tracepoints that must be enabled for the specific test. */ /** * @brief Performs two main actions: diff --git a/test/modern_bpf/start_tests.cpp b/test/modern_bpf/start_tests.cpp index 741c0310ed..b6dbaffc00 100644 --- a/test/modern_bpf/start_tests.cpp +++ b/test/modern_bpf/start_tests.cpp @@ -70,11 +70,6 @@ int main(int argc, char** argv) ret = ret ?: pman_load_probe(); ret = ret ?: pman_finalize_maps_after_loading(); ret = ret ?: pman_finalize_ringbuf_array_after_loading(); - /* Syscall dispatchers are always attached. - * Generic tracepoints will be attached only in the dedicated test cases. - */ - ret = ret ?: pman_attach_syscall_enter_dispatcher(); - ret = ret ?: pman_attach_syscall_exit_dispatcher(); if(ret) { std::cout << "\n* Error in the bpf probe setup, TESTS not started!" << std::endl; diff --git a/test/modern_bpf/test_suites/generic_tracepoints_suite/sched_process_fork.cpp b/test/modern_bpf/test_suites/generic_tracepoints_suite/sched_process_fork.cpp index b254cc9772..1d7283060c 100644 --- a/test/modern_bpf/test_suites/generic_tracepoints_suite/sched_process_fork.cpp +++ b/test/modern_bpf/test_suites/generic_tracepoints_suite/sched_process_fork.cpp @@ -41,8 +41,6 @@ TEST(GenericTracepoints, sched_proc_fork_case_clone3) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - evt_test->assert_event_presence(pid); if(HasFatalFailure()) @@ -145,6 +143,8 @@ TEST(GenericTracepoints, sched_proc_fork_case_clone3) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif /* __NR_clone3 */ @@ -196,8 +196,6 @@ TEST(GenericTracepoints, sched_proc_fork_case_clone) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - evt_test->assert_event_presence(pid); if(HasFatalFailure()) @@ -300,6 +298,8 @@ TEST(GenericTracepoints, sched_proc_fork_case_clone) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif /* __NR_clone */ @@ -334,8 +334,6 @@ TEST(GenericTracepoints, sched_proc_fork_case_fork) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - evt_test->assert_event_presence(pid); if(HasFatalFailure()) @@ -438,6 +436,8 @@ TEST(GenericTracepoints, sched_proc_fork_case_fork) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif /* __NR_fork */ diff --git a/test/modern_bpf/test_suites/local_suite/ring_buffer.cpp b/test/modern_bpf/test_suites/local_suite/ring_buffer.cpp index 2f9334c979..af9f939f78 100644 --- a/test/modern_bpf/test_suites/local_suite/ring_buffer.cpp +++ b/test/modern_bpf/test_suites/local_suite/ring_buffer.cpp @@ -67,6 +67,8 @@ TEST(Local, ring_buffer_overwrite) ASSERT_EQ(prev_len, evt->len); ASSERT_EQ(prev_type, evt->type); ASSERT_EQ(prev_nparams, evt->nparams); + + evt_test->disable_capture(); } #endif diff --git a/test/modern_bpf/test_suites/syscall_exit_suite/clone3_x.cpp b/test/modern_bpf/test_suites/syscall_exit_suite/clone3_x.cpp index 5ab716126d..ef5c9b25f8 100644 --- a/test/modern_bpf/test_suites/syscall_exit_suite/clone3_x.cpp +++ b/test/modern_bpf/test_suites/syscall_exit_suite/clone3_x.cpp @@ -165,8 +165,6 @@ TEST(SyscallExit, clone3X_child) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - /* In some architectures we are not able to catch the `clone exit child * event` from the `sys_exit` tracepoint. This is because there is no * default behavior among different architectures... you can find more @@ -277,6 +275,8 @@ TEST(SyscallExit, clone3X_child) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif diff --git a/test/modern_bpf/test_suites/syscall_exit_suite/clone_x.cpp b/test/modern_bpf/test_suites/syscall_exit_suite/clone_x.cpp index f54c34cdb7..06316210d8 100644 --- a/test/modern_bpf/test_suites/syscall_exit_suite/clone_x.cpp +++ b/test/modern_bpf/test_suites/syscall_exit_suite/clone_x.cpp @@ -211,8 +211,6 @@ TEST(SyscallExit, cloneX_child) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - /* In some architectures we are not able to catch the `clone exit child * event` from the `sys_exit` tracepoint. This is because there is no * default behavior among different architectures... you can find more @@ -325,6 +323,8 @@ TEST(SyscallExit, cloneX_child) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif /* CAPTURE_SCHED_PROC_FORK */ diff --git a/test/modern_bpf/test_suites/syscall_exit_suite/fork_x.cpp b/test/modern_bpf/test_suites/syscall_exit_suite/fork_x.cpp index fd08f94e00..d726fdaae6 100644 --- a/test/modern_bpf/test_suites/syscall_exit_suite/fork_x.cpp +++ b/test/modern_bpf/test_suites/syscall_exit_suite/fork_x.cpp @@ -152,8 +152,6 @@ TEST(SyscallExit, forkX_child) exit(EXIT_FAILURE); } - evt_test->disable_capture(); - #ifdef CAPTURE_SCHED_PROC_FORK evt_test->assert_event_absence(pid); #else @@ -261,6 +259,8 @@ TEST(SyscallExit, forkX_child) FAIL() << "Something in the child failed." << std::endl; } + evt_test->disable_capture(); + /*=============================== TRIGGER SYSCALL ===========================*/ } #endif diff --git a/userspace/libpman/CMakeLists.txt b/userspace/libpman/CMakeLists.txt index 0359207778..a73f9d1c4c 100644 --- a/userspace/libpman/CMakeLists.txt +++ b/userspace/libpman/CMakeLists.txt @@ -17,6 +17,7 @@ set(PMAN_PRIVATE_INCLUDES "${LIBSCAP_DIR}/driver/" ## ppm_enum and tables "${LIBSCAP_DIR}/userspace/libscap" ## scap-stats struct "${LIBSCAP_DIR}/driver/modern_bpf/" ## bpf-shared structs + "./include" ) set(PMAN_PUBLIC_INCLUDES diff --git a/userspace/libpman/include/libpman.h b/userspace/libpman/include/libpman.h index 32438f48be..36d94dc6c8 100644 --- a/userspace/libpman/include/libpman.h +++ b/userspace/libpman/include/libpman.h @@ -105,6 +105,12 @@ extern "C" */ int pman_detach_all_programs(void); + /** + * @brief Update single program state, + * attaching or detaching it. + */ + int pman_update_single_program(int tp, bool enabled); + /** * @brief Attach only the syscall_exit_dispatcher * @@ -232,13 +238,13 @@ extern "C" * @brief Enable BPF-capture if we have previously * disabled it. */ - void pman_enable_capture(void); + int pman_enable_capture(bool *tp_set); /** * @brief Disable BPF capture for example when we * want to dump a particular event. */ - void pman_disable_capture(void); + int pman_disable_capture(void); /** * @brief Receive a pointer to `struct scap_stats` and fill it diff --git a/userspace/libpman/src/capture.c b/userspace/libpman/src/capture.c index b14453ee20..8a65d7d43f 100644 --- a/userspace/libpman/src/capture.c +++ b/userspace/libpman/src/capture.c @@ -17,15 +17,30 @@ limitations under the License. #include "state.h" #include +#include -void pman_enable_capture() +int pman_enable_capture(bool *tp_set) { - g_state.skel->bss->g_settings.capture_enabled = true; + if (!tp_set) + { + return pman_attach_all_programs(); + } + + int ret = 0; + /* Enable requested tracepoints */ + for (int i = 0; i < TP_VAL_MAX && ret == 0; i++) + { + if (tp_set[i]) + { + ret = pman_update_single_program(i, true); + } + } + return ret; } -void pman_disable_capture() +int pman_disable_capture() { - g_state.skel->bss->g_settings.capture_enabled = false; + return pman_detach_all_programs(); } #ifdef TEST_HELPERS @@ -140,4 +155,4 @@ int pman_get_n_tracepoint_hit(long *n_events_per_cpu) clean_print_stats: close(counter_maps_fd); return errno; -} \ No newline at end of file +} diff --git a/userspace/libpman/src/programs.c b/userspace/libpman/src/programs.c index 9e282b4e2a..c435f5122a 100644 --- a/userspace/libpman/src/programs.c +++ b/userspace/libpman/src/programs.c @@ -17,11 +17,94 @@ limitations under the License. #include "state.h" #include +#include +#include /* Some notes about how a bpf program must be detached without unloading it: * https://lore.kernel.org/bpf/CAEf4BzZ8=dV0wvggAKnD64yXnhcXhdf1ovCT_LBd17RtJJXrdA@mail.gmail.com/T/ */ +int pman_update_single_program(int tp, bool enabled) +{ + int ret = 0; + switch(tp) + { + case SYS_ENTER: + if (enabled) + { + ret = pman_attach_syscall_enter_dispatcher(); + } + else + { + ret = pman_detach_syscall_enter_dispatcher(); + } + break; + + case SYS_EXIT: + if (enabled) + { + ret = pman_attach_syscall_exit_dispatcher(); + } + else + { + ret = pman_detach_syscall_exit_dispatcher(); + } + break; + case SCHED_PROC_EXIT: + if (enabled) + { + ret = pman_attach_sched_proc_exit(); + } + else + { + ret = pman_detach_sched_proc_exit(); + } + break; + + case SCHED_SWITCH: + if (enabled) + { + ret = pman_attach_sched_switch(); + } + else + { + ret = pman_detach_sched_switch(); + } + break; + +#ifdef CAPTURE_SCHED_PROC_EXEC + case SCHED_PROC_EXEC: + if (enabled) + { + ret = pman_attach_sched_proc_exec(); + } + else + { + ret = pman_detach_sched_proc_exec(); + } + break; +#endif + +#ifdef CAPTURE_SCHED_PROC_FORK + case SCHED_PROC_FORK: + if (enabled) + { + ret = pman_attach_sched_proc_fork(); + } + else + { + ret = pman_detach_sched_proc_fork(); + } + break; +#endif + + default: + /* Do nothing right now. */ + break; + } + return ret; +} + /*=============================== ATTACH PROGRAMS ===============================*/ int pman_attach_syscall_enter_dispatcher() @@ -132,19 +215,12 @@ int pman_attach_sched_proc_fork() int pman_attach_all_programs() { - int err; - err = pman_attach_syscall_enter_dispatcher(); - err = err ?: pman_attach_syscall_exit_dispatcher(); - err = err ?: pman_attach_sched_proc_exit(); - err = err ?: pman_attach_sched_switch(); -#ifdef CAPTURE_SCHED_PROC_EXEC - err = err ?: pman_attach_sched_proc_exec(); -#endif -#ifdef CAPTURE_SCHED_PROC_FORK - err = err ?: pman_attach_sched_proc_fork(); -#endif - /* add all other programs. */ - return err; + int ret = 0; + for (int i = 0; i < TP_VAL_MAX && ret == 0; i++) + { + ret = pman_update_single_program(i, true); + } + return ret; } /*=============================== ATTACH PROGRAMS ===============================*/ @@ -223,19 +299,13 @@ int pman_detach_sched_proc_fork() int pman_detach_all_programs() { - int err; - err = pman_detach_syscall_enter_dispatcher(); - err = err ?: pman_detach_syscall_exit_dispatcher(); - err = err ?: pman_detach_sched_proc_exit(); - err = err ?: pman_detach_sched_switch(); -#ifdef CAPTURE_SCHED_PROC_EXEC - err = err ?: pman_detach_sched_proc_exec(); -#endif -#ifdef CAPTURE_SCHED_PROC_FORK - err = err ?: pman_detach_sched_proc_fork(); -#endif - /* add all other programs. */ - return err; + int ret = 0; + for (int i = 0; i < TP_VAL_MAX && ret == 0; i++) + { + ret = pman_update_single_program(i, false); + + } + return ret; } /*=============================== DETACH PROGRAMS ===============================*/ diff --git a/userspace/libscap/engine/bpf/bpf.h b/userspace/libscap/engine/bpf/bpf.h index bb31ae18f7..39aacdf063 100644 --- a/userspace/libscap/engine/bpf/bpf.h +++ b/userspace/libscap/engine/bpf/bpf.h @@ -20,7 +20,7 @@ limitations under the License. #include #include #include "../../ringbuffer/devset.h" -#include "../../../../driver/ppm_events_public.h" +#include "scap_open.h" // // ebpf defs @@ -48,6 +48,11 @@ struct bpf_engine 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 + /* ELF related */ + int program_fd; + Elf *elf; + GElf_Ehdr ehdr; + + interesting_tp_set open_tp_set; +}; \ No newline at end of file diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 6324aad58c..b2ad4a671f 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -33,6 +33,8 @@ limitations under the License. #include #include +#define SCAP_HANDLE_T struct bpf_engine + #include "bpf.h" #include "engine_handle.h" #include "scap.h" @@ -71,6 +73,8 @@ static inline void scap_bpf_advance_to_next_evt(scap_device* dev, scap_evt *even #include "ringbuffer/ringbuffer.h" #endif +static int32_t scap_bpf_handle_tp_mask(struct scap_engine_handle engine, uint32_t op, uint32_t tp); + // // Some of this code is taken from the kernel samples under samples/bpf, // namely the parsing of the ELF objects, which is very tedious and not @@ -108,7 +112,7 @@ static void free_handle(struct scap_engine_handle engine) # define UINT32_MAX (4294967295U) -/* Recommended log buffer size. +/* Recommended log buffer size. * Taken from libbpf source code: https://github.com/libbpf/libbpf/blob/67a4b1464349345e483df26ed93f8d388a60cee1/src/bpf.h#L201 */ static const int BPF_LOG_SIZE = UINT32_MAX >> 8; /* verifier maximum in kernels <= 5.1 */ @@ -141,7 +145,7 @@ static int32_t lookup_filler_id(const char *filler_name) { int j; - /* In our table we must have a filler_name corresponding to the final + /* In our table we must have a filler_name corresponding to the final * part of the elf section. */ for(j = 0; j < sizeof(g_filler_names) / sizeof(g_filler_names[0]); ++j) @@ -246,7 +250,7 @@ static int bpf_load_program(const struct bpf_insn *insns, return fd; } - /* Try a second time catching verifier logs. This step is performed + /* Try a second time catching verifier logs. This step is performed * only if we have a buffer for collecting them (so only if we * pass to `bpf_load_program()` function a `log_buf`!= NULL). */ @@ -574,7 +578,7 @@ static int32_t load_tracepoint(struct bpf_engine* handle, const char *event, str return SCAP_FAILURE; } - /* Fill the tail table. The key is our filler internal code extracted + /* Fill the tail table. The key is our filler internal code extracted * from `g_filler_names` in `lookup_filler_id` function. The value * is the program fd. */ @@ -665,8 +669,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, uint64_t *api_version_p, - uint64_t *schema_version_p, - scap_open_args *oargs) + uint64_t *schema_version_p) { int j; int maps_shndx = 0; @@ -697,126 +700,144 @@ static int32_t load_bpf_file( return SCAP_FAILURE; } - 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", handle->m_filepath, scap_strerror_r(buf, errno)); - return SCAP_FAILURE; - } - - Elf *elf = elf_begin(program_fd, ELF_C_READ_MMAP_PRIVATE, NULL); - if(!elf) + if (!handle->elf) { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't read ELF format"); - goto cleanup; - } - - GElf_Ehdr ehdr; - if(gelf_getehdr(elf, &ehdr) != &ehdr) - { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't read ELF header"); - goto cleanup; - } - - for(j = 0; j < ehdr.e_shnum; ++j) - { - if(get_elf_section(elf, j, &ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) + handle->program_fd = open(handle->m_filepath, O_RDONLY, 0); + if(handle->program_fd < 0) { - continue; + char buf[SCAP_LASTERR_SIZE]; + 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; } - if(strcmp(shname, "maps") == 0) + handle->elf = elf_begin(handle->program_fd, ELF_C_READ_MMAP_PRIVATE, NULL); + if(!handle->elf) { - maps_shndx = j; + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't read ELF format"); + goto end; } - else if(shdr.sh_type == SHT_SYMTAB) + + if(gelf_getehdr(handle->elf, &handle->ehdr) != &handle->ehdr) { - strtabidx = shdr.sh_link; - symbols = data; + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "can't read ELF header"); + goto end; } - else if(strcmp(shname, "kernel_version") == 0) { - if(strcmp(osname.release, data->d_buf)) + + for(j = 0; j < handle->ehdr.e_shnum; ++j) + { + if(get_elf_section(handle->elf, j, &handle->ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "BPF probe is compiled for %s, but running version is %s", - (char *) data->d_buf, osname.release); - goto cleanup; + continue; + } + + if(strcmp(shname, "maps") == 0) + { + maps_shndx = j; + } + else if(shdr.sh_type == SHT_SYMTAB) + { + strtabidx = shdr.sh_link; + symbols = data; + } + else if(strcmp(shname, "kernel_version") == 0) + { + if(strcmp(osname.release, data->d_buf)) + { + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "BPF probe is compiled for %s, but running version is %s", + (char *)data->d_buf, osname.release); + goto end; + } + } + else if(strcmp(shname, "api_version") == 0) + { + got_api_version = true; + memcpy(api_version_p, data->d_buf, sizeof(*api_version_p)); + } + else if(strcmp(shname, "schema_version") == 0) + { + got_schema_version = true; + memcpy(schema_version_p, data->d_buf, sizeof(*schema_version_p)); + } + else if(strcmp(shname, "license") == 0) + { + license = data->d_buf; + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "BPF probe license is %s", license); } } - else if(strcmp(shname, "api_version") == 0) { - got_api_version = true; - memcpy(api_version_p, data->d_buf, sizeof(*api_version_p)); - } - else if(strcmp(shname, "schema_version") == 0) { - got_schema_version = true; - memcpy(schema_version_p, data->d_buf, sizeof(*schema_version_p)); - } - else if(strcmp(shname, "license") == 0) + + if(!got_api_version) { - license = data->d_buf; - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "BPF probe license is %s", license); + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing api_version section"); + goto end; } - } - if(!got_api_version) - { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing api_version section"); - goto cleanup; - } - - if(!got_schema_version) - { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing schema_version section"); - goto cleanup; - } - - if(!symbols) - { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing SHT_SYMTAB section"); - goto cleanup; - } - - if(maps_shndx) - { - if(load_elf_maps_section(handle, maps, maps_shndx, elf, symbols, strtabidx, &nr_maps) != SCAP_SUCCESS) + if(!got_schema_version) { - goto cleanup; + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing schema_version section"); + goto end; } - if(load_maps(handle, maps, nr_maps) != SCAP_SUCCESS) + if(!symbols) { - goto cleanup; + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing SHT_SYMTAB section"); + goto end; } - } - for(j = 0; j < ehdr.e_shnum; ++j) - { - if(get_elf_section(elf, j, &ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) + if(maps_shndx) { - continue; + if(load_elf_maps_section(handle, maps, maps_shndx, handle->elf, symbols, strtabidx, &nr_maps) != SCAP_SUCCESS) + { + goto end; + } + + if(load_maps(handle, maps, nr_maps) != SCAP_SUCCESS) + { + goto end; + } } - if(shdr.sh_type == SHT_REL) + for(j = 0; j < handle->ehdr.e_shnum; ++j) { - struct bpf_insn *insns; - - if(get_elf_section(elf, shdr.sh_info, &ehdr, &shname_prog, &shdr_prog, &data_prog) != SCAP_SUCCESS) + if(get_elf_section(handle->elf, j, &handle->ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) { continue; } - insns = (struct bpf_insn *) data_prog->d_buf; - - if(parse_relocations(handle, data, symbols, &shdr, insns, maps, nr_maps)) + if(shdr.sh_type == SHT_REL) { - continue; + struct bpf_insn *insns; + + if(get_elf_section(handle->elf, shdr.sh_info, &handle->ehdr, &shname_prog, &shdr_prog, &data_prog) != SCAP_SUCCESS) + { + continue; + } + + insns = (struct bpf_insn *)data_prog->d_buf; + + if(parse_relocations(handle, data, symbols, &shdr, insns, maps, nr_maps)) + { + continue; + } } } } + res = SCAP_SUCCESS; +end: + return res; +} - for(j = 0; j < ehdr.e_shnum; ++j) +static int load_tracepoints(struct bpf_engine *handle, + interesting_tp_set *tp_of_interest) +{ + int j; + int32_t res = SCAP_FAILURE; + GElf_Shdr shdr; + Elf_Data *data; + char *shname; + + for(j = 0; j < handle->ehdr.e_shnum; ++j) { - if(get_elf_section(elf, j, &ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) + if(get_elf_section(handle->elf, j, &handle->ehdr, &shname, &shdr, &data) != SCAP_SUCCESS) { continue; } @@ -824,7 +845,7 @@ static int32_t load_bpf_file( if(memcmp(shname, "tracepoint/", sizeof("tracepoint/") - 1) == 0 || memcmp(shname, "raw_tracepoint/", sizeof("raw_tracepoint/") - 1) == 0) { - if(is_tp_enabled(&(oargs->tp_of_interest), shname)) + if(is_tp_enabled(tp_of_interest, shname)) { bool already_attached = false; for (int i = 0; i < handle->m_bpf_prog_cnt && !already_attached; i++) @@ -839,17 +860,14 @@ static int32_t load_bpf_file( { if(load_tracepoint(handle, shname, data->d_buf, data->d_size) != SCAP_SUCCESS) { - goto cleanup; + goto end; } } } } } - res = SCAP_SUCCESS; -cleanup: - elf_end(elf); - close(program_fd); +end: return res; } @@ -989,7 +1007,7 @@ static int32_t populate_fillers_table_map(struct bpf_engine *handle) } } - /* Even if the filler ppm code is defined it could happen that there + /* Even if the filler ppm code is defined it could happen that there * is no filler implementation, some fillers are architecture-specifc. * For example `sched_prog_exec` filler exists only on `ARM64` while * `sys_pagefault_e` exists only on `x86`. @@ -1019,20 +1037,19 @@ static int32_t calibrate_socket_file_ops() int32_t scap_bpf_start_capture(struct scap_engine_handle engine) { struct bpf_engine* handle = engine.m_handle; - struct scap_bpf_settings settings; - int k = 0; - if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0) + /* Enable requested tracepoints */ + int ret = SCAP_SUCCESS; + for (int i = 0; i < TP_VAL_MAX && ret == SCAP_SUCCESS; i++) { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0"); - return SCAP_FAILURE; + if (handle->open_tp_set.tp[i]) + { + ret = scap_bpf_handle_tp_mask(engine, SCAP_TPMASK_SET, i); + } } - - settings.capture_enabled = true; - if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0) + if (ret != SCAP_SUCCESS) { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0"); - return SCAP_FAILURE; + return ret; } if(calibrate_socket_file_ops() != SCAP_SUCCESS) @@ -1047,24 +1064,13 @@ int32_t scap_bpf_start_capture(struct scap_engine_handle engine) int32_t scap_bpf_stop_capture(struct scap_engine_handle engine) { - struct bpf_engine* handle = engine.m_handle; - struct scap_bpf_settings settings; - int k = 0; - - if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0) + /* Disable all tracepoints */ + int ret = SCAP_SUCCESS; + for (int i = 0; i < TP_VAL_MAX && ret == SCAP_SUCCESS; i++) { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0"); - return SCAP_FAILURE; - } - - settings.capture_enabled = false; - if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0) - { - snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0"); - return SCAP_FAILURE; + ret = scap_bpf_handle_tp_mask(engine, SCAP_TPMASK_UNSET, i); } - - return SCAP_SUCCESS; + return ret; } int32_t scap_bpf_set_snaplen(struct scap_engine_handle engine, uint32_t snaplen) @@ -1308,6 +1314,17 @@ int32_t scap_bpf_close(struct scap_engine_handle engine) handle->m_bpf_prog_cnt = 0; handle->m_bpf_prog_array_map_idx = -1; + if (handle->elf) + { + elf_end(handle->elf); + handle->elf = NULL; + } + if (handle->program_fd > 0) + { + close(handle->program_fd); + handle->program_fd = -1; + } + return SCAP_SUCCESS; } @@ -1390,7 +1407,6 @@ static int32_t set_default_settings(struct bpf_engine *handle) settings.socket_file_ops = NULL; settings.snaplen = RW_SNAPLEN; settings.sampling_ratio = 1; - settings.capture_enabled = false; settings.do_dynamic_snaplen = false; settings.dropping_mode = false; settings.is_dropping = false; @@ -1435,7 +1451,17 @@ int32_t scap_bpf_load( } snprintf(handle->m_filepath, PATH_MAX, "%s", bpf_probe); - if(load_bpf_file(handle, api_version_p, schema_version_p, oargs) != SCAP_SUCCESS) + + if(load_bpf_file(handle, api_version_p, schema_version_p) != SCAP_SUCCESS) + { + return SCAP_FAILURE; + } + + /* Store interesting Tracepoints */ + memcpy(&handle->open_tp_set, &oargs->tp_of_interest, sizeof(interesting_tp_set)); + /* Start with all tracepoints disabled */ + interesting_tp_set initial_tp_set = {0}; + if (load_tracepoints(handle, &initial_tp_set) != SCAP_SUCCESS) { return SCAP_FAILURE; } @@ -1691,11 +1717,9 @@ static int32_t scap_bpf_handle_tp_mask(struct scap_engine_handle engine, uint32_ 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); + interesting_tp_set new_tp_set = {0}; + new_tp_set.tp[tp] = 1; + return load_tracepoints(handle, &new_tp_set); } static int32_t scap_bpf_handle_event_mask(struct scap_engine_handle engine, uint32_t op, uint32_t ppm_sc) @@ -1709,7 +1733,7 @@ static int32_t scap_bpf_handle_event_mask(struct scap_engine_handle engine, uint ret = update_interesting_syscalls_map(engine, SCAP_EVENTMASK_UNSET, ppm_sc); } break; - + case SCAP_EVENTMASK_SET: case SCAP_EVENTMASK_UNSET: ret = update_interesting_syscalls_map(engine, op, ppm_sc); diff --git a/userspace/libscap/engine/kmod/kmod.h b/userspace/libscap/engine/kmod/kmod.h index 5b6031c829..48e00fa0b8 100644 --- a/userspace/libscap/engine/kmod/kmod.h +++ b/userspace/libscap/engine/kmod/kmod.h @@ -18,11 +18,11 @@ limitations under the License. #include #include "ringbuffer/devset.h" - -struct scap; +#include "scap_open.h" struct kmod_engine { struct scap_device_set m_dev_set; char* m_lasterr; + interesting_tp_set open_tp_set; }; diff --git a/userspace/libscap/engine/kmod/scap_kmod.c b/userspace/libscap/engine/kmod/scap_kmod.c index 9726aa32a0..21e0484b80 100644 --- a/userspace/libscap/engine/kmod/scap_kmod.c +++ b/userspace/libscap/engine/kmod/scap_kmod.c @@ -418,12 +418,8 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs) scap_kmod_handle_event_mask(engine, op, ppm_sc); } - /* Set interesting Tracepoints */ - for (int i = 0; i < TP_VAL_MAX; i++) - { - uint32_t op = oargs->tp_of_interest.tp[i] ? SCAP_TPMASK_SET : SCAP_TPMASK_UNSET; - scap_kmod_handle_tp_mask(engine, op, i); - } + /* Store interesting Tracepoints */ + memcpy(&engine.m_handle->open_tp_set, &oargs->tp_of_interest, sizeof(interesting_tp_set)); return SCAP_SUCCESS; } @@ -491,26 +487,13 @@ return SCAP_SUCCESS; // int32_t scap_kmod_stop_capture(struct scap_engine_handle engine) { - uint32_t j; - - struct scap_device_set *devset = &engine.m_handle->m_dev_set; - // - // Disable capture on all the rings - // - for(j = 0; j < devset->m_ndevs; j++) + /* Disable all tracepoints */ + int ret = SCAP_SUCCESS; + for (int i = 0; i < TP_VAL_MAX && ret == SCAP_SUCCESS; i++) { - struct scap_device *dev = &devset->m_devs[j]; - { - if(ioctl(dev->m_fd, PPM_IOCTL_DISABLE_CAPTURE)) - { - snprintf(engine.m_handle->m_lasterr, SCAP_LASTERR_SIZE, "scap_stop_capture failed for device %" PRIu32, j); - ASSERT(false); - return SCAP_FAILURE; - } - } + ret = scap_kmod_handle_tp_mask(engine, SCAP_TPMASK_UNSET, i); } - - return SCAP_SUCCESS; + return ret; } // @@ -518,19 +501,19 @@ int32_t scap_kmod_stop_capture(struct scap_engine_handle engine) // int32_t scap_kmod_start_capture(struct scap_engine_handle engine) { - uint32_t j; - struct scap_device_set *devset = &engine.m_handle->m_dev_set; - for(j = 0; j < devset->m_ndevs; j++) + struct kmod_engine* handle = engine.m_handle; + + /* Enable requested tracepoints */ + int ret = SCAP_SUCCESS; + for (int i = 0; i < TP_VAL_MAX && ret == SCAP_SUCCESS; i++) { - if(ioctl(devset->m_devs[j].m_fd, PPM_IOCTL_ENABLE_CAPTURE)) + if (handle->open_tp_set.tp[i]) { - snprintf(engine.m_handle->m_lasterr, SCAP_LASTERR_SIZE, "scap_start_capture failed for device %" PRIu32, j); - ASSERT(false); - return SCAP_FAILURE; + ret = scap_kmod_handle_tp_mask(engine, SCAP_TPMASK_SET, i); } } - return SCAP_SUCCESS; + return ret; } static int32_t scap_kmod_set_dropping_mode(struct scap_engine_handle engine, int request, uint32_t sampling_ratio) diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c index a0a296cd16..5c2c831040 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c @@ -20,6 +20,7 @@ limitations under the License. #include #include "scap_modern_bpf.h" +#define SCAP_HANDLE_T struct modern_bpf_engine #include "scap.h" #include "scap-int.h" #include "scap_procs.h" @@ -34,107 +35,6 @@ limitations under the License. /*=============================== UTILS ===============================*/ -static int32_t update_single_tp_of_interest(int tp, bool interesting) -{ - int ret = SCAP_SUCCESS; - switch(tp) - { - case SYS_ENTER: - if (interesting) - { - ret = pman_attach_syscall_enter_dispatcher(); - } - else - { - ret = pman_detach_syscall_enter_dispatcher(); - } - break; - - case SYS_EXIT: - if (interesting) - { - ret = pman_attach_syscall_exit_dispatcher(); - } - else - { - ret = pman_detach_syscall_exit_dispatcher(); - } - break; - case SCHED_PROC_EXIT: - if (interesting) - { - ret = pman_attach_sched_proc_exit(); - } - else - { - ret = pman_detach_sched_proc_exit(); - } - break; - - case SCHED_SWITCH: - if (interesting) - { - ret = pman_attach_sched_switch(); - } - else - { - ret = pman_detach_sched_switch(); - } - break; - -#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 - -#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 - - 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; -} - static void update_single_64bit_syscall_of_interest(int ppm_sc, bool interesting) { for(int syscall_nr = 0; syscall_nr < SYSCALL_TABLE_SIZE; syscall_nr++) @@ -264,7 +164,7 @@ static int32_t scap_modern_bpf__configure(struct scap_engine_handle engine, enum } return SCAP_SUCCESS; case SCAP_TPMASK: - return update_single_tp_of_interest(arg2, arg1 == SCAP_TPMASK_SET); + return pman_update_single_program(arg2, arg1 == SCAP_TPMASK_SET); case SCAP_DYNAMIC_SNAPLEN: /* Not supported */ return SCAP_SUCCESS; @@ -289,14 +189,13 @@ static int32_t scap_modern_bpf__configure(struct scap_engine_handle engine, enum int32_t scap_modern_bpf__start_capture(struct scap_engine_handle engine) { - pman_enable_capture(); - return SCAP_SUCCESS; + struct modern_bpf_engine* handle = engine.m_handle; + return pman_enable_capture(handle->open_tp_set.tp); } int32_t scap_modern_bpf__stop_capture(struct scap_engine_handle engine) { - pman_disable_capture(); - return SCAP_SUCCESS; + return pman_disable_capture(); } int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) @@ -340,12 +239,15 @@ int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) ret = ret ?: pman_finalize_maps_after_loading(); ret = ret ?: pman_finalize_ringbuf_array_after_loading(); ret = ret ?: populate_64bit_interesting_syscalls_table(oargs->ppm_sc_of_interest.ppm_sc); - ret = ret ?: attach_interesting_tracepoints(oargs->tp_of_interest.tp); + // Do not attach tracepoints at this stage. if(ret != SCAP_SUCCESS) { return ret; } + /* Store interesting Tracepoints */ + memcpy(&engine.m_handle->open_tp_set, &oargs->tp_of_interest, sizeof(interesting_tp_set)); + /* Set the boot time */ uint64_t boot_time = 0; if(scap_get_boot_time(handle->m_lasterr, &boot_time) != SCAP_SUCCESS) diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.h b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.h index bd8d8d5adf..b88c0288f4 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.h +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.h @@ -20,6 +20,7 @@ limitations under the License. #include #include #include "../../../../driver/ppm_events_public.h" +#include "scap_open.h" struct scap; @@ -27,6 +28,5 @@ struct modern_bpf_engine { size_t m_num_cpus; char* m_lasterr; + interesting_tp_set open_tp_set; }; - -#define SCAP_HANDLE_T struct modern_bpf_engine diff --git a/userspace/libscap/engine/nodriver/nodriver.c b/userspace/libscap/engine/nodriver/nodriver.c index 5ea444f0dd..9ef395a48c 100644 --- a/userspace/libscap/engine/nodriver/nodriver.c +++ b/userspace/libscap/engine/nodriver/nodriver.c @@ -18,6 +18,8 @@ limitations under the License. #include #include +#define SCAP_HANDLE_T struct nodriver_engine + #include "nodriver.h" #include "noop.h" diff --git a/userspace/libscap/engine/nodriver/nodriver.h b/userspace/libscap/engine/nodriver/nodriver.h index bf367db839..1c9dda432c 100644 --- a/userspace/libscap/engine/nodriver/nodriver.h +++ b/userspace/libscap/engine/nodriver/nodriver.h @@ -23,6 +23,4 @@ struct scap; struct nodriver_engine { char* m_lasterr; -}; - -#define SCAP_HANDLE_T struct nodriver_engine +}; \ No newline at end of file diff --git a/userspace/libscap/engine/savefile/savefile.h b/userspace/libscap/engine/savefile/savefile.h index 73cb1e0817..6bc76523ae 100644 --- a/userspace/libscap/engine/savefile/savefile.h +++ b/userspace/libscap/engine/savefile/savefile.h @@ -21,8 +21,6 @@ limitations under the License. #include "scap_reader.h" #include "scap_savefile.h" -#define SCAP_HANDLE_T struct savefile_engine - typedef struct _scap_machine_info scap_machine_info; struct scap_proclist; struct scap_addrlist; diff --git a/userspace/libscap/engine/savefile/scap_savefile.c b/userspace/libscap/engine/savefile/scap_savefile.c index 1a44d3c4d8..6a2dd23f62 100644 --- a/userspace/libscap/engine/savefile/scap_savefile.c +++ b/userspace/libscap/engine/savefile/scap_savefile.c @@ -30,6 +30,7 @@ struct iovec { #endif #include "../common/strlcpy.h" +#define SCAP_HANDLE_T struct savefile_engine #include "savefile.h" #include "scap.h" #include "scap-int.h" diff --git a/userspace/libscap/engine/source_plugin/source_plugin.c b/userspace/libscap/engine/source_plugin/source_plugin.c index 407f09a656..c028e823a2 100644 --- a/userspace/libscap/engine/source_plugin/source_plugin.c +++ b/userspace/libscap/engine/source_plugin/source_plugin.c @@ -15,6 +15,8 @@ limitations under the License. */ +#define SCAP_HANDLE_T struct source_plugin_engine + #include #include diff --git a/userspace/libscap/engine/source_plugin/source_plugin.h b/userspace/libscap/engine/source_plugin/source_plugin.h index f22383ab9f..ac7b96ae5e 100644 --- a/userspace/libscap/engine/source_plugin/source_plugin.h +++ b/userspace/libscap/engine/source_plugin/source_plugin.h @@ -47,6 +47,4 @@ struct source_plugin_engine // The return value from the last call to next_batch(). ss_plugin_rc m_input_plugin_last_batch_res; -}; - -#define SCAP_HANDLE_T struct source_plugin_engine +}; \ No newline at end of file diff --git a/userspace/libscap/engine/udig/scap_udig.c b/userspace/libscap/engine/udig/scap_udig.c index 23cb360bb4..187c4435bb 100644 --- a/userspace/libscap/engine/udig/scap_udig.c +++ b/userspace/libscap/engine/udig/scap_udig.c @@ -17,6 +17,8 @@ #include #endif // _WIN32 +#define SCAP_HANDLE_T struct udig_engine + #include "../common/strlcpy.h" #include "udig.h" #include "scap.h" diff --git a/userspace/libscap/engine/udig/udig.h b/userspace/libscap/engine/udig/udig.h index d277c4a334..17e04e8221 100644 --- a/userspace/libscap/engine/udig/udig.h +++ b/userspace/libscap/engine/udig/udig.h @@ -32,5 +32,3 @@ struct udig_engine HANDLE m_win_descs_handle; #endif }; - -#define SCAP_HANDLE_T struct udig_engine diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 37863e7f77..5c87fe4544 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -98,7 +98,7 @@ struct iovec; // call `scap_get_driver_api_version()` and/or `scap_get_driver_schema_version()` // and handle the result // -#define SCAP_MINIMUM_DRIVER_API_VERSION PPM_API_VERSION(2, 0, 0) +#define SCAP_MINIMUM_DRIVER_API_VERSION PPM_API_VERSION(3, 0, 0) #define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(2, 0, 0) // diff --git a/userspace/libscap/scap_open.h b/userspace/libscap/scap_open.h index a89ee14ff4..85f203aa31 100644 --- a/userspace/libscap/scap_open.h +++ b/userspace/libscap/scap_open.h @@ -80,7 +80,7 @@ extern "C" * Set any tracepoint idx to true to enable its tracing at driver level, * otherwise a tp is not attached (so called "uninteresting tracepoint"). */ - typedef struct + typedef struct { bool tp[TP_VAL_MAX]; } interesting_tp_set;