From 9288fb8337afcd1a3241835046cb63cd667e995f Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 25 Oct 2022 09:22:35 +0000 Subject: [PATCH] update(userspace): support `execveat` exit event for `s390x` Signed-off-by: Andrea Terzolo --- userspace/libsinsp/parsers.cpp | 18 ++-- userspace/libsinsp/test/sinsp.ut.cpp | 153 +++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 6 deletions(-) diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index ec42010d28..1159f4dea5 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -1711,9 +1711,9 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) ASSERT(parinfo->m_len == sizeof(int64_t)); retval = *(int64_t *)parinfo->m_val; - /* Please note here we will never parse an `PPME_SYSCALL_EXECVEAT_X` event since it is - * generated only in case of failure, here if `retval<0` we return immediately. - * If we remove this `if` we need to support also the `PPME_SYSCALL_EXECVEAT_X` event. + /* Some architectures like s390x send a `PPME_SYSCALL_EXECVEAT_X` exit event + * when the `execveat` syscall succeeds, for this reason, we need to manage also + * this event in the parser. */ if(retval < 0) { @@ -1721,7 +1721,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) } // - // We get here when `execve` return. The thread has already been added by a previous fork or clone, + // We get here when `execve` or `execveat` return. The thread has already been added by a previous fork or clone, // and we just update the entry with the new information. // if(!evt->m_tinfo) @@ -1754,6 +1754,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) case PPME_SYSCALL_EXECVE_17_X: case PPME_SYSCALL_EXECVE_18_X: case PPME_SYSCALL_EXECVE_19_X: + case PPME_SYSCALL_EXECVEAT_X: // Get the comm parinfo = evt->get_param(13); evt->m_tinfo->m_comm = parinfo->m_val; @@ -1799,6 +1800,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) case PPME_SYSCALL_EXECVE_17_X: case PPME_SYSCALL_EXECVE_18_X: case PPME_SYSCALL_EXECVE_19_X: + case PPME_SYSCALL_EXECVEAT_X: // Get the pgflt_maj parinfo = evt->get_param(8); ASSERT(parinfo->m_len == sizeof(uint64_t)); @@ -1847,6 +1849,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) case PPME_SYSCALL_EXECVE_17_X: case PPME_SYSCALL_EXECVE_18_X: case PPME_SYSCALL_EXECVE_19_X: + case PPME_SYSCALL_EXECVEAT_X: // Get the environment parinfo = evt->get_param(15); evt->m_tinfo->set_env(parinfo->m_val, parinfo->m_len); @@ -1884,6 +1887,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) case PPME_SYSCALL_EXECVE_17_X: case PPME_SYSCALL_EXECVE_18_X: case PPME_SYSCALL_EXECVE_19_X: + case PPME_SYSCALL_EXECVEAT_X: // Get the tty parinfo = evt->get_param(16); ASSERT(parinfo->m_len == sizeof(int32_t)); @@ -1903,7 +1907,8 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) * we can do nothing. */ if((etype == PPME_SYSCALL_EXECVE_18_X || - etype == PPME_SYSCALL_EXECVE_19_X) + etype == PPME_SYSCALL_EXECVE_19_X || + etype == PPME_SYSCALL_EXECVEAT_X) && retrieve_enter_event(enter_evt, evt)) { @@ -2036,6 +2041,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) case PPME_SYSCALL_EXECVE_18_X: break; case PPME_SYSCALL_EXECVE_19_X: + case PPME_SYSCALL_EXECVEAT_X: // Get the vpgid parinfo = evt->get_param(17); ASSERT(parinfo->m_len == sizeof(int64_t)); @@ -2077,7 +2083,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) // Get capabilities if(evt->get_num_params() > 22) { - if(etype == PPME_SYSCALL_EXECVE_19_X) + if(etype == PPME_SYSCALL_EXECVE_19_X || etype == PPME_SYSCALL_EXECVEAT_X) { parinfo = evt->get_param(20); ASSERT(parinfo->m_len == sizeof(uint64_t)); diff --git a/userspace/libsinsp/test/sinsp.ut.cpp b/userspace/libsinsp/test/sinsp.ut.cpp index 7803ee3fc0..f10fe25319 100644 --- a/userspace/libsinsp/test/sinsp.ut.cpp +++ b/userspace/libsinsp/test/sinsp.ut.cpp @@ -511,6 +511,159 @@ TEST_F(sinsp_with_test_input, execveat_invalid_path) } } +/* Same as `execveat_empty_path_flag` but with `PPME_SYSCALL_EXECVEAT_X` as exit event + * since on s390x architectures the `execveat` syscall correctly returns a `PPME_SYSCALL_EXECVEAT_X` + * exit event in case of success. + */ +TEST_F(sinsp_with_test_input, execveat_empty_path_flag_s390) +{ + add_default_init_thread(); + + open_inspector(); + sinsp_evt *evt = NULL; + + /* We generate a `dirfd` associated with the file that + * we want to run with the `execveat`, + */ + int64_t dirfd = 3; + const char *file_to_run = "/tmp/s390x/file_to_run"; + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_E, 3, file_to_run, 0, 0); + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_X, 6, dirfd, file_to_run, 0, 0, 0, 0); + + /* Now we call the `execveat_e` event,`sinsp` will store this enter + * event in the thread storage, in this way the exit event can use it. + */ + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_E, 3, dirfd, "", PPM_EXVAT_AT_EMPTY_PATH); + + struct scap_const_sized_buffer empty_bytebuf = {nullptr, 0}; + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_X, 23, 0, "", empty_bytebuf, 1, 1, 1, "", 0, 0, 0, 0, 0, 0, "", empty_bytebuf, empty_bytebuf, 0, 0, 0, 0, 0, 0, 0); + + /* The `exepath` should be the file pointed by the `dirfd` since `execveat` is called with + * `AT_EMPTY_PATH` flag. + */ + if(evt->get_thread_info()) + { + ASSERT_STREQ(evt->get_thread_info()->m_exepath.c_str(), file_to_run); + } + else + { + FAIL(); + } +} + +/* Same as `execveat_relative_path` but with `PPME_SYSCALL_EXECVEAT_X` as exit event + * since on s390x architectures the `execveat` syscall correctly returns a `PPME_SYSCALL_EXECVEAT_X` + * exit event in case of success. + */ +TEST_F(sinsp_with_test_input, execveat_relative_path_s390) +{ + add_default_init_thread(); + + open_inspector(); + sinsp_evt *evt = NULL; + + /* We generate a `dirfd` associated with the directory that contains the file that + * we want to run with the `execveat`, + */ + int64_t dirfd = 3; + const char *directory = "/tmp/s390x/dir"; + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_E, 3, directory, 0, 0); + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_X, 6, dirfd, directory, 0, 0, 0, 0); + + /* Now we call the `execveat_e` event,`sinsp` will store this enter + * event in the thread storage, in this way the exit event can use it. + */ + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_E, 3, dirfd, "file", 0); + + struct scap_const_sized_buffer empty_bytebuf = {nullptr, 0}; + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_X, 23, 0, "", empty_bytebuf, 1, 1, 1, "", 0, 0, 0, 0, 0, 0, "", empty_bytebuf, empty_bytebuf, 0, 0, 0, 0, 0, 0, 0); + + /* The `exepath` should be the directory pointed by the `dirfd` + the pathname + * specified in the `execveat` enter event. + */ + if(evt->get_thread_info()) + { + ASSERT_STREQ(evt->get_thread_info()->m_exepath.c_str(), "/tmp/s390x/dir/file"); + } + else + { + FAIL(); + } +} + +/* Same as `execveat_absolute_path` but with `PPME_SYSCALL_EXECVEAT_X` as exit event + * since on s390x architectures the `execveat` syscall correctly returns a `PPME_SYSCALL_EXECVEAT_X` + * exit event in case of success. + */ +TEST_F(sinsp_with_test_input, execveat_absolute_path_s390) +{ + add_default_init_thread(); + + open_inspector(); + sinsp_evt *evt = NULL; + + /* Now we call the `execveat_e` event,`sinsp` will store this enter + * event in the thread storage, in this way the exit event can use it. + */ + int invalid_dirfd = 0; + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_E, 3, invalid_dirfd, "/tmp/s390/file", 0); + + struct scap_const_sized_buffer empty_bytebuf = {nullptr, 0}; + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_X, 23, 0, "", empty_bytebuf, 1, 1, 1, "", 0, 0, 0, 0, 0, 0, "", empty_bytebuf, empty_bytebuf, 0, 0, 0, 0, 0, 0, 0); + + /* The `exepath` should be the absolute file path that we passed in the + * `execveat` enter event. + */ + if(evt->get_thread_info()) + { + ASSERT_STREQ(evt->get_thread_info()->m_exepath.c_str(), "/tmp/s390/file"); + } + else + { + FAIL(); + } +} + +/* Same as `execveat_invalid_path` but with `PPME_SYSCALL_EXECVEAT_X` as exit event + * since on s390x architectures the `execveat` syscall correctly returns a `PPME_SYSCALL_EXECVEAT_X` + * exit event in case of success. + */ +TEST_F(sinsp_with_test_input, execveat_invalid_path_s390) +{ + add_default_init_thread(); + + open_inspector(); + sinsp_evt *evt = NULL; + + /* We generate a `dirfd` associated with the directory that contains the file that + * we want to run with the `execveat`, + */ + int64_t dirfd = 3; + const char *directory = "/tmp/s390/dir"; + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_E, 3, directory, 0, 0); + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_X, 6, dirfd, directory, 0, 0, 0, 0); + + /* Now we call the `execveat_e` event,`sinsp` will store this enter + * event in the thread storage, in this way the exit event can use it. + */ + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_E, 3, dirfd, "", 0); + + struct scap_const_sized_buffer empty_bytebuf = {nullptr, 0}; + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_EXECVEAT_X, 23, 0, "", empty_bytebuf, 1, 1, 1, "", 0, 0, 0, 0, 0, 0, "", empty_bytebuf, empty_bytebuf, 0, 0, 0, 0, 0, 0, 0); + + /* The `exepath` should be ``, sinsp should recognize that the `pathname` + * is invalid and should set ``. + */ + if(evt->get_thread_info()) + { + ASSERT_STREQ(evt->get_thread_info()->m_exepath.c_str(), ""); + } + else + { + FAIL(); + } +} + TEST_F(sinsp_with_test_input, creates_fd_generic) { add_default_init_thread();