Skip to content

Commit

Permalink
new: support io_uring_setup syscall
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Terzolo <[email protected]>
  • Loading branch information
Andreagit97 committed Jan 26, 2023
1 parent 227690e commit c13a4c5
Show file tree
Hide file tree
Showing 7 changed files with 385 additions and 130 deletions.
116 changes: 47 additions & 69 deletions driver/bpf/fillers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3295,94 +3295,72 @@ FILLER(sys_open_by_handle_at_x, true)

FILLER(sys_io_uring_setup_x, true)
{
long retval;
int res;
unsigned long val;
unsigned long sq_entries;
unsigned long cq_entries;
unsigned long flags;
unsigned long sq_thread_cpu;
unsigned long sq_thread_idle;
unsigned long features = 0;

#ifdef __NR_io_uring_setup
struct io_uring_params params;
#endif
retval = bpf_syscall_get_retval(data->ctx);
res = bpf_val_to_ring(data, retval);
if (res != PPM_SUCCESS)
return res;
/*
* entries
/* All these params are sent equal to `0` if `__NR_io_uring_setup`
* syscall is not defined.
*/
val = bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
u32 sq_entries = 0;
u32 cq_entries = 0;
u32 flags = 0;
u32 sq_thread_cpu = 0;
u32 sq_thread_idle = 0;
u32 features = 0;

/* If the syscall is defined use the syscall data */
#ifdef __NR_io_uring_setup
/*
* io_uring_params: we get the data structure, and put its fields in the buffer one by one
struct io_uring_params params = {0};
unsigned long params_pointer = bpf_syscall_get_argument(data, 1);
/* if the call fails we don't care since `bpf_probe_read` under the hood memsets
* the destination memory to `0`
*/
val = bpf_syscall_get_argument(data, 1);
if (bpf_probe_read(&params, sizeof(struct io_uring_params), (void *)val)) {
return PPM_FAILURE_INVALID_USER_MEMORY;
}
bpf_probe_read(&params, sizeof(struct io_uring_params), (void *)params_pointer);

sq_entries = params.sq_entries;
cq_entries = params.cq_entries;
flags = io_uring_setup_flags_to_scap(params.flags);
sq_thread_cpu = params.sq_thread_cpu;
sq_thread_idle = params.sq_thread_idle;

/* We need this ifdef because `features` field is defined into the
* `struct io_uring_params` only if the `IORING_FEAT_SINGLE_MMAP` is
* defined.
*/
#ifdef IORING_FEAT_SINGLE_MMAP
features = io_uring_setup_feats_to_scap(params.features);
#endif
#else
sq_entries = 0;
cq_entries = 0;
flags = 0;
sq_thread_cpu = 0;
sq_thread_idle = 0;
features = 0;
#endif
#endif /* __NR_io_uring_setup */

/*
* sq_entries (extracted from io_uring_params structure)
*/
/* Parameter 1: res (type: PT_ERRNO) */
long retval = bpf_syscall_get_retval(data->ctx);
int res = bpf_val_to_ring(data, retval);
CHECK_RES(res);

/* Parameter 2: entries (type: PT_UINT32) */
u32 entries = (u32)bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring(data, entries);
CHECK_RES(res);

/* Parameter 3: sq_entries (type: PT_UINT32) */
res = bpf_val_to_ring(data, sq_entries);
if (res != PPM_SUCCESS)
return res;
/*
* cq_entries (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 4: cq_entries (type: PT_UINT32) */
res = bpf_val_to_ring(data, cq_entries);
if (res != PPM_SUCCESS)
return res;
/*
* flags (extracted from io_uring_params structure)
* Already converted in ppm portable representation
*/
CHECK_RES(res);

/* Parameter 5: flags (type: PT_FLAGS32) */
res = bpf_val_to_ring(data, flags);
if (res != PPM_SUCCESS)
return res;
/*
* sq_thread_cpu (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 6: sq_thread_cpu (type: PT_UINT32) */
res = bpf_val_to_ring(data, sq_thread_cpu);
if (res != PPM_SUCCESS)
return res;
/*
* sq_thread_idle (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 7: sq_thread_idle (type: PT_UINT32) */
res = bpf_val_to_ring(data, sq_thread_idle);
if (res != PPM_SUCCESS)
return res;
/*
* features (extracted from io_uring_params structure)
* Already converted in ppm portable representation
*/
res = bpf_val_to_ring(data, features);
return res;
CHECK_RES(res);

/* Parameter 8: features (type: PT_FLAGS32) */
return bpf_val_to_ring(data, features);
}

