diff --git a/test/modern_bpf/test_suites/syscall_exit_suite/execve_x.cpp b/test/modern_bpf/test_suites/syscall_exit_suite/execve_x.cpp index 9b71186825..752034e901 100644 --- a/test/modern_bpf/test_suites/syscall_exit_suite/execve_x.cpp +++ b/test/modern_bpf/test_suites/syscall_exit_suite/execve_x.cpp @@ -4,7 +4,7 @@ #if defined(__NR_execve) && defined(__NR_capget) -TEST(SyscallExit, execveX) +TEST(SyscallExit, execveX_failure) { auto evt_test = get_syscall_event_test(__NR_execve, EXIT_EVENT); @@ -38,8 +38,8 @@ TEST(SyscallExit, execveX) * 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}; + const char *newargv[] = {pathname, "first_argv", "second_argv", NULL}; + const char *newenviron[] = {"IN_TEST=yes", "3_ARGUMENT=yes", "2_ARGUMENT=no", NULL}; assert_syscall_state(SYSCALL_FAILURE, "execve", syscall(__NR_execve, pathname, newargv, newenviron)); int64_t errno_value = -errno; @@ -139,4 +139,108 @@ TEST(SyscallExit, execveX) evt_test->assert_num_params_pushed(23); } + +#if !defined(CAPTURE_SCHED_PROC_EXEC) && defined(__NR_clone3) && defined(__NR_wait4) + +#include + +TEST(SyscallExit, execveX_success) +{ + auto evt_test = get_syscall_event_test(__NR_execve, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== 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}; + + /* We need to use `SIGCHLD` otherwise the parent won't receive any signal + * when the child terminates. + */ + struct clone_args cl_args = {0}; + cl_args.exit_signal = SIGCHLD; + pid_t ret_pid = syscall(__NR_clone3, &cl_args, sizeof(cl_args)); + + if(ret_pid == 0) + { + syscall(__NR_execve, pathname, argv, envp); + exit(EXIT_FAILURE); + } + + assert_syscall_state(SYSCALL_SUCCESS, "clone3", ret_pid, NOT_EQUAL, -1); + + /* Catch the child before doing anything else. */ + int status = 0; + int options = 0; + assert_syscall_state(SYSCALL_SUCCESS, "wait4", syscall(__NR_wait4, ret_pid, &status, options, NULL), NOT_EQUAL, -1); + + if(__WEXITSTATUS(status) == EXIT_FAILURE) + { + FAIL() << "The child execve failed." << std::endl; + } + + /*=============================== TRIGGER SYSCALL ===========================*/ + + evt_test->disable_capture(); + + /* We search for a child event. */ + evt_test->assert_event_presence(ret_pid); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Please note here we cannot assert all the params, we check only the possible ones. */ + + /* Parameter 1: res (type: PT_ERRNO)*/ + evt_test->assert_numeric_param(1, (int64_t)0); + + /* Parameter 2: exe (type: PT_CHARBUF) */ + evt_test->assert_charbuf_param(2, pathname); + + /* Parameter 3: args (type: PT_CHARBUFARRAY) */ + /* Starting from `1` because the first is `exe`. */ + evt_test->assert_charbuf_array_param(3, &argv[1]); + + /* Parameter 4: tid (type: PT_PID) */ + evt_test->assert_numeric_param(4, (int64_t)ret_pid); + + /* Parameter 5: pid (type: PT_PID) */ + /* We are the main thread of the process so it's equal to `tid`. */ + evt_test->assert_numeric_param(5, (int64_t)ret_pid); + + /* Parameter 6: ptid (type: PT_PID) */ + evt_test->assert_numeric_param(6, (int64_t)::getpid()); + + /* Parameter 7: cwd (type: PT_CHARBUF) */ + /* leave the current working directory empty like in the old probe. */ + evt_test->assert_empty_param(7); + + /* Parameter 14: comm (type: PT_CHARBUF) */ + evt_test->assert_charbuf_param(14, comm); + + /* Parameter 16: env (type: PT_CHARBUFARRAY) */ + evt_test->assert_charbuf_array_param(16, &envp[0]); + + /* Parameter 20: flags (type: PT_UINT32) */ + /* Right now we send always `0`. */ + evt_test->assert_numeric_param(20, (uint32_t)0); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(23); +} +#endif + #endif