From 39ada9ecb00b26a8f926698a6190981059f356fc Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 24 Jan 2023 23:41:21 +0100 Subject: [PATCH 1/6] new: support `io_uring_enter` syscall Signed-off-by: Andrea Terzolo --- driver/bpf/fillers.h | 67 +++++--------- .../definitions/events_dimensions.h | 2 + .../io_uring_enter.bpf.c | 91 +++++++++++++++++++ driver/ppm_fillers.c | 44 ++++----- .../syscall_enter_suite/io_uring_enter_e.cpp | 46 ++++++++++ .../syscall_exit_suite/io_uring_enter_x.cpp | 64 +++++++++++++ userspace/libpman/src/events_prog_names.h | 2 + 7 files changed, 252 insertions(+), 64 deletions(-) create mode 100644 driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_enter.bpf.c create mode 100644 test/drivers/test_suites/syscall_enter_suite/io_uring_enter_e.cpp create mode 100644 test/drivers/test_suites/syscall_exit_suite/io_uring_enter_x.cpp diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 139c91e6d2..1cd36451cc 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -3387,54 +3387,37 @@ FILLER(sys_io_uring_setup_x, true) FILLER(sys_io_uring_enter_x, true) { - long retval; - int res; - unsigned long val; - - retval = bpf_syscall_get_retval(data->ctx); - res = bpf_val_to_ring(data, retval); - if (res != PPM_SUCCESS) - return res; + /* 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); - /* - * fd - */ - val = bpf_syscall_get_argument(data, 0); - res = bpf_val_to_ring(data, val); - if (res != PPM_SUCCESS) - return res; + /* Parameter 2: fd (type: PT_FD) */ + s32 fd = (s32)bpf_syscall_get_argument(data, 0); + res = bpf_val_to_ring(data, (s64)fd); + CHECK_RES(res); - /* - * to_submit - */ - val = bpf_syscall_get_argument(data, 1); - res = bpf_val_to_ring(data, val); - if (res != PPM_SUCCESS) - return res; + /* Parameter 3: to_submit (type: PT_UINT32) */ + u32 to_submit = (u32)bpf_syscall_get_argument(data, 1); + res = bpf_val_to_ring(data, to_submit); + CHECK_RES(res); - /* - * min_complete - */ - val = bpf_syscall_get_argument(data, 2); - res = bpf_val_to_ring(data, val); - if (res != PPM_SUCCESS) - return res; + /* Parameter 4: min_complete (type: PT_UINT32) */ + u32 min_complete = (u32)bpf_syscall_get_argument(data, 2); + res = bpf_val_to_ring(data, min_complete); + CHECK_RES(res); - /* - * flags - */ - val = bpf_syscall_get_argument(data, 3); - res = bpf_val_to_ring(data, io_uring_enter_flags_to_scap(val)); - if (res != PPM_SUCCESS) - return res; + /* Parameter 5: flags (type: PT_FLAGS32) */ + u32 flags = (u32)bpf_syscall_get_argument(data, 3); + res = bpf_val_to_ring(data, io_uring_enter_flags_to_scap(flags)); + CHECK_RES(res); - /* - * min_complete - */ - val = bpf_syscall_get_argument(data, 4); - res = bpf_val_to_ring(data, val); + /* Parameter 6: sig (type: PT_SIGSET) */ + u32 sig = (u32)bpf_syscall_get_argument(data, 4); + return bpf_val_to_ring(data, sig); - return res; + /// TODO: We miss the last parameter `size_t argsz` + /// we need to implement it in all our drivers } FILLER(sys_io_uring_register_x, true) diff --git a/driver/modern_bpf/definitions/events_dimensions.h b/driver/modern_bpf/definitions/events_dimensions.h index 3024463524..29ad7b11fa 100644 --- a/driver/modern_bpf/definitions/events_dimensions.h +++ b/driver/modern_bpf/definitions/events_dimensions.h @@ -152,6 +152,8 @@ #define MLOCKALL_X_SIZE HEADER_LEN + sizeof(int64_t) + sizeof(uint32_t) + PARAM_LEN * 2 #define MUNLOCKALL_E_SIZE HEADER_LEN #define MUNLOCKALL_X_SIZE HEADER_LEN + sizeof(int64_t) + PARAM_LEN +#define IO_URING_ENTER_E_SIZE HEADER_LEN +#define IO_URING_ENTER_X_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint32_t) * 4 + PARAM_LEN * 6 /* Generic tracepoints events. */ #define PROC_EXIT_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint8_t) * 2 + PARAM_LEN * 4 diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_enter.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_enter.bpf.c new file mode 100644 index 0000000000..b2eaa9e7f0 --- /dev/null +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_enter.bpf.c @@ -0,0 +1,91 @@ +/* + * 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 + +/*=============================== ENTER EVENT ===========================*/ + +SEC("tp_btf/sys_enter") +int BPF_PROG(io_uring_enter_e, + struct pt_regs *regs, + long id) +{ + struct ringbuf_struct ringbuf; + if(!ringbuf__reserve_space(&ringbuf, IO_URING_ENTER_E_SIZE)) + { + return 0; + } + + ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_ENTER_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_enter_x, + struct pt_regs *regs, + long ret) +{ + struct ringbuf_struct ringbuf; + if(!ringbuf__reserve_space(&ringbuf, IO_URING_ENTER_X_SIZE)) + { + return 0; + } + + ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_ENTER_X); + + /*=============================== COLLECT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + ringbuf__store_s64(&ringbuf, ret); + + /* Parameter 2: fd (type: PT_FD) */ + s32 fd = (s32)extract__syscall_argument(regs, 0); + ringbuf__store_s64(&ringbuf, (s64)fd); + + /* Parameter 3: to_submit (type: PT_UINT32) */ + u32 to_submit = (u32)extract__syscall_argument(regs, 1); + ringbuf__store_u32(&ringbuf, to_submit); + + /* Parameter 4: min_complete (type: PT_UINT32) */ + u32 min_complete = (u32)extract__syscall_argument(regs, 2); + ringbuf__store_u32(&ringbuf, min_complete); + + /* Parameter 5: flags (type: PT_FLAGS32) */ + u32 flags = (u32)extract__syscall_argument(regs, 3); + ringbuf__store_u32(&ringbuf, io_uring_enter_flags_to_scap(flags)); + + /* Parameter 6: sig (type: PT_SIGSET) */ + /* This is unclear, why we store only the first 32 bit? this is a pointer! + * It could be also a pointer to a `struct io_uring_getevents_args`. + */ + u32 sig = (u32)extract__syscall_argument(regs, 4); + ringbuf__store_u32(&ringbuf, sig); + + /// TODO: We miss the last parameter `size_t argsz` + /// we need to implement it in all our drivers + + /*=============================== COLLECT PARAMETERS ===========================*/ + + ringbuf__submit_event(&ringbuf); + + return 0; +} + +/*=============================== EXIT EVENT ===========================*/ diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index a8ecea3af0..7aac57e749 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -5175,45 +5175,45 @@ int f_sys_io_uring_setup_x (struct event_filler_arguments *args) return add_sentinel(args); } -int f_sys_io_uring_enter_x (struct event_filler_arguments *args) +int f_sys_io_uring_enter_x(struct event_filler_arguments *args) { - int res; - unsigned long val; + int res = 0; + int32_t fd = 0; + unsigned long val = 0; - int64_t retval = (int64_t)syscall_get_return_value(current, args->regs); + /* Parameter 1: res (type: PT_ERRNO) */ + long retval = (long)syscall_get_return_value(current, args->regs); res = val_to_ring(args, retval, 0, false, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* fd */ + /* Parameter 2: fd (type: PT_FD) */ 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; + fd = (s32)val; + res = val_to_ring(args, (s64)fd, 0, true, 0); + CHECK_RES(res); - /* to_submit */ + /* Parameter 3: to_submit (type: PT_UINT32) */ syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val); res = val_to_ring(args, val, 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* min_complete */ + /* Parameter 4: min_complete (type: PT_UINT32) */ syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val); res = val_to_ring(args, val, 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* flags */ + /* Parameter 5: flags (type: PT_FLAGS32) */ syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val); res = val_to_ring(args, io_uring_enter_flags_to_scap(val), 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* sig */ + /* Parameter 6: sig (type: PT_SIGSET) */ syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val); res = val_to_ring(args, val, 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); + + /// TODO: We miss the last parameter `size_t argsz` + /// we need to implement it in all our drivers return add_sentinel(args); } diff --git a/test/drivers/test_suites/syscall_enter_suite/io_uring_enter_e.cpp b/test/drivers/test_suites/syscall_enter_suite/io_uring_enter_e.cpp new file mode 100644 index 0000000000..374d8eaa0b --- /dev/null +++ b/test/drivers/test_suites/syscall_enter_suite/io_uring_enter_e.cpp @@ -0,0 +1,46 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_enter) + +#include + +TEST(SyscallEnter, io_uring_enterE) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_enter, ENTER_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t fd = -1; + uint32_t to_submit = 10; + uint32_t min_complete = 20; + uint32_t flags = IORING_ENTER_EXT_ARG; + const void* argp = NULL; + size_t argsz = 7; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_enter", syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, argp, argsz)); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + // Here we have no parameters to assert. + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(0); +} +#endif diff --git a/test/drivers/test_suites/syscall_exit_suite/io_uring_enter_x.cpp b/test/drivers/test_suites/syscall_exit_suite/io_uring_enter_x.cpp new file mode 100644 index 0000000000..117e85c4e3 --- /dev/null +++ b/test/drivers/test_suites/syscall_exit_suite/io_uring_enter_x.cpp @@ -0,0 +1,64 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_enter) && defined(__NR_close) + +#include + +TEST(SyscallExit, io_uring_enterX) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_enter, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t fd = -1; + uint32_t to_submit = 10; + uint32_t min_complete = 20; + uint32_t flags = IORING_ENTER_EXT_ARG; + const void* argp = NULL; + size_t argsz = 7; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_enter", syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, argp, argsz)); + int64_t errno_value = -errno; + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + evt_test->assert_numeric_param(1, (int64_t)errno_value); + + /* Parameter 2: fd (type: PT_FD) */ + evt_test->assert_numeric_param(2, (int64_t)fd); + + /* Parameter 3: to_submit (type: PT_UINT32) */ + evt_test->assert_numeric_param(3, (uint32_t)to_submit); + + /* Parameter 4: min_complete (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)min_complete); + + /* Parameter 5: flags (type: PT_FLAGS32) */ + evt_test->assert_numeric_param(5, (uint32_t)PPM_IORING_ENTER_EXT_ARG); + + /* Parameter 6: sig (type: PT_SIGSET) */ + /* These are the first 32 bit of a pointer so in this case all zeros */ + evt_test->assert_numeric_param(6, (uint32_t)0); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(6); +} +#endif diff --git a/userspace/libpman/src/events_prog_names.h b/userspace/libpman/src/events_prog_names.h index 5225f4f7b5..39b1a56d5c 100644 --- a/userspace/libpman/src/events_prog_names.h +++ b/userspace/libpman/src/events_prog_names.h @@ -207,6 +207,8 @@ static const char* event_prog_names[PPM_EVENT_MAX] = { [PPME_SYSCALL_MLOCKALL_X] = "mlockall_x", [PPME_SYSCALL_MUNLOCKALL_E] = "munlockall_e", [PPME_SYSCALL_MUNLOCKALL_X] = "munlockall_x", + [PPME_SYSCALL_IO_URING_ENTER_E] = "io_uring_enter_e", + [PPME_SYSCALL_IO_URING_ENTER_X] = "io_uring_enter_x", }; /* Some events can require more than one bpf program to collect all the data. */ From 31f685a0ba2184a8bd0b09846f50d44790edb8a2 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Wed, 25 Jan 2023 00:28:11 +0100 Subject: [PATCH 2/6] new: support `io_uring_register` syscall Signed-off-by: Andrea Terzolo --- driver/bpf/fillers.h | 55 +++++------- .../definitions/events_dimensions.h | 2 + .../io_uring_register.bpf.c | 84 +++++++++++++++++++ driver/ppm_fillers.c | 32 ++++--- .../io_uring_register_e.cpp | 44 ++++++++++ .../io_uring_register_x.cpp | 59 +++++++++++++ userspace/libpman/src/events_prog_names.h | 2 + 7 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_register.bpf.c create mode 100644 test/drivers/test_suites/syscall_enter_suite/io_uring_register_e.cpp create mode 100644 test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 1cd36451cc..5f10ab7d15 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -3422,46 +3422,29 @@ FILLER(sys_io_uring_enter_x, true) FILLER(sys_io_uring_register_x, true) { - long retval; - int res; - unsigned long val; - - retval = bpf_syscall_get_retval(data->ctx); - res = bpf_val_to_ring(data, retval); - if (res != PPM_SUCCESS) - return res; - - /* - * fd - */ - val = bpf_syscall_get_argument(data, 0); - res = bpf_val_to_ring(data, val); - if (res != PPM_SUCCESS) - return res; + /* 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); - /* - * opcode - */ - val = bpf_syscall_get_argument(data, 1); - res = bpf_val_to_ring(data, io_uring_register_opcodes_to_scap(val)); - if (res != PPM_SUCCESS) - return res; + /* Parameter 2: fd (type: PT_FD) */ + s32 fd = (s32)bpf_syscall_get_argument(data, 0); + res = bpf_val_to_ring(data, (s64)fd); + CHECK_RES(res); - /* - * args - */ - val = bpf_syscall_get_argument(data, 2); - res = bpf_val_to_ring(data, val); - if (res != PPM_SUCCESS) - return res; + /* Parameter 3: opcode (type: PT_ENUMFLAGS16) */ + u32 opcode = (u32)bpf_syscall_get_argument(data, 1); + res = bpf_val_to_ring(data, io_uring_register_opcodes_to_scap(opcode)); + CHECK_RES(res); - /* - * nr_args - */ - val = bpf_syscall_get_argument(data, 3); - res = bpf_val_to_ring(data, val); + /* Parameter 4: arg (type: PT_UINT64) */ + unsigned long arg = bpf_syscall_get_argument(data, 2); + res = bpf_val_to_ring(data, arg); + CHECK_RES(res); - return res; + /* Parameter 5: nr_args (type: PT_UINT32) */ + u32 nr_args = (u32)bpf_syscall_get_argument(data, 3); + return bpf_val_to_ring(data, nr_args); } FILLER(sys_mlock_x, true) diff --git a/driver/modern_bpf/definitions/events_dimensions.h b/driver/modern_bpf/definitions/events_dimensions.h index 29ad7b11fa..704685f128 100644 --- a/driver/modern_bpf/definitions/events_dimensions.h +++ b/driver/modern_bpf/definitions/events_dimensions.h @@ -154,6 +154,8 @@ #define MUNLOCKALL_X_SIZE HEADER_LEN + sizeof(int64_t) + PARAM_LEN #define IO_URING_ENTER_E_SIZE HEADER_LEN #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 /* Generic tracepoints events. */ #define PROC_EXIT_SIZE HEADER_LEN + sizeof(int64_t) * 2 + sizeof(uint8_t) * 2 + PARAM_LEN * 4 diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_register.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_register.bpf.c new file mode 100644 index 0000000000..6357a57b3c --- /dev/null +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_register.bpf.c @@ -0,0 +1,84 @@ +/* + * 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 + +/*=============================== ENTER EVENT ===========================*/ + +SEC("tp_btf/sys_enter") +int BPF_PROG(io_uring_register_e, + struct pt_regs *regs, + long id) +{ + struct ringbuf_struct ringbuf; + if(!ringbuf__reserve_space(&ringbuf, IO_URING_REGISTER_E_SIZE)) + { + return 0; + } + + ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_REGISTER_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_register_x, + struct pt_regs *regs, + long ret) +{ + struct ringbuf_struct ringbuf; + if(!ringbuf__reserve_space(&ringbuf, IO_URING_REGISTER_X_SIZE)) + { + return 0; + } + + ringbuf__store_event_header(&ringbuf, PPME_SYSCALL_IO_URING_REGISTER_X); + + /*=============================== COLLECT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + ringbuf__store_s64(&ringbuf, ret); + + /* Parameter 2: fd (type: PT_FD) */ + s32 fd = (s32)extract__syscall_argument(regs, 0); + ringbuf__store_s64(&ringbuf, (s64)fd); + + /* Parameter 3: opcode (type: PT_ENUMFLAGS16) */ + u32 opcode = (u32)extract__syscall_argument(regs, 1); + ringbuf__store_u16(&ringbuf, (u16)io_uring_register_opcodes_to_scap(opcode)); + + /* Parameter 4: arg (type: PT_UINT64) */ + /* Here we push directly a pointer to userspace. `arg` is + * pointer to `struct io_uring_rsrc_register` + */ + unsigned long arg = extract__syscall_argument(regs, 2); + ringbuf__store_u64(&ringbuf, arg); + + /* Parameter 5: nr_args (type: PT_UINT32) */ + u32 nr_args = (u32)extract__syscall_argument(regs, 3); + ringbuf__store_u32(&ringbuf, nr_args); + + /*=============================== COLLECT PARAMETERS ===========================*/ + + ringbuf__submit_event(&ringbuf); + + return 0; +} + +/*=============================== EXIT EVENT ===========================*/ diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 7aac57e749..9f7e813343 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -5220,37 +5220,35 @@ int f_sys_io_uring_enter_x(struct event_filler_arguments *args) int f_sys_io_uring_register_x (struct event_filler_arguments *args) { - int res; - unsigned long val; + int res = 0; + unsigned long val = 0; + s32 fd = 0; + /* Parameter 1: res (type: PT_ERRNO) */ 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; + CHECK_RES(res); - /* fd */ + /* Parameter 2: fd (type: PT_FD) */ 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; + fd = (s32)val; + res = val_to_ring(args, (s64)fd, 0, true, 0); + CHECK_RES(res); - /* opcode */ + /* Parameter 3: opcode (type: PT_UINT32) */ syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val); res = val_to_ring(args, io_uring_register_opcodes_to_scap(val) , 0 , true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* arg */ + /* Parameter 4: arg (type: PT_UINT64) */ syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val); res = val_to_ring(args, val, 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); - /* nr_args */ + /* Parameter 5: nr_args (type: PT_UINT32) */ syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val); res = val_to_ring(args, val, 0, true, 0); - if (unlikely(res != PPM_SUCCESS)) - return res; + CHECK_RES(res); return add_sentinel(args); } diff --git a/test/drivers/test_suites/syscall_enter_suite/io_uring_register_e.cpp b/test/drivers/test_suites/syscall_enter_suite/io_uring_register_e.cpp new file mode 100644 index 0000000000..1a9f7aabce --- /dev/null +++ b/test/drivers/test_suites/syscall_enter_suite/io_uring_register_e.cpp @@ -0,0 +1,44 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_register) + +#include + +TEST(SyscallEnter, io_uring_registerE) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_register, ENTER_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t fd = -1; + uint32_t opcode = IORING_REGISTER_BUFFERS; + const void* arg = NULL; + unsigned int nr_args = 7; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_register", syscall(__NR_io_uring_register, fd, opcode, arg, nr_args)); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + // Here we have no parameters to assert. + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(0); +} +#endif diff --git a/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp b/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp new file mode 100644 index 0000000000..66bd6dffb1 --- /dev/null +++ b/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp @@ -0,0 +1,59 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_register) + +#include + +TEST(SyscallExit, io_uring_registerX) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_register, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + int32_t fd = -1; + uint32_t opcode = IORING_REGISTER_RESTRICTIONS; + const void* arg = (const void*)0x7fff5694dc58; + unsigned int nr_args = 34; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_register", syscall(__NR_io_uring_register, fd, opcode, arg, nr_args)); + int64_t errno_value = -errno; + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + evt_test->assert_numeric_param(1, (int64_t)errno_value); + + /* Parameter 2: fd (type: PT_FD) */ + evt_test->assert_numeric_param(2, (int64_t)fd); + + /* Parameter 3: opcode (type: PT_ENUMFLAGS16) */ + evt_test->assert_numeric_param(3, (uint16_t)opcode); + + /* Parameter 4: arg (type: PT_UINT64) */ + evt_test->assert_numeric_param(4, (uint64_t)arg); + + /* Parameter 5: nr_args (type: PT_UINT32) */ + evt_test->assert_numeric_param(5, (uint32_t)nr_args); + + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(5); +} +#endif diff --git a/userspace/libpman/src/events_prog_names.h b/userspace/libpman/src/events_prog_names.h index 39b1a56d5c..295effc1bb 100644 --- a/userspace/libpman/src/events_prog_names.h +++ b/userspace/libpman/src/events_prog_names.h @@ -209,6 +209,8 @@ static const char* event_prog_names[PPM_EVENT_MAX] = { [PPME_SYSCALL_MUNLOCKALL_X] = "munlockall_x", [PPME_SYSCALL_IO_URING_ENTER_E] = "io_uring_enter_e", [PPME_SYSCALL_IO_URING_ENTER_X] = "io_uring_enter_x", + [PPME_SYSCALL_IO_URING_REGISTER_E] = "io_uring_register_e", + [PPME_SYSCALL_IO_URING_REGISTER_X] = "io_uring_register_x", }; /* Some events can require more than one bpf program to collect all the data. */ From c8cdc70b88609fb83e33fd4c88171aafcb8cdf1d Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 26 Jan 2023 13:16:58 +0100 Subject: [PATCH 3/6] new: support `io_uring_setup` syscall Signed-off-by: Andrea Terzolo --- driver/bpf/fillers.h | 116 ++++++-------- .../definitions/events_dimensions.h | 2 + .../io_uring_setup.bpf.c | 94 ++++++++++++ driver/ppm_fillers.c | 118 +++++++-------- .../syscall_enter_suite/io_uring_setup_e.cpp | 42 ++++++ .../syscall_exit_suite/io_uring_setup_x.cpp | 141 ++++++++++++++++++ userspace/libpman/src/events_prog_names.h | 2 + 7 files changed, 385 insertions(+), 130 deletions(-) create mode 100644 driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c create mode 100644 test/drivers/test_suites/syscall_enter_suite/io_uring_setup_e.cpp create mode 100644 test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 5f10ab7d15..f208870b23 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -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(¶ms, sizeof(struct io_uring_params), (void *)val)) { - return PPM_FAILURE_INVALID_USER_MEMORY; - } + bpf_probe_read(¶ms, 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) diff --git a/driver/modern_bpf/definitions/events_dimensions.h b/driver/modern_bpf/definitions/events_dimensions.h index 704685f128..82aa85fc5d 100644 --- a/driver/modern_bpf/definitions/events_dimensions.h +++ b/driver/modern_bpf/definitions/events_dimensions.h @@ -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 diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c new file mode 100644 index 0000000000..8254863ee3 --- /dev/null +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c @@ -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 + +/*=============================== 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 *)¶ms, 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 ===========================*/ diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 9f7e813343..04cd7c63d4 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -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(¶ms, (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); } diff --git a/test/drivers/test_suites/syscall_enter_suite/io_uring_setup_e.cpp b/test/drivers/test_suites/syscall_enter_suite/io_uring_setup_e.cpp new file mode 100644 index 0000000000..d3aca19179 --- /dev/null +++ b/test/drivers/test_suites/syscall_enter_suite/io_uring_setup_e.cpp @@ -0,0 +1,42 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_setup) + +#include + +TEST(SyscallEnter, io_uring_setupE) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_setup, ENTER_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + uint32_t entries = 4; + struct io_uring_params* params_pointer = NULL; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_setup", syscall(__NR_io_uring_setup, entries, params_pointer)); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + // Here we have no parameters to assert. + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(0); +} +#endif diff --git a/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp b/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp new file mode 100644 index 0000000000..e3976a2dab --- /dev/null +++ b/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp @@ -0,0 +1,141 @@ +#include "../../event_class/event_class.h" + +#if defined(__NR_io_uring_setup) + +#include + +TEST(SyscallExit, io_uring_setupX) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_setup, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + /* There could be cases in which the structure `io_uring_params` + * doesn't have the filed `feature`, so define it to `0` as default. + */ + uint32_t expected_features = 0; + uint32_t entries = 4; + struct io_uring_params params = {0}; + params.sq_entries = 5; + params.cq_entries = 6; + /* The call should fail since we specified only `IORING_SETUP_SQ_AFF` + * but not `IORING_SETUP_SQPOLL` + */ + params.flags = IORING_SETUP_SQ_AFF; + params.sq_thread_cpu = 7; + params.sq_thread_idle = 8; +#ifdef IORING_FEAT_SINGLE_MMAP + params.features = IORING_FEAT_NODROP; + expected_features = PPM_IORING_FEAT_NODROP; +#endif + assert_syscall_state(SYSCALL_FAILURE, "io_uring_setup", syscall(__NR_io_uring_setup, entries, ¶ms)); + int64_t errno_value = -errno; + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + evt_test->assert_numeric_param(1, (int64_t)errno_value); + + /* Parameter 2: entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(2, (uint32_t)entries); + + /* Parameter 3: sq_entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(3, (uint32_t)params.sq_entries); + + /* Parameter 4: cq_entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)params.cq_entries); + + /* Parameter 5: flags (type: PT_FLAGS32) */ + evt_test->assert_numeric_param(5, (uint32_t)PPM_IORING_SETUP_SQ_AFF); + + /* Parameter 6: sq_thread_cpu (type: PT_UINT32) */ + evt_test->assert_numeric_param(6, (uint32_t)params.sq_thread_cpu); + + /* Parameter 7: sq_thread_idle (type: PT_UINT32) */ + evt_test->assert_numeric_param(7, (uint32_t)params.sq_thread_idle); + + /* Parameter 8: features (type: PT_FLAGS32) */ + evt_test->assert_numeric_param(8, (uint32_t)expected_features); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(8); +} + +TEST(SyscallExit, io_uring_setupX_with_NULL_pointer) +{ + auto evt_test = get_syscall_event_test(__NR_io_uring_setup, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + uint32_t entries = 4; + struct io_uring_params* params_pointer = NULL; + assert_syscall_state(SYSCALL_FAILURE, "io_uring_setup", syscall(__NR_io_uring_setup, entries, params_pointer)); + int64_t errno_value = -errno; + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + evt_test->assert_event_presence(); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + evt_test->assert_numeric_param(1, (int64_t)errno_value); + + /* Parameter 2: entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(2, (uint32_t)entries); + + /* Parameter 3: sq_entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(3, (uint32_t)0); + + /* Parameter 4: cq_entries (type: PT_UINT32) */ + evt_test->assert_numeric_param(4, (uint32_t)0); + + /* Parameter 5: flags (type: PT_FLAGS32) */ + evt_test->assert_numeric_param(5, (uint32_t)0); + + /* Parameter 6: sq_thread_cpu (type: PT_UINT32) */ + evt_test->assert_numeric_param(6, (uint32_t)0); + + /* Parameter 7: sq_thread_idle (type: PT_UINT32) */ + evt_test->assert_numeric_param(7, (uint32_t)0); + + /* Parameter 8: features (type: PT_FLAGS32) */ + evt_test->assert_numeric_param(8, (uint32_t)0); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(8); +} + +#endif diff --git a/userspace/libpman/src/events_prog_names.h b/userspace/libpman/src/events_prog_names.h index 295effc1bb..b5f35f0c84 100644 --- a/userspace/libpman/src/events_prog_names.h +++ b/userspace/libpman/src/events_prog_names.h @@ -211,6 +211,8 @@ static const char* event_prog_names[PPM_EVENT_MAX] = { [PPME_SYSCALL_IO_URING_ENTER_X] = "io_uring_enter_x", [PPME_SYSCALL_IO_URING_REGISTER_E] = "io_uring_register_e", [PPME_SYSCALL_IO_URING_REGISTER_X] = "io_uring_register_x", + [PPME_SYSCALL_IO_URING_SETUP_E] = "io_uring_setup_e", + [PPME_SYSCALL_IO_URING_SETUP_X] = "io_uring_setup_x", }; /* Some events can require more than one bpf program to collect all the data. */ From c2780b77257a94a18390340c351ec174ea8e6512 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 31 Jan 2023 12:16:50 +0100 Subject: [PATCH 4/6] fix(driver): use memset to clear the params struct Signed-off-by: Andrea Terzolo Co-authored-by: Federico Di Pierro --- driver/ppm_fillers.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 04cd7c63d4..0b775e7976 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -5111,12 +5111,7 @@ int f_sys_io_uring_setup_x(struct event_filler_arguments *args) res = ppm_copy_from_user(¶ms, (void *)val, sizeof(struct io_uring_params)); if(unlikely(res != 0)) { - sq_entries = 0; - cq_entries = 0; - flags = 0; - sq_thread_cpu = 0; - sq_thread_idle = 0; - features = 0; + memset(¶ms, 0, sizeof(params)); } sq_entries = params.sq_entries; From 8f79f649429e7487222cf46e9946e0526dbafba1 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 31 Jan 2023 12:28:36 +0100 Subject: [PATCH 5/6] fix: CO-RE relocation on struct size Signed-off-by: Andrea Terzolo Co-authored-by: Hendrik Brueckner --- .../events/syscall_dispatched_events/io_uring_setup.bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c index 8254863ee3..df2bc9d1c4 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/io_uring_setup.bpf.c @@ -64,7 +64,7 @@ int BPF_PROG(io_uring_setup_x, */ unsigned long params_pointer = extract__syscall_argument(regs, 1); struct io_uring_params params = {0}; - bpf_probe_read_user((void *)¶ms, sizeof(struct io_uring_params), (void *)params_pointer); + bpf_probe_read_user((void *)¶ms, bpf_core_type_size(struct io_uring_params), (void *)params_pointer); /* Parameter 3: sq_entries (type: PT_UINT32) */ ringbuf__store_u32(&ringbuf, params.sq_entries); From 502ecb76db2455eb826ea28c58d2be52debb9b1d Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 31 Jan 2023 12:29:18 +0100 Subject: [PATCH 6/6] cleanup: linting Signed-off-by: Andrea Terzolo Co-authored-by: Hendrik Brueckner --- .../syscall_exit_suite/io_uring_register_x.cpp | 1 - .../syscall_exit_suite/io_uring_setup_x.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp b/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp index 66bd6dffb1..40ce98fee0 100644 --- a/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/io_uring_register_x.cpp @@ -51,7 +51,6 @@ TEST(SyscallExit, io_uring_registerX) /* Parameter 5: nr_args (type: PT_UINT32) */ evt_test->assert_numeric_param(5, (uint32_t)nr_args); - /*=============================== ASSERT PARAMETERS ===========================*/ evt_test->assert_num_params_pushed(5); diff --git a/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp b/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp index e3976a2dab..f0704ec4fc 100644 --- a/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/io_uring_setup_x.cpp @@ -12,10 +12,10 @@ TEST(SyscallExit, io_uring_setupX) /*=============================== TRIGGER SYSCALL ===========================*/ - /* There could be cases in which the structure `io_uring_params` - * doesn't have the filed `feature`, so define it to `0` as default. - */ - uint32_t expected_features = 0; + /* There could be cases in which the structure `io_uring_params` + * doesn't have the filed `feature`, so define it to `0` as default. + */ + uint32_t expected_features = 0; uint32_t entries = 4; struct io_uring_params params = {0}; params.sq_entries = 5; @@ -28,7 +28,7 @@ TEST(SyscallExit, io_uring_setupX) params.sq_thread_idle = 8; #ifdef IORING_FEAT_SINGLE_MMAP params.features = IORING_FEAT_NODROP; - expected_features = PPM_IORING_FEAT_NODROP; + expected_features = PPM_IORING_FEAT_NODROP; #endif assert_syscall_state(SYSCALL_FAILURE, "io_uring_setup", syscall(__NR_io_uring_setup, entries, ¶ms)); int64_t errno_value = -errno;