FILLER(sys_io_uring_enter_x, true)
Expand Down
2 changes: 2 additions & 0 deletions driver/modern_bpf/definitions/events_dimensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@
#define IO_URING_ENTER_X_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint32_t) * 4 + PARAM_LEN * 6
#define IO_URING_REGISTER_E_SIZE HEADER_LEN
#define IO_URING_REGISTER_X_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint16_t) + sizeof(uint64_t) + sizeof(uint32_t) + PARAM_LEN * 5
#define IO_URING_SETUP_E_SIZE HEADER_LEN
#define IO_URING_SETUP_X_SIZE HEADER_LEN + sizeof(int64_t) + sizeof(uint32_t) * 7 + PARAM_LEN * 8

/* Generic tracepoints events. */
#define PROC_EXIT_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint8_t) * 2 + PARAM_LEN * 4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2023 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.
*/

#include <helpers/interfaces/fixed_size_event.h>

/*=============================== ENTER EVENT ===========================*/

SEC("tp_btf/sys_enter")
int BPF_PROG(io_uring_setup_e,
struct pt_regs *regs,
long id)
{
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, IO_URING_SETUP_E_SIZE))
{
return 0;
}

ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_SETUP_E);

/*=============================== COLLECT PARAMETERS ===========================*/

// Here we have no parameters to collect.

/*=============================== COLLECT PARAMETERS ===========================*/

ringbuf__submit_event(&ringbuf);

return 0;
}

/*=============================== ENTER EVENT ===========================*/

/*=============================== EXIT EVENT ===========================*/

SEC("tp_btf/sys_exit")
int BPF_PROG(io_uring_setup_x,
struct pt_regs *regs,
long ret)
{
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, IO_URING_SETUP_X_SIZE))
{
return 0;
}

ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_SETUP_X);

/*=============================== COLLECT PARAMETERS ===========================*/

/* Parameter 1: res (type: PT_ERRNO) */
ringbuf__store_s64(&ringbuf, ret);

/* Parameter 2: entries (type: PT_UINT32) */
u32 entries = (u32)extract__syscall_argument(regs, 0);
ringbuf__store_u32(&ringbuf, entries);

/* Get the second syscall argument that is a `struct io_uring_params*`
* This struct is defined since kernel release 5.1
*/
unsigned long params_pointer = extract__syscall_argument(regs, 1);
struct io_uring_params params = {0};
bpf_probe_read_user((void *)&params, sizeof(struct io_uring_params), (void *)params_pointer);

/* Parameter 3: sq_entries (type: PT_UINT32) */
ringbuf__store_u32(&ringbuf, params.sq_entries);

/* Parameter 4: cq_entries (type: PT_UINT32) */
ringbuf__store_u32(&ringbuf, params.cq_entries);

/* Parameter 5: flags (type: PT_FLAGS32) */
ringbuf__store_u32(&ringbuf, (u32)io_uring_setup_flags_to_scap(params.flags));

/* Parameter 6: sq_thread_cpu (type: PT_UINT32) */
ringbuf__store_u32(&ringbuf, params.sq_thread_cpu);

/* Parameter 7: sq_thread_idle (type: PT_UINT32) */
ringbuf__store_u32(&ringbuf, params.sq_thread_idle);

/* Parameter 8: features (type: PT_FLAGS32) */
ringbuf__store_u32(&ringbuf, (u32)io_uring_setup_feats_to_scap(params.features));

