Skip to content

Commit

Permalink
new(driver,userspace): added new APIs to dynamically manage tracepoints.
Browse files Browse the repository at this point in the history
This is the same API we introduced for runtime ppm_sc management in #521,
but for tracepoints.
It is implemented for kmod, bpf and modern_bpf.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
  • Loading branch information
FedeDP authored and poiana committed Oct 26, 2022
1 parent 266ea1e commit 287f867
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 143 deletions.
6 changes: 6 additions & 0 deletions driver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions driver/ppm_events_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,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[];
Expand Down
10 changes: 8 additions & 2 deletions userspace/libscap/engine/bpf/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
117 changes: 93 additions & 24 deletions userspace/libscap/engine/bpf/scap_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,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;
Expand Down Expand Up @@ -545,7 +546,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)
{
Expand Down Expand Up @@ -643,7 +646,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;
}
Expand All @@ -661,7 +664,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)
Expand Down Expand Up @@ -695,11 +698,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;
}

Expand Down Expand Up @@ -824,9 +827,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;
}
}
}
}
Expand Down Expand Up @@ -1255,6 +1270,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;
Expand All @@ -1264,22 +1292,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)
Expand Down Expand Up @@ -1420,7 +1435,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;
}
Expand Down Expand Up @@ -1632,13 +1648,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);
}
Expand Down Expand Up @@ -1679,6 +1746,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)
{
Expand Down
55 changes: 44 additions & 11 deletions userspace/libscap/engine/kmod/scap_kmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,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;
Expand Down Expand Up @@ -371,19 +411,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;
Expand Down Expand Up @@ -729,6 +760,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)
{
Expand Down
Loading

0 comments on commit 287f867

Please sign in to comment.