From 3bcbd534a3ad0090ab154da8c47c915dd1d1a3a3 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sun, 2 Oct 2022 19:22:09 +0200 Subject: [PATCH] update(modern_bpf): reduce the `execve` instrumentation time with new APIs Signed-off-by: Andrea Terzolo --- .../helpers/extract/extract_from_kernel.h | 33 --------- .../helpers/store/auxmap_store_params.h | 68 +++++++++++-------- .../syscall_dispatched_events/execve.bpf.c | 6 +- .../syscall_dispatched_events/execveat.bpf.c | 6 +- 4 files changed, 44 insertions(+), 69 deletions(-) diff --git a/driver/modern_bpf/helpers/extract/extract_from_kernel.h b/driver/modern_bpf/helpers/extract/extract_from_kernel.h index 79ddaf3062..8720583227 100644 --- a/driver/modern_bpf/helpers/extract/extract_from_kernel.h +++ b/driver/modern_bpf/helpers/extract/extract_from_kernel.h @@ -210,39 +210,6 @@ static __always_inline u64 extract__capability(struct task_struct *task, enum ca return capabilities_to_scap(((unsigned long)cap_struct.cap[1] << 32) | cap_struct.cap[0]); } -/////////////////////////// -// CHARBUF EXTRACION -/////////////////////////// - -/** - * @brief Extract a specif charbuf pointer from an array of charbuf pointers - * using `index`. - * - * Please note: Here we don't care about the result of `bpf_probe_read_...()` - * if we obtain a not-valid pointer we will manage it in the caller - * functions. - * - * @param array charbuf pointers array. - * @param index at which we want to extract the charbuf pointer. - * @param mem from which memory we need to read: user-space or kernel-space. - * @return unsigned long return the extracted charbuf pointer or an invalid pointer in - * case of failure. - */ -static __always_inline unsigned long extract__charbuf_pointer_from_array(unsigned long array, u16 index, enum read_memory mem) -{ - char **charbuf_array = (char **)array; - char *charbuf_pointer = NULL; - if(mem == KERNEL) - { - bpf_probe_read_kernel(&charbuf_pointer, sizeof(charbuf_pointer), &charbuf_array[index]); - } - else - { - bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &charbuf_array[index]); - } - return (unsigned long)charbuf_pointer; -} - ///////////////////////// // PIDS EXTRACION //////////////////////// diff --git a/driver/modern_bpf/helpers/store/auxmap_store_params.h b/driver/modern_bpf/helpers/store/auxmap_store_params.h index 3e15ab6c94..44a90ccdf8 100644 --- a/driver/modern_bpf/helpers/store/auxmap_store_params.h +++ b/driver/modern_bpf/helpers/store/auxmap_store_params.h @@ -49,6 +49,9 @@ enum connection_direction /* Maximum number of charbuf pointers that we assume an array can have. */ #define MAX_CHARBUF_POINTERS 16 +/* Maximum length of an `execve` arg. */ +#define MAX_EXECVE_ARG_LEN 4096 + /* Concept of auxamp (auxiliary map): * * For variable size events we cannot directly reserve space into the ringbuf, @@ -344,58 +347,63 @@ static __always_inline u16 auxmap__store_bytebuf_param(struct auxiliary_map *aux } /** - * @brief Use `auxmap__store_single_charbuf_param_from_array` when - * you have to store a charbuf from a charbuf pointer array. - * You have to provide the index of the charbuf pointer inside the - * array. Indexes start from '0' as usual. - * Once we obtain the pointer with `extract__charbuf_pointer_from_array`, - * we can store the charbuf with `auxmap__store_charbuf_param`. + * @brief Use `auxmap__store_execve_exe` when you have to store the + * `exe` name from an execve-family syscall. + * By convention, `exe` is `argv[0]`, this is the reason why here we pass the `argv` array. * * @param auxmap pointer to the auxmap in which we are storing the param. - * @param array charbuf pointer array. - * @param index position at which we want to extract our charbuf. - * @param mem from which memory we need to read: user-space or kernel-space. + * @param array charbuf pointer array, obtained directly from the syscall (`argv`). */ -static __always_inline void auxmap__store_single_charbuf_param_from_array(struct auxiliary_map *auxmap, unsigned long array, u16 index, enum read_memory mem) +static __always_inline void auxmap__store_execve_exe(struct auxiliary_map *auxmap, char **array) { - unsigned long charbuf_pointer = extract__charbuf_pointer_from_array(array, index, mem); - auxmap__store_charbuf_param(auxmap, charbuf_pointer, mem); + unsigned long charbuf_pointer = 0; + u16 exe_len = 0; + + if(bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &array[0])) + { + push__param_len(auxmap->data, &auxmap->lengths_pos, exe_len); + return; + } + + exe_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_EXECVE_ARG_LEN, USER); + push__param_len(auxmap->data, &auxmap->lengths_pos, exe_len); } /** - * @brief Use `auxmap__store_multiple_charbufs_param_from_array` when - * you have to store multiple charbufs from a charbuf pointer - * array. You have to provide an index that states where to start - * the charbuf collection. If you want to store all the charbufs - * pointed in the array, you can use '0' as 'index'. + * @brief Use `auxmap__store_execve_args` when you have to store + * `argv` or `envp` params from an execve-family syscall. + * You have to provide an index that states where to start + * the charbuf collection. This is becuase with `argv` we want to avoid + * the first param (`argv[0]`), since it is already collected with + * `auxmap__store_execve_exe`. * * Please note: right now we assume that our arrays have no more * than `MAX_CHARBUF_POINTERS` * * @param auxmap pointer to the auxmap in which we are storing the param. - * @param array charbuf pointer array + * @param array charbuf pointer array, obtained directly from the syscall (`argv` or `envp`). * @param index position at which we start to collect our charbufs. - * @param mem from which memory we need to read: user-space or kernel-space. */ -static __always_inline void auxmap__store_multiple_charbufs_param_from_array(struct auxiliary_map *auxmap, unsigned long array, u16 index, enum read_memory mem) +static __always_inline void auxmap__store_execve_args(struct auxiliary_map *auxmap, char **array, u16 index) { - unsigned long charbuf_pointer; - u16 charbuf_len = 0; + unsigned long charbuf_pointer = 0; + u16 arg_len = 0; u16 total_len = 0; - /* We push in the auxmap all the charbufs that we find. - * We push the overall length only at the end of the - * for loop with `push__param_len`. - */ + for(; index < MAX_CHARBUF_POINTERS; ++index) { - charbuf_pointer = extract__charbuf_pointer_from_array(array, index, mem); - charbuf_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_PARAM_SIZE, mem); - if(!charbuf_len) + if(bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &array[index])) { break; } - total_len += charbuf_len; + arg_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_EXECVE_ARG_LEN, USER); + if(!arg_len) + { + break; + } + total_len += arg_len; } + push__param_len(auxmap->data, &auxmap->lengths_pos, total_len); } diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c index e9151b32a4..655759673f 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c @@ -99,10 +99,10 @@ int BPF_PROG(execve_x, unsigned long argv = extract__syscall_argument(regs, 1); /* Parameter 2: exe (type: PT_CHARBUF) */ - auxmap__store_single_charbuf_param_from_array(auxmap, argv, 0, USER); + auxmap__store_execve_exe(auxmap, (char **)argv); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - auxmap__store_multiple_charbufs_param_from_array(auxmap, argv, 1, USER); + auxmap__store_execve_args(auxmap, (char **)argv, 1); } /* Parameter 4: tid (type: PT_PID) */ @@ -209,7 +209,7 @@ int BPF_PROG(t1_execve_x, { /* Parameter 16: env (type: PT_CHARBUFARRAY) */ unsigned long envp = extract__syscall_argument(regs, 2); - auxmap__store_multiple_charbufs_param_from_array(auxmap, envp, 0, USER); + auxmap__store_execve_args(auxmap, (char **)envp, 0); } /* Parameter 17: tty (type: PT_INT32) */ diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c index ebaafc25c6..da895f2591 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c @@ -81,10 +81,10 @@ int BPF_PROG(execveat_x, unsigned long argv = extract__syscall_argument(regs, 2); /* Parameter 2: exe (type: PT_CHARBUF) */ - auxmap__store_single_charbuf_param_from_array(auxmap, argv, 0, USER); + auxmap__store_execve_exe(auxmap, (char **)argv); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - auxmap__store_multiple_charbufs_param_from_array(auxmap, argv, 1, USER); + auxmap__store_execve_args(auxmap, (char **)argv, 1); /* Parameter 4: tid (type: PT_PID) */ /* this is called `tid` but it is the `pid`. */ @@ -167,7 +167,7 @@ int BPF_PROG(t1_execveat_x, /* Parameter 16: env (type: PT_CHARBUFARRAY) */ unsigned long envp = extract__syscall_argument(regs, 3); - auxmap__store_multiple_charbufs_param_from_array(auxmap, envp, 0, USER); + auxmap__store_execve_args(auxmap, (char **)envp, 0); /* Parameter 17: tty (type: PT_INT32) */ u32 tty = exctract__tty(task);