/*=============================== COLLECT PARAMETERS ===========================*/

ringbuf__submit_event(&ringbuf);

return 0;
}

/*=============================== EXIT EVENT ===========================*/
118 changes: 57 additions & 61 deletions driver/ppm_fillers.c
Original file line number Diff line number Diff line change
Expand Up @@ -5089,88 +5089,84 @@ int f_sys_open_by_handle_at_x(struct event_filler_arguments *args)
return add_sentinel(args);
}

int f_sys_io_uring_setup_x (struct event_filler_arguments *args)
int f_sys_io_uring_setup_x(struct event_filler_arguments *args)
{
int res;
unsigned long val;
unsigned long sq_entries = 0;
unsigned long cq_entries = 0;
unsigned long flags = 0;
unsigned long sq_thread_cpu = 0;
unsigned long sq_thread_idle = 0;
unsigned long features = 0;

#ifdef __NR_io_uring_setup
struct io_uring_params params;
#endif

int64_t retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
int res = 0;
long retval = 0;
unsigned long val = 0;

/* entries */
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* All these params are sent equal to `0` if `__NR_io_uring_setup`
* syscall is not defined.
*/
u32 sq_entries = 0;
u32 cq_entries = 0;
u32 flags = 0;
u32 sq_thread_cpu = 0;
u32 sq_thread_idle = 0;
u32 features = 0;

#ifdef __NR_io_uring_setup
/*
* io_uring_params: we get the data structure, and put its fields in the buffer one by one
*/
struct io_uring_params params = {0};
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = ppm_copy_from_user(&params, (void *)val, sizeof(struct io_uring_params));
if (unlikely(res != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
if(unlikely(res != 0))
{
sq_entries = 0;
cq_entries = 0;
flags = 0;
sq_thread_cpu = 0;
sq_thread_idle = 0;
features = 0;
}

sq_entries = params.sq_entries;
cq_entries = params.cq_entries;
flags = io_uring_setup_flags_to_scap(params.flags);
sq_thread_cpu = params.sq_thread_cpu;
sq_thread_idle = params.sq_thread_idle;

/* We need this ifdef because `features` field is defined into the
* `struct io_uring_params` only if the `IORING_FEAT_SINGLE_MMAP` is
* defined.
*/
#ifdef IORING_FEAT_SINGLE_MMAP
features = io_uring_setup_feats_to_scap(params.features);
#endif
#endif // __NR_io_uring_setup
/*
* sq_entries (extracted from io_uring_params structure)
*/
#endif /* __NR_io_uring_setup */

/* Parameter 1: res (type: PT_ERRNO) */
retval = (long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
CHECK_RES(res);

/* Parameter 2: entries (type: PT_UINT32) */
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
CHECK_RES(res);

/* Parameter 3: sq_entries (type: PT_UINT32) */
res = val_to_ring(args, sq_entries, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* cq_entries (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 4: cq_entries (type: PT_UINT32) */
res = val_to_ring(args, cq_entries, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* flags (extracted from io_uring_params structure)
* Already converted in ppm portable representation
*/
CHECK_RES(res);

/* Parameter 5: flags (type: PT_FLAGS32) */
res = val_to_ring(args, flags, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* sq_thread_cpu (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 6: sq_thread_cpu (type: PT_UINT32) */
res = val_to_ring(args, sq_thread_cpu, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* sq_thread_idle (extracted from io_uring_params structure)
*/
CHECK_RES(res);

/* Parameter 7: sq_thread_idle (type: PT_UINT32) */
res = val_to_ring(args, sq_thread_idle, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* features (extracted from io_uring_params structure)
* Already converted in ppm portable representation
*/
CHECK_RES(res);

/* Parameter 8: features (type: PT_FLAGS32) */
res = val_to_ring(args, features, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
CHECK_RES(res);

return add_sentinel(args);
}
Expand Down
Loading

0 comments on commit c13a4c5

Please sign in to comment.