diff --git a/driver/API_VERSION b/driver/API_VERSION index 0062ac9718..831446cbd2 100644 --- a/driver/API_VERSION +++ b/driver/API_VERSION @@ -1 +1 @@ -5.0.0 +5.1.0 diff --git a/driver/bpf/maps.h b/driver/bpf/maps.h index c5a6ee0c34..2016309b7a 100644 --- a/driver/bpf/maps.h +++ b/driver/bpf/maps.h @@ -90,6 +90,13 @@ struct bpf_map_def __bpf_section("maps") interesting_syscalls_table = { .max_entries = SYSCALL_TABLE_SIZE, }; +struct bpf_map_def __bpf_section("maps") sampling_exclude_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(bool), + .max_entries = SYSCALL_TABLE_SIZE, +}; + #ifndef BPF_SUPPORTS_RAW_TRACEPOINTS struct bpf_map_def __bpf_section("maps") stash_map = { .type = BPF_MAP_TYPE_HASH, diff --git a/driver/bpf/plumbing_helpers.h b/driver/bpf/plumbing_helpers.h index f111e54e6a..f83a92a5ba 100644 --- a/driver/bpf/plumbing_helpers.h +++ b/driver/bpf/plumbing_helpers.h @@ -493,6 +493,7 @@ static __always_inline bool drop_event(void *ctx, struct scap_bpf_settings *settings, enum syscall_flags drop_flags) { + long id; if (!settings->dropping_mode) return false; @@ -563,6 +564,12 @@ static __always_inline bool drop_event(void *ctx, if (drop_flags & UF_ALWAYS_DROP) return true; + id = bpf_syscall_get_nr(ctx); + bool *enabled = bpf_map_lookup_elem(&sampling_exclude_map, &id); + if (enabled && *enabled) { + return false; + } + if (state->tail_ctx.ts % 1000000000 >= 1000000000 / settings->sampling_ratio) { if (!settings->is_dropping) { diff --git a/driver/bpf/types.h b/driver/bpf/types.h index b8ac747cc5..b82f0b1711 100644 --- a/driver/bpf/types.h +++ b/driver/bpf/types.h @@ -224,8 +224,9 @@ enum scap_map_types { SCAP_SETTINGS_MAP = 7, SCAP_LOCAL_STATE_MAP = 8, SCAP_INTERESTING_SYSCALLS_TABLE = 9, + SCAP_SAMPLING_MAP = 10, #ifndef BPF_SUPPORTS_RAW_TRACEPOINTS - SCAP_STASH_MAP = 10, + SCAP_STASH_MAP = 11, #endif }; diff --git a/driver/main.c b/driver/main.c index 4cea5b04a4..0cf2b7876e 100644 --- a/driver/main.c +++ b/driver/main.c @@ -542,6 +542,7 @@ static int ppm_open(struct inode *inode, struct file *filp) consumer->fullcapture_port_range_end = 0; consumer->statsd_port = PPM_PORT_STATSD; bitmap_zero(consumer->syscalls_mask, SYSCALL_TABLE_SIZE); /* Start with no syscalls */ + bitmap_zero(consumer->sampling_mask, SYSCALL_TABLE_SIZE); reset_ring_buffer(ring); ring->open = true; @@ -1186,6 +1187,34 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = 0; goto cleanup_ioctl; } + case PPM_IOCTL_ADD_SAMPLING_EXCLUDE: + case PPM_IOCTL_DEL_SAMPLING_EXCLUDE: + { + u32 syscall_to_set = (u32)arg - SYSCALL_TABLE_ID0; + + vpr_info("PPM_IOCTL_ADD_DROP_EXCLUDE (%u), consumer %p\n", syscall_to_set, consumer_id); + + if (syscall_to_set >= SYSCALL_TABLE_SIZE) { + pr_err("invalid syscall %u\n", syscall_to_set); + ret = -EINVAL; + goto cleanup_ioctl; + } + if ((g_syscall_table[syscall_to_set].flags & (UF_NEVER_DROP | UF_ALWAYS_DROP))) { + ret = -EPERM; + goto cleanup_ioctl; + } + if (cmd == PPM_IOCTL_ADD_SAMPLING_EXCLUDE) + { + set_bit(syscall_to_set, consumer->sampling_mask); + } + else + { + clear_bit(syscall_to_set, consumer->sampling_mask); + } + ret = 0; + goto cleanup_ioctl; + } + default: ret = -ENOTTY; goto cleanup_ioctl; @@ -1660,6 +1689,7 @@ static inline int drop_nostate_event(ppm_event_code event_type, static inline int drop_event(struct ppm_consumer_t *consumer, ppm_event_code event_type, enum syscall_flags drop_flags, + long table_index, nanoseconds ns, struct pt_regs *regs) { @@ -1682,6 +1712,9 @@ static inline int drop_event(struct ppm_consumer_t *consumer, ASSERT((drop_flags & UF_NEVER_DROP) == 0); return 1; } + if (table_index != -1 && test_bit(table_index, consumer->sampling_mask)) { + return 0; + } if (consumer->sampling_interval < SECOND_IN_NS && /* do_div replaces ns2 with the quotient and returns the remainder */ @@ -1742,7 +1775,7 @@ static int record_event_consumer(struct ppm_consumer_t *consumer, int drop = 1; int32_t cbres = PPM_SUCCESS; int cpu; - long table_index; + long table_index = -1; int64_t retval; if (tp_type < INTERNAL_EVENTS && !(consumer->tracepoints_attached & (1 << tp_type))) @@ -1807,6 +1840,7 @@ static int record_event_consumer(struct ppm_consumer_t *consumer, if (drop_event(consumer, event_type, drop_flags, + table_index, ns, event_datap->event_info.syscall_data.regs)) return res; diff --git a/driver/ppm_consumer.h b/driver/ppm_consumer.h index 70801bce7d..c2e6940a53 100644 --- a/driver/ppm_consumer.h +++ b/driver/ppm_consumer.h @@ -36,6 +36,7 @@ struct ppm_consumer_t { unsigned long buffer_bytes_dim; /* Every consumer will have its per-CPU buffer dim in bytes. */ DECLARE_BITMAP(syscalls_mask, SYSCALL_TABLE_SIZE); u32 tracepoints_attached; + DECLARE_BITMAP(sampling_mask, SYSCALL_TABLE_SIZE); }; typedef struct ppm_consumer_t ppm_consumer_t; diff --git a/driver/ppm_events_public.h b/driver/ppm_events_public.h index 1b5d75ed35..9379e8dca0 100644 --- a/driver/ppm_events_public.h +++ b/driver/ppm_events_public.h @@ -2076,6 +2076,8 @@ struct ppm_evt_hdr { #define PPM_IOCTL_DISABLE_TP _IO(PPM_IOCTL_MAGIC, 32) #define PPM_IOCTL_ENABLE_DROPFAILED _IO(PPM_IOCTL_MAGIC, 33) #define PPM_IOCTL_DISABLE_DROPFAILED _IO(PPM_IOCTL_MAGIC, 34) +#define PPM_IOCTL_ADD_SAMPLING_EXCLUDE _IO(PPM_IOCTL_MAGIC, 35) +#define PPM_IOCTL_DEL_SAMPLING_EXCLUDE _IO(PPM_IOCTL_MAGIC, 36) #endif // CYGWING_AGENT extern const struct ppm_name_value socket_families[]; diff --git a/userspace/libpman/include/libpman.h b/userspace/libpman/include/libpman.h index 4d382875f9..bfef6d281b 100644 --- a/userspace/libpman/include/libpman.h +++ b/userspace/libpman/include/libpman.h @@ -445,6 +445,8 @@ extern "C" */ void pman_mark_single_64bit_syscall(int syscall_id, bool interesting); + + int pman_mark_syscall_sampling_exclude(int syscall_id, bool excluding); #ifdef __cplusplus } #endif diff --git a/userspace/libpman/src/maps.c b/userspace/libpman/src/maps.c index d71a878598..0288b55b66 100644 --- a/userspace/libpman/src/maps.c +++ b/userspace/libpman/src/maps.c @@ -108,6 +108,23 @@ void pman_mark_single_64bit_syscall(int intersting_syscall_id, bool interesting) g_state.skel->bss->g_64bit_interesting_syscalls_table[intersting_syscall_id] = interesting; } +int pman_mark_syscall_sampling_exclude(int syscall_id, bool excluding) +{ + if(g_syscall_table[syscall_id].flags & UF_NEVER_DROP) + { + return 1; + } + if(g_syscall_table[syscall_id].flags & UF_ALWAYS_DROP || g_syscall_table[syscall_id].flags == UF_NONE) + { + return 1; + } + if(g_syscall_table[syscall_id].flags & UF_USED) + { + g_state.skel->bss->g_64bit_sampling_syscall_table[syscall_id] = excluding ? UF_NEVER_DROP : 0; + } + return 0; +} + void pman_fill_syscall_sampling_table() { for(int syscall_id = 0; syscall_id < SYSCALL_TABLE_SIZE; syscall_id++) diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index f0396a9ad3..51923419c8 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -1836,6 +1836,31 @@ static int32_t next(struct scap_engine_handle engine, OUT scap_evt** pevent, OUT return ringbuffer_next(&engine.m_handle->m_dev_set, pevent, pcpuid); } +static int32_t scap_bpf_set_drop_exclude(struct scap_engine_handle engine, uint32_t op, uint32_t sc) +{ + struct bpf_engine* handle = engine.m_handle; + struct syscall_evt_pair sc_evt; + int ret; + bool exclude = (op == 1); + int syscall_id = scap_ppm_sc_to_native_id(sc); + if(syscall_id == -1) + { + return SCAP_FAILURE; + } + if ((ret = bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SYSCALL_TABLE], &syscall_id, &sc_evt)) != 0) + { + return scap_errprintf(handle->m_lasterr, -ret, "SCAP_SYSCALL_TABLE bpf_map_lookup_elem: %d", syscall_id); + } + if ((sc_evt.flags & (UF_NEVER_DROP | UF_ALWAYS_DROP))) { + return SCAP_FAILURE; + } + if ((ret = bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SAMPLING_MAP], &syscall_id, &exclude, BPF_ANY)) != 0) + { + return scap_errprintf(handle->m_lasterr, -ret, "SCAP_DROPPING_MAP unable to update: %d", syscall_id); + } + return SCAP_SUCCESS; +} + static int32_t unsupported_config(struct scap_engine_handle engine, const char* msg) { struct bpf_engine* handle = engine.m_handle; @@ -1917,6 +1942,8 @@ static int32_t configure(struct scap_engine_handle engine, enum scap_setting set return scap_bpf_set_fullcapture_port_range(engine, arg1, arg2); case SCAP_STATSD_PORT: return scap_bpf_set_statsd_port(engine, arg1); + case SCAP_SAMPLING_EXCLUDE: + return scap_bpf_set_drop_exclude(engine, arg1, arg2); default: { char msg[SCAP_LASTERR_SIZE]; diff --git a/userspace/libscap/engine/kmod/scap_kmod.c b/userspace/libscap/engine/kmod/scap_kmod.c index 47fc113280..ff43582a05 100644 --- a/userspace/libscap/engine/kmod/scap_kmod.c +++ b/userspace/libscap/engine/kmod/scap_kmod.c @@ -835,6 +835,17 @@ int32_t scap_kmod_set_statsd_port(struct scap_engine_handle engine, const uint16 return SCAP_SUCCESS; } +static int32_t scap_kmod_set_sampling_exclude(struct scap_engine_handle engine, uint32_t op, uint32_t sc) +{ + struct kmod_engine* handle = engine.m_handle; + int syscall_id = scap_ppm_sc_to_native_id(sc); + if(syscall_id == -1) + { + return SCAP_FAILURE; + } + return mark_syscall(handle, op == 1 ? PPM_IOCTL_ADD_SAMPLING_EXCLUDE : PPM_IOCTL_DEL_SAMPLING_EXCLUDE, syscall_id); +} + static int32_t unsupported_config(struct scap_engine_handle engine, const char* msg) { struct kmod_engine* handle = engine.m_handle; @@ -874,6 +885,8 @@ static int32_t configure(struct scap_engine_handle engine, enum scap_setting set return scap_kmod_set_fullcapture_port_range(engine, arg1, arg2); case SCAP_STATSD_PORT: return scap_kmod_set_statsd_port(engine, arg1); + case SCAP_SAMPLING_EXCLUDE: + return scap_kmod_set_sampling_exclude(engine, arg1, arg2); default: { char msg[256]; diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c index 797d867ec0..2ef53170d3 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c @@ -92,6 +92,16 @@ static int32_t scap_modern_bpf_handle_sc(struct scap_engine_handle engine, uint3 return SCAP_SUCCESS; } +static int32_t scap_modern_bpf_sampling_exclude(struct scap_engine_handle engine, uint32_t op, uint32_t sc) +{ + int syscall_id = scap_ppm_sc_to_native_id(sc); + if(syscall_id == -1) + { + return SCAP_FAILURE; + } + return pman_mark_syscall_sampling_exclude(syscall_id, op == 1) == 0 ? SCAP_SUCCESS : SCAP_FAILURE; +} + static int32_t scap_modern_bpf__configure(struct scap_engine_handle engine, enum scap_setting setting, unsigned long arg1, unsigned long arg2) { switch(setting) @@ -125,6 +135,8 @@ static int32_t scap_modern_bpf__configure(struct scap_engine_handle engine, enum case SCAP_STATSD_PORT: pman_set_statsd_port(arg1); break; + case SCAP_SAMPLING_EXCLUDE: + return scap_modern_bpf_sampling_exclude(engine, arg1, arg2); default: { char msg[SCAP_LASTERR_SIZE]; diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index 6864cb3f06..8008f70fff 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -458,6 +458,18 @@ int32_t scap_stop_dropping_mode(scap_t* handle) return SCAP_FAILURE; } +int32_t scap_set_sampling_exclude(scap_t* handle, ppm_sc_code ppm_sc, bool enabled) +{ + if(handle->m_vtable) + { + return handle->m_vtable->configure(handle->m_engine, SCAP_SAMPLING_EXCLUDE, enabled, ppm_sc); + } + + snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "operation not supported"); + ASSERT(false); + return SCAP_FAILURE; +} + int32_t scap_start_dropping_mode(scap_t* handle, uint32_t sampling_ratio) { switch(sampling_ratio) diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 4ae1eb7d7d..7efe788cf2 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -913,6 +913,8 @@ uint64_t scap_get_driver_api_version(scap_t* handle); */ uint64_t scap_get_driver_schema_version(scap_t* handle); +int32_t scap_set_sampling_exclude(scap_t* handle, ppm_sc_code ppm_sc, bool enabled); + #ifdef __cplusplus } #endif diff --git a/userspace/libscap/scap_vtable.h b/userspace/libscap/scap_vtable.h index 086d87851d..d8247b5bb2 100644 --- a/userspace/libscap/scap_vtable.h +++ b/userspace/libscap/scap_vtable.h @@ -85,6 +85,8 @@ enum scap_setting { * arg1: whether to enabled or disable the feature */ SCAP_DROP_FAILED, + + SCAP_SAMPLING_EXCLUDE, }; struct scap_savefile_vtable {