From 31a142bfffe69b16ed8aad5f140f15055761b066 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 6 Oct 2023 11:57:59 +0200 Subject: [PATCH] cleanup(modern): add some comments and clean some code paths Signed-off-by: Andrea Terzolo --- .../helpers/extract/extract_from_kernel.h | 21 +++++++------ .../helpers/interfaces/syscalls_dispatcher.h | 30 +++++++++++++++---- .../attached/dispatchers/syscall_enter.bpf.c | 20 +++++++------ .../attached/dispatchers/syscall_exit.bpf.c | 24 ++++++++------- 4 files changed, 61 insertions(+), 34 deletions(-) diff --git a/driver/modern_bpf/helpers/extract/extract_from_kernel.h b/driver/modern_bpf/helpers/extract/extract_from_kernel.h index 10dd6b4378..62c143e254 100644 --- a/driver/modern_bpf/helpers/extract/extract_from_kernel.h +++ b/driver/modern_bpf/helpers/extract/extract_from_kernel.h @@ -56,9 +56,9 @@ static __always_inline u32 extract__syscall_id(struct pt_regs *regs) #endif } -static __always_inline bool extract__32bit_syscall() +static __always_inline bool bpf_in_ia32_syscall() { - uint32_t status; + uint32_t status = 0; struct task_struct *task = get_current_task(); #if defined(__TARGET_ARCH_x86) @@ -87,7 +87,7 @@ static __always_inline unsigned long extract__syscall_argument(struct pt_regs *r { unsigned long arg; #if defined(__TARGET_ARCH_x86) - if (extract__32bit_syscall()) + if (bpf_in_ia32_syscall()) { switch(idx) { @@ -167,21 +167,24 @@ static __always_inline void extract__network_args(void *argv, int num, struct pt } #elif defined(__TARGET_ARCH_x86) int id = extract__syscall_id(regs); - if(extract__32bit_syscall() && id == __NR_ia32_socketcall) + if(bpf_in_ia32_syscall() && id == __NR_ia32_socketcall) { - __builtin_memset(argv, 0, sizeof(unsigned long) * num); + // First read all arguments on 32 bits. + u32 args_u32[6] = {}; unsigned long args_pointer = extract__syscall_argument(regs, 1); - for(int i = 0; i < num; i++) + bpf_probe_read_user(args_u32, num * sizeof(u32), (void *)args_pointer); + + unsigned long *dst = (unsigned long *)argv; + for (int i = 0; i < num; i++) { - unsigned long *dst = ((unsigned long *)argv) + i; - bpf_probe_read_user(dst, sizeof(u32), ((u32 *)(args_pointer)) + i); + dst[i] = args_u32[i]; } return; } #endif + unsigned long *dst = (unsigned long *)argv; for (int i = 0; i < num; i++) { - unsigned long *dst = (unsigned long *)argv; dst[i] = extract__syscall_argument(regs, i); } } diff --git a/driver/modern_bpf/helpers/interfaces/syscalls_dispatcher.h b/driver/modern_bpf/helpers/interfaces/syscalls_dispatcher.h index 5121ba4a71..837863b611 100644 --- a/driver/modern_bpf/helpers/interfaces/syscalls_dispatcher.h +++ b/driver/modern_bpf/helpers/interfaces/syscalls_dispatcher.h @@ -13,11 +13,6 @@ #include #include -static __always_inline bool syscalls_dispatcher__check_32bit_syscalls() -{ - return extract__32bit_syscall(); -} - static __always_inline bool syscalls_dispatcher__64bit_interesting_syscall(u32 syscall_id) { return maps__64bit_interesting_syscall(syscall_id); @@ -140,6 +135,31 @@ static __always_inline long convert_network_syscalls(struct pt_regs *regs) break; } + /* There are cases in which the socket call code is defined + * but the corresponding syscall code is not. + * For example on s390x machines `SYS_ACCEPT` is defined but + * `__NR_accept` is not. The difference with other drivers is + * that in the modern probe we cannot return the associated event + * instead of the syscall code, so we need to find other workarounds. + * + * Known cases in which the socket call code is defined but + * the corresponding syscall code is not: + * + * ----- s390x + * - `SYS_ACCEPT` is defined but `__NR_accept` is not defined + * -> In this case we return a `__NR_accept4` + * + * ----- x86 with CONFIG_IA32_EMULATION + * - `SYS_ACCEPT` is defined but `__NR_accept` is not defined + * -> In this case we return a `__NR_accept4` + * + * - `SYS_SEND` is defined but `__NR_send` is not defined + * -> In this case we drop the event + * + * - `SYS_RECV` is defined but `__NR_recv` is not defined + * -> In this case we drop the event + */ + // Reset NR_socketcall to send a generic even with correct id #ifdef __NR_socketcall return __NR_socketcall; 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 9d21b1641e..476e5d1683 100644 --- a/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c +++ b/driver/modern_bpf/programs/attached/dispatchers/syscall_enter.bpf.c @@ -19,29 +19,31 @@ int BPF_PROG(sys_enter, { int socketcall_syscall_id = -1; -#ifdef __NR_socketcall - socketcall_syscall_id = __NR_socketcall; -#endif - - if(syscalls_dispatcher__check_32bit_syscalls()) + if(bpf_in_ia32_syscall()) { +#if defined(__TARGET_ARCH_x86) if (syscall_id == __NR_ia32_socketcall) { socketcall_syscall_id = __NR_ia32_socketcall; } else { -#if defined(__TARGET_ARCH_x86) syscall_id = syscalls_dispatcher__convert_ia32_to_64(syscall_id); + // syscalls defined only on 32 bits are dropped here. if(syscall_id == (u32)-1) { return 0; } + } #else - // TODO: unsupported - return 0; + return 0; +#endif + } + else + { +#ifdef __NR_socketcall + socketcall_syscall_id = __NR_socketcall; #endif - } } /* we convert it here in this way the syscall will be treated exactly as the original one */ 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 385266566a..243567f4dc 100644 --- a/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c +++ b/driver/modern_bpf/programs/attached/dispatchers/syscall_exit.bpf.c @@ -23,26 +23,22 @@ int BPF_PROG(sys_exit, { int socketcall_syscall_id = -1; -#ifdef __NR_socketcall - socketcall_syscall_id = __NR_socketcall; -#endif - u32 syscall_id = extract__syscall_id(regs); - if(syscalls_dispatcher__check_32bit_syscalls()) + if(bpf_in_ia32_syscall()) { +#if defined(__TARGET_ARCH_x86) if (syscall_id == __NR_ia32_socketcall) { socketcall_syscall_id = __NR_ia32_socketcall; } else { -#if defined(__TARGET_ARCH_x86) /* - * When a process does execve from 64bit to 32bit, TS_COMPAT is marked true - * but the id of the syscall is __NR_execve, so to correctly parse it we need to - * use 64bit syscall table. On 32bit __NR_execve is equal to __NR_ia32_oldolduname - * which is a very old syscall, not used anymore by most applications + * When a process does execve from 64bit to 32bit, TS_COMPAT is marked true + * but the id of the syscall is __NR_execve, so to correctly parse it we need to + * use 64bit syscall table. On 32bit __NR_execve is equal to __NR_ia32_oldolduname + * which is a very old syscall, not used anymore by most applications */ if(syscall_id != X86_64_NR_EXECVE && syscall_id != X86_64_NR_EXECVEAT) { @@ -52,11 +48,17 @@ int BPF_PROG(sys_exit, return 0; } } + } #else // TODO: unsupported return 0; #endif - } + } + else + { +#ifdef __NR_socketcall + socketcall_syscall_id = __NR_socketcall; +#endif } /* we convert it here in this way the syscall will be treated exactly as the original one */