diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 352cabd320..0cbaae0574 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -1929,6 +1929,13 @@ static __always_inline int bpf_accumulate_argv_or_env(struct filler_data *data, *args_len = 0; off = data->state->tail_ctx.curoff; + if(argv == NULL) + { + // we need to put a `\0` otherwise we could read junk data + data->buf[off & SCRATCH_SIZE_HALF] = '\0'; + return PPM_SUCCESS; + } + #pragma unroll for (j = 0; j < FAILED_ARGS_ENV_ITEMS_MAX; ++j) { arg = _READ_USER(argv[j]); diff --git a/driver/modern_bpf/helpers/base/push_data.h b/driver/modern_bpf/helpers/base/push_data.h index 0fd01b9100..a304b8522f 100644 --- a/driver/modern_bpf/helpers/base/push_data.h +++ b/driver/modern_bpf/helpers/base/push_data.h @@ -214,7 +214,8 @@ static __always_inline void push__previous_character(uint8_t *data, uint64_t *pa * @param charbuf_pointer pointer to the charbuf. * @param limit maximum number of bytes that we read in case we don't find a `\0` * @param mem tell where it must read: user-space or kernel-space. - * @return (uint16_t) the number of bytes written in the buffer. Could be '0' if the passed pointer is not valid. + * @return (uint16_t) the number of bytes written in the buffer. Returns '0' if the passed pointer is not valid. + * Returns `1` if the provided pointer points to an empty string "". */ static __always_inline uint16_t push__charbuf(uint8_t *data, uint64_t *payload_pos, unsigned long charbuf_pointer, uint16_t limit, enum read_memory mem) { @@ -233,11 +234,19 @@ static __always_inline uint16_t push__charbuf(uint8_t *data, uint64_t *payload_p (char *)charbuf_pointer); } - if(written_bytes <= 0) + if(written_bytes < 0) { + /* This is probably a page fault */ return 0; } + /* Since `bpf_probe_read_user_str` return `0` in case of empty string we push a `\0` and we return 1. */ + if(written_bytes==0) + { + *((char *)&data[SAFE_ACCESS(*payload_pos)]) = '\0'; + written_bytes = 1; + } + *payload_pos += written_bytes; return (uint16_t)written_bytes; } diff --git a/driver/modern_bpf/helpers/store/auxmap_store_params.h b/driver/modern_bpf/helpers/store/auxmap_store_params.h index 1dae772fa0..0564584e2e 100644 --- a/driver/modern_bpf/helpers/store/auxmap_store_params.h +++ b/driver/modern_bpf/helpers/store/auxmap_store_params.h @@ -339,30 +339,112 @@ static __always_inline uint16_t auxmap__store_bytebuf_param(struct auxiliary_map } /** - * @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. + * @brief This helper stores a char buffer array as a byte buffer into the auxmap. * * @param auxmap pointer to the auxmap in which we are storing the param. - * @param array charbuf pointer array, obtained directly from the syscall (`argv`). + * @param start_pointer pointer where we start to read. + * @param len_to_read len that we can ideally read. + * @param max_len max len that we can read. */ -static __always_inline void auxmap__store_execve_exe(struct auxiliary_map *auxmap, char **array) +static __always_inline void auxmap__store_charbufarray_as_bytebuf(struct auxiliary_map *auxmap, unsigned long start_pointer, uint16_t len_to_read, uint16_t max_len) +{ + /* Here we read an array of charbufs starting from a pointer. + * We could also read the array element per element but + * since we know the total len we read it as a `bytebuf`. + * Since this is an array of charbufs the `\0` after every argument are preserved. + * We just need to add a final `\0` in case we args are too long and we have a partial + * read. + */ + if(len_to_read >= max_len) + { + len_to_read = max_len; + } + + /* if `auxmap__store_bytebuf_param` returns 0 we will send an empty param. + * we don't need the final `\0`. + */ + if(auxmap__store_bytebuf_param(auxmap, start_pointer, len_to_read, USER) > 0) + { + // maybe we read only part of the last argument so we need to put a `\0` at the end. + push__previous_character(auxmap->data, &auxmap->payload_pos, '\0'); + } +} + +/** + * @brief This helper stores the exe + args in just one helper + * This is the unique helper that stores 2 different params (`exe` and `args`) + * + * @param auxmap pointer to the auxmap in which we are storing the param. + * @param charbuf pointer array, obtained directly from the syscall (`argv`). + */ +static __always_inline void auxmap__store_exe_args_failure(struct auxiliary_map *auxmap, char **array) { unsigned long charbuf_pointer = 0; uint16_t exe_len = 0; + if(array == NULL) + { + /* We need to store both the exe and the args. + * To be compliant with other drivers we send an empty string as exe not a param with len==0. + */ + push__new_character(auxmap->data, &auxmap->payload_pos, '\0'); + push__param_len(auxmap->data, &auxmap->lengths_pos, sizeof(char)); + + auxmap__store_empty_param(auxmap); + return; + } + + /* Here we read the pointer to `exe` and we store it */ if(bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &array[0])) { + /* we cannot read the pointer so `exe` will be `0` */ + push__param_len(auxmap->data, &auxmap->lengths_pos, 0); + } + else + { + /* we push the `exe` as a separate arg. */ + exe_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_PROC_EXE, USER); push__param_len(auxmap->data, &auxmap->lengths_pos, exe_len); - return; } + + /* Here we read the pointers to `args` and we store it. + * `payload_pos` points after `exe` + */ + uint64_t initial_payload_pos = auxmap->payload_pos; + uint16_t args_len = 0; + /* Index 1 because we skip the `exe` */ + for(uint8_t index = 1; index < MAX_CHARBUF_POINTERS; ++index) + { + if(bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &array[index])) + { + break; + } + + if(!charbuf_pointer) + { + break; + } + + args_len += push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_PROC_ARG_ENV, USER); - exe_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_PROC_EXE, USER); - push__param_len(auxmap->data, &auxmap->lengths_pos, exe_len); + /* the sum of `exe` + `args` should be `<= MAX_PROC_ARG_ENV` */ + if(args_len + exe_len >= MAX_PROC_ARG_ENV) + { + args_len = MAX_PROC_ARG_ENV - exe_len; + break; + } + } + + if(args_len > 0) + { + auxmap->payload_pos = initial_payload_pos + args_len; + push__previous_character(auxmap->data, &auxmap->payload_pos, '\0'); + } + push__param_len(auxmap->data, &auxmap->lengths_pos, args_len); } /** - * @brief Use `auxmap__store_execve_args` when you have to store + * @brief Use `auxmap__store_env_failure` 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 @@ -374,16 +456,21 @@ static __always_inline void auxmap__store_execve_exe(struct auxiliary_map *auxma * * @param auxmap pointer to the auxmap in which we are storing the param. * @param array charbuf pointer array, obtained directly from the syscall (`argv` or `envp`). - * @param index position at which we start to collect our charbufs. */ -static __always_inline void auxmap__store_execve_args(struct auxiliary_map *auxmap, char **array, uint16_t index) +static __always_inline void auxmap__store_env_failure(struct auxiliary_map *auxmap, char **array) { unsigned long charbuf_pointer = 0; uint16_t arg_len = 0; uint16_t total_len = 0; uint64_t initial_payload_pos = auxmap->payload_pos; - for(; index < MAX_CHARBUF_POINTERS; ++index) + if(array == NULL) + { + auxmap__store_empty_param(auxmap); + return; + } + + for(uint8_t index = 0; index < MAX_CHARBUF_POINTERS; ++index) { if(bpf_probe_read_user(&charbuf_pointer, sizeof(charbuf_pointer), &array[index])) { @@ -396,25 +483,18 @@ static __always_inline void auxmap__store_execve_args(struct auxiliary_map *auxm } arg_len = push__charbuf(auxmap->data, &auxmap->payload_pos, charbuf_pointer, MAX_PROC_ARG_ENV, USER); - - // push trailing \0 if the arg is empty - if(arg_len == 0) + total_len += arg_len; + + /* the sum of all env variables lengths should be `<= MAX_PROC_ARG_ENV` */ + if(total_len >= MAX_PROC_ARG_ENV) { - push__u8(auxmap->data, &auxmap->payload_pos, 0); - arg_len = 1; + total_len = MAX_PROC_ARG_ENV; + break; } - total_len += arg_len; - } - /* the sum of all env variables lengths should be `<= MAX_PROC_ARG_ENV` */ - if(total_len >= MAX_PROC_ARG_ENV) - { - total_len = MAX_PROC_ARG_ENV; - } - else - { - total_len = total_len & (MAX_PROC_ARG_ENV - 1); } + auxmap->payload_pos = initial_payload_pos + total_len; + push__previous_character(auxmap->data, &auxmap->payload_pos, '\0'); push__param_len(auxmap->data, &auxmap->lengths_pos, total_len); } diff --git a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c index 87e1370e3d..d60638039b 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c @@ -54,21 +54,13 @@ int BPF_PROG(sched_p_exec, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can understand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read the whole array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument is preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, total_args_len - exe_arg_len, + MAX_PROC_ARG_ENV - exe_arg_len); /* Parameter 4: tid (type: PT_PID) */ /* this is called `tid` but it is the `pid`. */ @@ -152,15 +144,9 @@ int BPF_PROG(t1_sched_p_exec, READ_TASK_FIELD_INTO(&env_start_pointer, task, mm, env_start); READ_TASK_FIELD_INTO(&env_end_pointer, task, mm, env_end); - unsigned long total_env_len = env_end_pointer - env_start_pointer; - /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, env_start_pointer, total_env_len & (MAX_PROC_ARG_ENV - 1), USER); + auxmap__store_charbufarray_as_bytebuf(auxmap, env_start_pointer, env_end_pointer - env_start_pointer, + MAX_PROC_ARG_ENV); /* Parameter 17: tty (type: PT_UINT32) */ uint32_t tty = exctract__tty(task); diff --git a/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c index d58e913d2a..9a3c101fde 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_fork.bpf.c @@ -64,8 +64,6 @@ int BPF_PROG(sched_p_fork, READ_TASK_FIELD_INTO(&arg_start_pointer, child, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, child, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ /* We need to extract the len of `exe` arg so we can understand * the overall length of the remaining args. @@ -73,12 +71,9 @@ int BPF_PROG(sched_p_fork, uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read the whole array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument is preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); /* Parameter 4: tid (type: PT_PID) */ /* this is called `tid` but it is the `pid`. */ diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone.bpf.c index e3f875cbb9..b77b3b1eb1 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone.bpf.c @@ -86,21 +86,13 @@ int BPF_PROG(clone_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can understand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone3.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone3.bpf.c index 0820aafeaa..0ac39c92e3 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone3.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/clone3.bpf.c @@ -86,21 +86,13 @@ int BPF_PROG(clone3_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can understand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { 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 46c14ce70c..23579738ff 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 @@ -87,36 +87,24 @@ int BPF_PROG(execve_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can undestand + /* We need to extract the len of `exe` arg so we can understand * the overall length of the remaining args. */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read the whole array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { - /* This is a charbuf pointer array. - * Every element of `argv` array is a pointer to a charbuf. - * Here the first pointer points to `exe` param while all - * the others point to the different args. - */ unsigned long argv = extract__syscall_argument(regs, 1); /* Parameter 2: exe (type: PT_CHARBUF) */ - auxmap__store_execve_exe(auxmap, (char **)argv); - /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - auxmap__store_execve_args(auxmap, (char **)argv, 1); + auxmap__store_exe_args_failure(auxmap, (char **)argv); } /* Parameter 4: tid (type: PT_PID) */ @@ -209,21 +197,15 @@ int BPF_PROG(t1_execve_x, READ_TASK_FIELD_INTO(&env_start_pointer, task, mm, env_start); READ_TASK_FIELD_INTO(&env_end_pointer, task, mm, env_end); - unsigned long total_env_len = env_end_pointer - env_start_pointer; - /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, env_start_pointer, total_env_len & (MAX_PROC_ARG_ENV - 1), USER); + auxmap__store_charbufarray_as_bytebuf(auxmap, env_start_pointer, env_end_pointer - env_start_pointer, + MAX_PROC_ARG_ENV); } else { /* Parameter 16: env (type: PT_CHARBUFARRAY) */ unsigned long envp = extract__syscall_argument(regs, 2); - auxmap__store_execve_args(auxmap, (char **)envp, 0); + auxmap__store_env_failure(auxmap, (char **)envp); } /* 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 5442b97a09..718d876877 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 @@ -104,36 +104,21 @@ int BPF_PROG(execveat_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can undestand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read the whole array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { - /* This is a charbuf pointer array. - * Every element of `argv` array is a pointer to a charbuf. - * Here the first pointer points to `exe` param while all - * the others point to the different args. - */ unsigned long argv = extract__syscall_argument(regs, 2); /* Parameter 2: exe (type: PT_CHARBUF) */ - auxmap__store_execve_exe(auxmap, (char **)argv); - /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - auxmap__store_execve_args(auxmap, (char **)argv, 1); + auxmap__store_exe_args_failure(auxmap, (char **)argv); } /* Parameter 4: tid (type: PT_PID) */ @@ -226,21 +211,15 @@ int BPF_PROG(t1_execveat_x, READ_TASK_FIELD_INTO(&env_start_pointer, task, mm, env_start); READ_TASK_FIELD_INTO(&env_end_pointer, task, mm, env_end); - unsigned long total_env_len = env_end_pointer - env_start_pointer; - /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, env_start_pointer, total_env_len & (MAX_PROC_ARG_ENV - 1), USER); + auxmap__store_charbufarray_as_bytebuf(auxmap, env_start_pointer, env_end_pointer - env_start_pointer, + MAX_PROC_ARG_ENV); } else { /* Parameter 16: env (type: PT_CHARBUFARRAY) */ unsigned long envp = extract__syscall_argument(regs, 3); - auxmap__store_execve_args(auxmap, (char **)envp, 0); + auxmap__store_env_failure(auxmap, (char **)envp); } /* Parameter 17: tty (type: PT_UID) */ diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/fork.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/fork.bpf.c index 64b43c34f8..00d24543da 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/fork.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/fork.bpf.c @@ -88,21 +88,13 @@ int BPF_PROG(fork_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can undestand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/vfork.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/vfork.bpf.c index 0e6dbdae1a..d4f45e7d31 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/vfork.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/vfork.bpf.c @@ -88,21 +88,13 @@ int BPF_PROG(vfork_x, READ_TASK_FIELD_INTO(&arg_start_pointer, task, mm, arg_start); READ_TASK_FIELD_INTO(&arg_end_pointer, task, mm, arg_end); - unsigned long total_args_len = arg_end_pointer - arg_start_pointer; - /* Parameter 2: exe (type: PT_CHARBUF) */ - /* We need to extract the len of `exe` arg so we can undestand - * the overall length of the remaining args. - */ uint16_t exe_arg_len = auxmap__store_charbuf_param(auxmap, arg_start_pointer, MAX_PROC_EXE, USER); /* Parameter 3: args (type: PT_CHARBUFARRAY) */ - /* Here we read all the array starting from the pointer to the first - * element. We could also read the array element per element but - * since we know the total len we read it as a `bytebuf`. - * The `\0` after every argument are preserved. - */ - auxmap__store_bytebuf_param(auxmap, arg_start_pointer + exe_arg_len, (total_args_len - exe_arg_len) & (MAX_PROC_ARG_ENV - 1), USER); + unsigned long total_args_len = arg_end_pointer - arg_start_pointer; + auxmap__store_charbufarray_as_bytebuf(auxmap, arg_start_pointer + exe_arg_len, + total_args_len - exe_arg_len, MAX_PROC_ARG_ENV - exe_arg_len); } else { diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index c674c5471e..7846001f20 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -723,106 +723,116 @@ if (append_cgroup(#_x, _x ## _subsys_id, args->str_storage + STR_STORAGE_SIZE - #endif /* Takes in a NULL-terminated array of pointers to strings in userspace, and - * concatenates them to a single \0-separated string. Return the length of this - * string, or <0 on error */ -int accumulate_argv_or_env(const char __user * __user *argv, - char *str_storage, - int available) + * concatenates them to a single \0-separated string. Return the length of these + * strings with the final '\0' included. + */ +int accumulate_argv_or_env(const void __user * argv, + char *str_storage) { int len = 0; - int n_bytes_copied; - - if (argv == NULL) - return len; + int ret = 0; + const char __user * p = NULL; for (;;) { - const char __user *p; + + if (argv == NULL) + break; if (unlikely(ppm_get_user(p, argv))) - return PPM_FAILURE_INVALID_USER_MEMORY; + { + /* We return what we read until now */ + break; + } if (p == NULL) break; - /* need at least enough space for a \0 */ - if (available < 1) - return PPM_FAILURE_BUFFER_FULL; - - n_bytes_copied = ppm_strncpy_from_user(&str_storage[len], p, - available); - - /* ppm_strncpy_from_user includes the trailing \0 in its return - * count. I want to pretend it was strncpy_from_user() so I - * subtract off the 1 */ - n_bytes_copied--; - - if (n_bytes_copied < 0) - return PPM_FAILURE_INVALID_USER_MEMORY; - - if (n_bytes_copied >= available) - return PPM_FAILURE_BUFFER_FULL; + /* ppm_strncpy_from_user includes the trailing \0 */ + ret = ppm_strncpy_from_user(&str_storage[len], p, + STR_STORAGE_SIZE-len); + if(ret < 0) + { + /* We ignore the failed read. We will try to read from the same position in + * the next iteration. + */ + ret = 0; + } - /* update buffer. I want to keep the trailing \0, so I +1 */ - available -= n_bytes_copied+1; - len += n_bytes_copied+1; + len += ret; + if(len >= STR_STORAGE_SIZE) + { + len = STR_STORAGE_SIZE; + break; + } - argv++; + argv += sizeof(argv); } + if(len>0) + { + str_storage[len-1] = '\0'; + } + else + { + str_storage[0] = '\0'; + } return len; } #ifdef CONFIG_COMPAT /* compat version that deals correctly with 32bits pointers of argv */ -static int compat_accumulate_argv_or_env(compat_uptr_t argv, - char *str_storage, - int available) +int compat_accumulate_argv_or_env(compat_uptr_t argv, + char *str_storage) { int len = 0; - int n_bytes_copied; - - if (compat_ptr(argv) == NULL) - return len; - + int ret = 0; + const char __user *p = NULL; for (;;) { - compat_uptr_t compat_p; - const char __user *p; + compat_uptr_t compat_p = 0; + + if (compat_ptr(argv) == NULL) + break; if (unlikely(ppm_get_user(compat_p, compat_ptr(argv)))) - return PPM_FAILURE_INVALID_USER_MEMORY; + { + /* We return what we read until now */ + break; + } p = compat_ptr(compat_p); - if (p == NULL) break; - /* need at least enough space for a \0 */ - if (available < 1) - return PPM_FAILURE_BUFFER_FULL; - - n_bytes_copied = ppm_strncpy_from_user(&str_storage[len], p, - available); - - /* ppm_strncpy_from_user includes the trailing \0 in its return - * count. I want to pretend it was strncpy_from_user() so I - * subtract off the 1 */ - n_bytes_copied--; - - if (n_bytes_copied < 0) { - return PPM_FAILURE_INVALID_USER_MEMORY; + /* ppm_strncpy_from_user includes the trailing \0 */ + ret = ppm_strncpy_from_user(&str_storage[len], p, + STR_STORAGE_SIZE-len); + if(ret < 0) + { + /* We ignore the failed read. We will try to read from the same position in + * the next iteration. + */ + ret = 0; } - if (n_bytes_copied >= available) - return PPM_FAILURE_BUFFER_FULL; - /* update buffer. I want to keep the trailing \0, so I +1 */ - available -= n_bytes_copied+1; - len += n_bytes_copied+1; + len += ret; + if(len >= STR_STORAGE_SIZE) + { + len = STR_STORAGE_SIZE; + break; + } - argv += sizeof(compat_uptr_t); + argv += sizeof(argv); } + if(len>0) + { + str_storage[len-1] = '\0'; + } + else + { + str_storage[0] = '\0'; + } return len; } - #endif static uint32_t ppm_get_tty(void) @@ -991,8 +1001,8 @@ int f_proc_startupdate(struct event_filler_arguments *args) args_len = mm->arg_end - mm->arg_start; if (args_len) { - if (args_len > PAGE_SIZE) - args_len = PAGE_SIZE; + if (args_len > STR_STORAGE_SIZE) + args_len = STR_STORAGE_SIZE; if (unlikely(ppm_copy_from_user(args->str_storage, (const void __user *)mm->arg_start, args_len))) args_len = 0; @@ -1002,7 +1012,7 @@ int f_proc_startupdate(struct event_filler_arguments *args) } else { /* - * The execve or execveat call failed. I get exe, args from the + * The execve or execveat call failed. We get exe, args from the * input args; put one \0-separated exe-args string into * str_storage */ @@ -1025,20 +1035,18 @@ int f_proc_startupdate(struct event_filler_arguments *args) #ifdef CONFIG_COMPAT if (unlikely(args->compat)) args_len = compat_accumulate_argv_or_env((compat_uptr_t)val, - args->str_storage, available); + args->str_storage); else #endif - args_len = accumulate_argv_or_env((const char __user * __user *)val, - args->str_storage, available); - - if (unlikely(args_len < 0)) - args_len = 0; + args_len = accumulate_argv_or_env((const char __user *)val, + args->str_storage); } if (args_len == 0) *args->str_storage = 0; exe_len = strnlen(args->str_storage, args_len); + // we add the `\0` terminator if (exe_len < args_len) ++exe_len; @@ -1301,8 +1309,8 @@ int f_proc_startupdate(struct event_filler_arguments *args) env_len = mm->env_end - mm->env_start; if (env_len) { - if (env_len > PAGE_SIZE) - env_len = PAGE_SIZE; + if (env_len > STR_STORAGE_SIZE) + env_len = STR_STORAGE_SIZE; if (unlikely(ppm_copy_from_user(args->str_storage, (const void __user *)mm->env_start, env_len))) env_len = 0; @@ -1326,18 +1334,15 @@ int f_proc_startupdate(struct event_filler_arguments *args) default: val = 0; break; - } + } #ifdef CONFIG_COMPAT if (unlikely(args->compat)) env_len = compat_accumulate_argv_or_env((compat_uptr_t)val, - args->str_storage, available); + args->str_storage); else #endif - env_len = accumulate_argv_or_env((const char __user * __user *)val, - args->str_storage, available); - - if (unlikely(env_len < 0)) - env_len = 0; + env_len = accumulate_argv_or_env((const char __user *)val, + args->str_storage); } if (env_len == 0) @@ -7315,9 +7320,9 @@ int f_sched_prog_exec(struct event_filler_arguments *args) /* the combined length of the arguments string + executable string. */ args_len = mm->arg_end - mm->arg_start; - if(args_len > PAGE_SIZE) + if(args_len > STR_STORAGE_SIZE) { - args_len = PAGE_SIZE; + args_len = STR_STORAGE_SIZE; } correctly_read = ppm_copy_from_user(args->str_storage, (const void __user *)mm->arg_start, args_len); @@ -7418,9 +7423,9 @@ int f_sched_prog_exec(struct event_filler_arguments *args) CHECK_RES(res); env_len = mm->env_end - mm->env_start; - if(env_len > PAGE_SIZE) + if(env_len > STR_STORAGE_SIZE) { - env_len = PAGE_SIZE; + env_len = STR_STORAGE_SIZE; } correctly_read = ppm_copy_from_user(args->str_storage, (const void __user *)mm->env_start, env_len); @@ -7669,9 +7674,9 @@ int f_sched_prog_fork(struct event_filler_arguments *args) /* the combined length of the arguments string + executable string. */ args_len = mm->arg_end - mm->arg_start; - if(args_len > PAGE_SIZE) + if(args_len > STR_STORAGE_SIZE) { - args_len = PAGE_SIZE; + args_len = STR_STORAGE_SIZE; } correctly_read = ppm_copy_from_user(args->str_storage, (const void __user *)mm->arg_start, args_len); @@ -7687,6 +7692,7 @@ int f_sched_prog_fork(struct event_filler_arguments *args) } exe_len = strnlen(args->str_storage, args_len); + // we add the `\0` terminator if(exe_len < args_len) { ++exe_len; diff --git a/test/drivers/event_class/event_class.cpp b/test/drivers/event_class/event_class.cpp index 612cf39225..4e0228876b 100644 --- a/test/drivers/event_class/event_class.cpp +++ b/test/drivers/event_class/event_class.cpp @@ -20,6 +20,7 @@ static_assert(sizeof(cgroup_prefix_array) / sizeof(*cgroup_prefix_array) == CGRO /* Messages. */ #define VALUE_NOT_CORRECT ">>>>> value of the param is not correct. Param id = " +#define LEN_NOT_CORRECT ">>>>> len of the param is not correct. Param id = " #define VALUE_NOT_ZERO ">>>>> value of the param must not be zero. Param id = " extern const syscall_evt_pair g_syscall_table[SYSCALL_TABLE_SIZE]; @@ -592,6 +593,7 @@ void event_test::assert_charbuf_array_param(int param_num, const char** param) break; } /* We can use `STREQ` because every `charbuf` is `\0` terminated. */ + ASSERT_EQ(strlen(m_event_params[m_current_param].valptr + total_len), strlen(param[index])) << LEN_NOT_CORRECT << m_current_param << std::endl; ASSERT_STREQ(m_event_params[m_current_param].valptr + total_len, param[index]) << VALUE_NOT_CORRECT << m_current_param << std::endl; total_len += strlen(param[index]) + 1; } diff --git a/test/drivers/test_suites/generic_tracepoints_suite/sched_process_exec.cpp b/test/drivers/test_suites/generic_tracepoints_suite/sched_process_exec.cpp index c10de200ed..e95dab99b6 100644 --- a/test/drivers/test_suites/generic_tracepoints_suite/sched_process_exec.cpp +++ b/test/drivers/test_suites/generic_tracepoints_suite/sched_process_exec.cpp @@ -14,10 +14,18 @@ TEST(GenericTracepoints, sched_proc_exec) /*=============================== TRIGGER SYSCALL ===========================*/ /* Prepare the execve args */ - const char *pathname = "/usr/bin/echo"; - const char *comm = "echo"; - const char *argv[] = {pathname, "[OUTPUT] GenericTracepoints.sched_proc_exec test", NULL}; - const char *envp[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; + const char *pathname = "/usr/bin/true"; + const char *comm = "true"; + + std::string too_long_arg (4096, 'x'); + const char *newargv[] = {pathname, "", "first_argv", "", too_long_arg.c_str(), "second_argv", NULL}; + std::string truncated_too_long_arg (4096 - (strlen(pathname)+1) - (strlen("first_argv")+1) - 2*(strlen("")+1) - 1, 'x'); + const char *expected_newargv[] = {pathname, "", "first_argv", "", truncated_too_long_arg.c_str(), NULL}; + + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", too_long_arg.c_str(), "2_ARGUMENT=no", NULL}; + std::string truncated_too_long_env (4096 - (strlen("IN_TEST=yes")+1) - (strlen("3_ARGUMENT=yes")+1) - 1, 'x'); + const char *expected_newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", truncated_too_long_env.c_str(), NULL}; + /* We need to use `SIGCHLD` otherwise the parent won't receive any signal * when the child terminates. @@ -28,7 +36,7 @@ TEST(GenericTracepoints, sched_proc_exec) if(ret_pid == 0) { - syscall(__NR_execve, pathname, argv, envp); + syscall(__NR_execve, pathname, newargv, newenviron); exit(EXIT_FAILURE); } @@ -72,7 +80,7 @@ TEST(GenericTracepoints, sched_proc_exec) /* Parameter 3: args (type: PT_CHARBUFARRAY) */ /* Starting from `1` because the first is `exe`. */ - evt_test->assert_charbuf_array_param(3, &argv[1]); + evt_test->assert_charbuf_array_param(3, &expected_newargv[1]); /* Parameter 4: tid (type: PT_PID) */ evt_test->assert_numeric_param(4, (int64_t)ret_pid); @@ -92,7 +100,7 @@ TEST(GenericTracepoints, sched_proc_exec) evt_test->assert_charbuf_param(14, comm); /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - evt_test->assert_charbuf_array_param(16, &envp[0]); + evt_test->assert_charbuf_array_param(16, &expected_newenviron[0]); /* PPM_EXE_WRITABLE is set when the user that executed a process can also write to the executable * file that is used to spawn it or is its owner or otherwise capable. diff --git a/test/drivers/test_suites/syscall_exit_suite/execve_x.cpp b/test/drivers/test_suites/syscall_exit_suite/execve_x.cpp index 0bfbeeb3e8..674c0c2817 100644 --- a/test/drivers/test_suites/syscall_exit_suite/execve_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/execve_x.cpp @@ -41,8 +41,16 @@ TEST(SyscallExit, execveX_failure) * Call the `execve` */ char pathname[] = "//**null-file-path**//"; - const char *newargv[] = {pathname, "first_argv", "second_argv", NULL}; - const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; + + std::string too_long_arg (4096, 'x'); + const char *newargv[] = {pathname, "", "first_argv", "", too_long_arg.c_str(), "second_argv", NULL}; + std::string truncated_too_long_arg (4096 - (strlen(pathname)+1) - (strlen("first_argv")+1) - 2*(strlen("")+1) - 1, 'x'); + const char *expected_newargv[] = {pathname, "", "first_argv", "", truncated_too_long_arg.c_str(), NULL}; + + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", too_long_arg.c_str(), "2_ARGUMENT=no", NULL}; + std::string truncated_too_long_env (4096 - (strlen("IN_TEST=yes")+1) - (strlen("3_ARGUMENT=yes")+1) - 1, 'x'); + const char *expected_newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", truncated_too_long_env.c_str(), NULL}; + assert_syscall_state(SYSCALL_FAILURE, "execve", syscall(__NR_execve, pathname, newargv, newenviron)); int64_t errno_value = -errno; @@ -71,7 +79,7 @@ TEST(SyscallExit, execveX_failure) /* Parameter 3: args (type: PT_CHARBUFARRAY) */ /* Starting from `1` because the first is `exe`. */ - evt_test->assert_charbuf_array_param(3, &newargv[1]); + evt_test->assert_charbuf_array_param(3, &expected_newargv[1]); /* Parameter 4: tid (type: PT_PID) */ evt_test->assert_numeric_param(4, (int64_t)pid); @@ -113,8 +121,8 @@ TEST(SyscallExit, execveX_failure) /* Parameter 15: cgroups (type: PT_CHARBUFARRAY) */ evt_test->assert_cgroup_param(15); - /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - evt_test->assert_charbuf_array_param(16, &newenviron[0]); + /* Parameter 16: env (type: PT_CHARBUFARRAY) */ + evt_test->assert_charbuf_array_param(16, &expected_newenviron[0]); /* Parameter 17: tty (type: PT_UINT32) */ evt_test->assert_numeric_param(17, (uint32_t)info.tty); @@ -161,6 +169,101 @@ TEST(SyscallExit, execveX_failure) evt_test->assert_num_params_pushed(28); } +TEST(SyscallExit, execveX_failure_args_env_NULL) +{ + auto evt_test = get_syscall_event_test(__NR_execve, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + char pathname[] = "//args_env_NULL//"; + assert_syscall_state(SYSCALL_FAILURE, "execve", syscall(__NR_execve, pathname, NULL, NULL)); + 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: exe (type: PT_CHARBUF) */ + /* exe is taken from the args and not from the pathname. */ + evt_test->assert_charbuf_param(2, ""); + + /* Parameter 3: args (type: PT_CHARBUFARRAY) */ + evt_test->assert_empty_param(3); + + /* Parameter 16: env (type: PT_CHARBUFARRAY) */ + evt_test->assert_empty_param(16); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(28); +} + +TEST(SyscallExit, execveX_failure_path_NULL_but_not_args) +{ + auto evt_test = get_syscall_event_test(__NR_execve, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + + char pathname[] = "//path_NULL_but_not_args//"; + const char *newargv[] = {"", NULL}; + const char *newenviron[] = {"", NULL}; + assert_syscall_state(SYSCALL_FAILURE, "execve", syscall(__NR_execve, pathname, newargv, newenviron)); + 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: exe (type: PT_CHARBUF) */ + evt_test->assert_charbuf_param(2, ""); + + /* Parameter 3: args (type: PT_CHARBUFARRAY) */ + evt_test->assert_empty_param(3); + + /* Parameter 16: env (type: PT_CHARBUFARRAY) */ + evt_test->assert_charbuf_array_param(16, &newenviron[0]); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(28); +} + TEST(SyscallExit, execveX_success) { auto evt_test = get_syscall_event_test(__NR_execve, EXIT_EVENT); @@ -170,10 +273,17 @@ TEST(SyscallExit, execveX_success) /*=============================== TRIGGER SYSCALL ===========================*/ /* Prepare the execve args */ - const char *pathname = "/usr/bin/echo"; - const char *comm = "echo"; - const char *argv[] = {pathname, "[OUTPUT] SyscallExit.execveX_success test", NULL}; - const char *envp[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; + const char *pathname = "/usr/bin/true"; + const char *comm = "true"; + + std::string too_long_arg (4096, 'x'); + const char *newargv[] = {pathname, "", "first_argv", "", too_long_arg.c_str(), "second_argv", NULL}; + std::string truncated_too_long_arg (4096 - (strlen(pathname)+1) - (strlen("first_argv")+1) - 2*(strlen("")+1) - 1, 'x'); + const char *expected_newargv[] = {pathname, "", "first_argv", "", truncated_too_long_arg.c_str(), NULL}; + + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", too_long_arg.c_str(), "2_ARGUMENT=no", NULL}; + std::string truncated_too_long_env (4096 - (strlen("IN_TEST=yes")+1) - (strlen("3_ARGUMENT=yes")+1) - 1, 'x'); + const char *expected_newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", truncated_too_long_env.c_str(), NULL}; /* We need to use `SIGCHLD` otherwise the parent won't receive any signal * when the child terminates. @@ -184,7 +294,7 @@ TEST(SyscallExit, execveX_success) if(ret_pid == 0) { - syscall(__NR_execve, pathname, argv, envp); + syscall(__NR_execve, pathname, newargv, newenviron); exit(EXIT_FAILURE); } @@ -228,7 +338,7 @@ TEST(SyscallExit, execveX_success) /* Parameter 3: args (type: PT_CHARBUFARRAY) */ /* Starting from `1` because the first is `exe`. */ - evt_test->assert_charbuf_array_param(3, &argv[1]); + evt_test->assert_charbuf_array_param(3, &expected_newargv[1]); /* Parameter 4: tid (type: PT_PID) */ evt_test->assert_numeric_param(4, (int64_t)ret_pid); @@ -251,7 +361,7 @@ TEST(SyscallExit, execveX_success) evt_test->assert_cgroup_param(15); /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - evt_test->assert_charbuf_array_param(16, &envp[0]); + evt_test->assert_charbuf_array_param(16, &expected_newenviron[0]); /* PPM_EXE_WRITABLE is set when the user that executed a process can also write to the executable * file that is used to spawn it or is its owner or otherwise capable. @@ -913,7 +1023,7 @@ TEST(SyscallExit, execveX_failure_empty_arg) /* * Call the `execve` */ - char pathname[] = "//**null-file-path**//"; + char pathname[] = ""; const char *newargv[] = {pathname, "first_argv", "second_argv", "", "fourth_argv", NULL}; const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", "", "0_ARGUMENT=no", NULL}; assert_syscall_state(SYSCALL_FAILURE, "execve", syscall(__NR_execve, pathname, newargv, newenviron)); diff --git a/test/drivers/test_suites/syscall_exit_suite/execveat_x.cpp b/test/drivers/test_suites/syscall_exit_suite/execveat_x.cpp index 2c2790c4f7..3d06673691 100644 --- a/test/drivers/test_suites/syscall_exit_suite/execveat_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/execveat_x.cpp @@ -42,8 +42,15 @@ TEST(SyscallExit, execveatX_failure) */ int dirfd = AT_FDCWD; char pathname[] = "//**null-file-path**//"; - const char *newargv[] = {pathname, "first_argv", "second_argv", NULL}; - const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; + std::string too_long_arg (4096, 'x'); + const char *newargv[] = {pathname, "", "first_argv", "", too_long_arg.c_str(), "second_argv", NULL}; + std::string truncated_too_long_arg (4096 - (strlen(pathname)+1) - (strlen("first_argv")+1) - 2*(strlen("")+1) - 1, 'x'); + const char *expected_newargv[] = {pathname, "", "first_argv", "", truncated_too_long_arg.c_str(), NULL}; + + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", too_long_arg.c_str(), "2_ARGUMENT=no", NULL}; + std::string truncated_too_long_env (4096 - (strlen("IN_TEST=yes")+1) - (strlen("3_ARGUMENT=yes")+1) - 1, 'x'); + const char *expected_newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", truncated_too_long_env.c_str(), NULL}; + int flags = AT_SYMLINK_NOFOLLOW; assert_syscall_state(SYSCALL_FAILURE, "execveat", syscall(__NR_execveat, dirfd, pathname, newargv, newenviron, flags)); int64_t errno_value = -errno; @@ -73,7 +80,7 @@ TEST(SyscallExit, execveatX_failure) /* Parameter 3: args (type: PT_CHARBUFARRAY) */ /* Starting from `1` because the first is `exe`. */ - evt_test->assert_charbuf_array_param(3, &newargv[1]); + evt_test->assert_charbuf_array_param(3, &expected_newargv[1]); /* Parameter 4: tid (type: PT_PID) */ evt_test->assert_numeric_param(4, (int64_t)pid); @@ -116,7 +123,7 @@ TEST(SyscallExit, execveatX_failure) evt_test->assert_cgroup_param(15); /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - evt_test->assert_charbuf_array_param(16, &newenviron[0]); + evt_test->assert_charbuf_array_param(16, &expected_newenviron[0]); /* Parameter 17: tty (type: PT_UINT32) */ evt_test->assert_numeric_param(17, (uint32_t)info.tty); @@ -177,9 +184,12 @@ TEST(SyscallExit, execveatX_correct_exit) /* Prepare the execve args */ int dirfd = 0; - const char *pathname = "/usr/bin/echo"; - const char *argv[] = {pathname, "[OUTPUT] SyscallExit.execveatX_success test", NULL}; - const char *envp[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; + const char *pathname = "/usr/bin/test"; + + std::string too_long_arg (4096, 'x'); + const char *newargv[] = {pathname, "", "first_argv", "", too_long_arg.c_str(), "second_argv", NULL}; + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", too_long_arg.c_str(), "2_ARGUMENT=no", NULL}; + int flags = 0; /* We need to use `SIGCHLD` otherwise the parent won't receive any signal @@ -191,7 +201,7 @@ TEST(SyscallExit, execveatX_correct_exit) if(ret_pid == 0) { - syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); + syscall(__NR_execveat, dirfd, pathname, newargv, newenviron, flags); exit(EXIT_FAILURE); } @@ -226,7 +236,7 @@ TEST(SyscallExit, execveatX_correct_exit) /*=============================== ASSERT PARAMETERS ===========================*/ - const char *comm = "echo"; + const char *comm = "test"; /* Please note here we cannot assert all the params, we check only the possible ones. */ @@ -238,7 +248,9 @@ TEST(SyscallExit, execveatX_correct_exit) /* Parameter 3: args (type: PT_CHARBUFARRAY) */ /* Starting from `1` because the first is `exe`. */ - evt_test->assert_charbuf_array_param(3, &argv[1]); + std::string truncated_too_long_arg (4096 - (strlen(pathname)+1) - (strlen("first_argv")+1) - 2*(strlen("")+1) - 1, 'x'); + const char *expected_newargv[] = {pathname, "", "first_argv", "", truncated_too_long_arg.c_str(), NULL}; + evt_test->assert_charbuf_array_param(3, &expected_newargv[1]); /* Parameter 4: tid (type: PT_PID) */ evt_test->assert_numeric_param(4, (int64_t)ret_pid); @@ -261,7 +273,9 @@ TEST(SyscallExit, execveatX_correct_exit) evt_test->assert_cgroup_param(15); /* Parameter 16: env (type: PT_CHARBUFARRAY) */ - evt_test->assert_charbuf_array_param(16, &envp[0]); + std::string truncated_too_long_env (4096 - (strlen("IN_TEST=yes")+1) - (strlen("3_ARGUMENT=yes")+1) - 1, 'x'); + const char *expected_newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", truncated_too_long_env.c_str(), NULL}; + evt_test->assert_charbuf_array_param(16, &expected_newenviron[0]); /* PPM_EXE_WRITABLE is set when the user that executed a process can also write to the executable * file that is used to spawn it or is its owner or otherwise capable.