diff --git a/driver/event_table.c b/driver/event_table.c index 479d7a1d43..3863c0e8cf 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -453,8 +453,8 @@ const struct ppm_event_info g_event_info[] = { [PPME_SYSCALL_PRCTL_X] = {"prctl", EC_PROCESS | EC_SYSCALL, EF_MODIFIES_STATE, 4, {{"res", PT_ERRNO, PF_DEC}, {"option", PT_ENUMFLAGS32, PF_DEC, prctl_options}, {"arg2_str", PT_CHARBUF, PF_NA}, {"arg2_int", PT_INT64, PF_DEC} } }, [PPME_ASYNCEVENT_E] = {"asyncevent", EC_OTHER | EC_METAEVENT, EF_LARGE_PAYLOAD, 3, {{"plugin_id", PT_UINT32, PF_DEC}, {"name", PT_CHARBUF, PF_NA}, {"data", PT_BYTEBUF, PF_NA} } }, [PPME_ASYNCEVENT_X] = {"NA", EC_UNKNOWN, EF_UNUSED, 0}, - [PPME_SYSCALL_MEMFD_CREATE_E] = {"memfd_create", EC_MEMORY | EC_SYSCALL, EF_CREATES_FD, 0}, - [PPME_SYSCALL_MEMFD_CREATE_X] = {"memfd_create", EC_MEMORY | EC_SYSCALL, EF_CREATES_FD, 3, {{"fd",PT_FD,PF_DEC},{"name", PT_CHARBUF, PF_NA},{"flags", PT_FLAGS32, PF_HEX, memfd_create_flags} } }, + [PPME_SYSCALL_MEMFD_CREATE_E] = {"memfd_create", EC_MEMORY | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 0}, + [PPME_SYSCALL_MEMFD_CREATE_X] = {"memfd_create", EC_MEMORY | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 3, {{"fd",PT_FD,PF_DEC},{"name", PT_CHARBUF, PF_NA},{"flags", PT_FLAGS32, PF_HEX, memfd_create_flags} } }, [PPME_SYSCALL_PIDFD_GETFD_E] = {"pidfd_getfd", EC_PROCESS | EC_SYSCALL, EF_CREATES_FD , 0}, [PPME_SYSCALL_PIDFD_GETFD_X] = {"pidfd_getfd", EC_PROCESS | EC_SYSCALL, EF_CREATES_FD , 4, {{"fd", PT_FD, PF_DEC}, {"pid_fd", PT_FD, PF_DEC}, {"target_fd", PT_FD, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX}}} }; diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 892fa2d7e8..1bd5c15d8f 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -171,6 +171,7 @@ typedef enum scap_fd_type SCAP_FD_BPF = 17, SCAP_FD_USERFAULTFD = 18, SCAP_FD_IOURING = 19, + SCAP_FD_MEMFD = 20 }scap_fd_type; /*! diff --git a/userspace/libsinsp/fdinfo.cpp b/userspace/libsinsp/fdinfo.cpp index 75289c3c94..d65da8c8d1 100644 --- a/userspace/libsinsp/fdinfo.cpp +++ b/userspace/libsinsp/fdinfo.cpp @@ -105,6 +105,8 @@ template<> char sinsp_fdinfo_t::get_typechar() return CHAR_FD_USERFAULTFD; case SCAP_FD_IOURING: return CHAR_FD_IO_URING; + case SCAP_FD_MEMFD: + return CHAR_FD_MEMFD; default: // ASSERT(false); return '?'; @@ -148,6 +150,8 @@ template<> char* sinsp_fdinfo_t::get_typestring() return (char*)"userfaultfd"; case SCAP_FD_IOURING: return (char*)"io_uring"; + case SCAP_FD_MEMFD: + return (char*)"memfd"; default: return (char*)""; } diff --git a/userspace/libsinsp/fdinfo.h b/userspace/libsinsp/fdinfo.h index 8cac70346e..2d51a92cde 100644 --- a/userspace/libsinsp/fdinfo.h +++ b/userspace/libsinsp/fdinfo.h @@ -48,6 +48,7 @@ class sinsp_protodecoder; #define CHAR_FD_BPF 'b' #define CHAR_FD_USERFAULTFD 'u' #define CHAR_FD_IO_URING 'r' +#define CHAR_FD_MEMFD 'm' /** @defgroup state State management * A collection of classes to query process and FD state. diff --git a/userspace/libsinsp/filterchecks.cpp b/userspace/libsinsp/filterchecks.cpp index 8f6dd03db6..70d5301168 100644 --- a/userspace/libsinsp/filterchecks.cpp +++ b/userspace/libsinsp/filterchecks.cpp @@ -464,8 +464,8 @@ bool sinsp_filter_check_fspath::extract_fspath(sinsp_evt* evt, const filtercheck_field_info sinsp_filter_check_fd_fields[] = { {PT_INT64, EPF_NONE, PF_ID, "fd.num", "FD Number", "the unique number identifying the file descriptor."}, - {PT_CHARBUF, EPF_NONE, PF_DEC, "fd.type", "FD Type", "type of FD. Can be 'file', 'directory', 'ipv4', 'ipv6', 'unix', 'pipe', 'event', 'signalfd', 'eventpoll', 'inotify' or 'signalfd'."}, - {PT_CHARBUF, EPF_NONE, PF_DEC, "fd.typechar", "FD Type Char", "type of FD as a single character. Can be 'f' for file, 4 for IPv4 socket, 6 for IPv6 socket, 'u' for unix socket, p for pipe, 'e' for eventfd, 's' for signalfd, 'l' for eventpoll, 'i' for inotify, 'b' for bpf, 'u' for userfaultd, 'r' for io_uring, 'o' for unknown."}, + {PT_CHARBUF, EPF_NONE, PF_DEC, "fd.type", "FD Type", "type of FD. Can be 'file', 'directory', 'ipv4', 'ipv6', 'unix', 'pipe', 'event', 'signalfd', 'eventpoll', 'inotify' 'signalfd' or 'memfd'."}, + {PT_CHARBUF, EPF_NONE, PF_DEC, "fd.typechar", "FD Type Char", "type of FD as a single character. Can be 'f' for file, 4 for IPv4 socket, 6 for IPv6 socket, 'u' for unix socket, p for pipe, 'e' for eventfd, 's' for signalfd, 'l' for eventpoll, 'i' for inotify, 'b' for bpf, 'u' for userfaultd, 'r' for io_uring, 'm' for memfd ,'o' for unknown."}, {PT_CHARBUF, EPF_NONE, PF_NA, "fd.name", "FD Name", "FD full name. If the fd is a file, this field contains the full path. If the FD is a socket, this field contain the connection tuple."}, {PT_CHARBUF, EPF_NONE, PF_NA, "fd.directory", "FD Directory", "If the fd is a file, the directory that contains it."}, {PT_CHARBUF, EPF_NONE, PF_NA, "fd.filename", "FD Filename", "If the fd is a file, the filename without the path."}, diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index 8c1fe361e3..2ef06c7a93 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -337,6 +337,9 @@ void sinsp_parser::process_event(sinsp_evt *evt) case PPME_SYSCALL_SETNS_X: parse_unshare_setns_exit(evt); break; + case PPME_SYSCALL_MEMFD_CREATE_X: + parse_memfd_create_exit(evt, SCAP_FD_MEMFD); + break; case PPME_SYSCALL_CLONE_11_X: case PPME_SYSCALL_CLONE_16_X: case PPME_SYSCALL_CLONE_17_X: @@ -6025,3 +6028,56 @@ void sinsp_parser::free_event_buffer(uint8_t *ptr) free(ptr); } } + +void sinsp_parser::parse_memfd_create_exit(sinsp_evt *evt, scap_fd_type type) +{ + sinsp_evt_param* parinfo; + int64_t fd; + char *name; + uint32_t flags; + sinsp_fdinfo_t fdi; + + + ASSERT(evt->m_tinfo) + if(evt->m_tinfo == nullptr) + { + return; + } + + /* ret (fd) */ + parinfo = evt->get_param(0); + ASSERT(parinfo->m_len == sizeof(int64_t)); + ASSERT(evt->get_param_info(0)->type == PT_FD); + fd = *(int64_t *)parinfo->m_val; + + /* name */ + /* + Suppose you create a memfd named libstest resulting in a fd.name libstest while on disk + (e.g. ls -l /proc/$PID/fd/$FD_NUM) it may look like /memfd:libstest (deleted) + */ + parinfo = evt->get_param(1); + name = parinfo->m_val; + + /* flags */ + parinfo = evt->get_param(2); + ASSERT(parinfo->m_len == sizeof(uint32_t)); + flags = *(uint32_t *)parinfo->m_val; + + if(fd >= 0) + { + fdi.m_type = type; + fdi.add_filename(name); + fdi.m_openflags = flags; + } + + if(fdi.m_name == USER_EVT_DEVICE_NAME) + { + fdi.m_flags |= sinsp_fdinfo_t::FLAGS_IS_TRACER_FILE; + } + else + { + fdi.m_flags |= sinsp_fdinfo_t::FLAGS_IS_NOT_TRACER_FD; + } + + evt->m_fdinfo = evt->m_tinfo->add_fd(fd, &fdi); +} \ No newline at end of file diff --git a/userspace/libsinsp/parsers.h b/userspace/libsinsp/parsers.h index 2454c090d0..57ba2b9fbf 100644 --- a/userspace/libsinsp/parsers.h +++ b/userspace/libsinsp/parsers.h @@ -108,6 +108,7 @@ class sinsp_parser void parse_close_enter(sinsp_evt* evt); void parse_close_exit(sinsp_evt* evt); void parse_thread_exit(sinsp_evt* evt); + void parse_memfd_create_exit(sinsp_evt* evt, scap_fd_type type); inline bool detect_and_process_tracer_write(sinsp_evt *evt, int64_t retval, ppm_event_flags eflags); void parse_fspath_related_exit(sinsp_evt* evt); inline void parse_rw_exit(sinsp_evt* evt); diff --git a/userspace/libsinsp/test/events_file.ut.cpp b/userspace/libsinsp/test/events_file.ut.cpp index 73dc9081de..3fee062038 100644 --- a/userspace/libsinsp/test/events_file.ut.cpp +++ b/userspace/libsinsp/test/events_file.ut.cpp @@ -625,3 +625,22 @@ TEST_F(sinsp_with_test_input, fchown) ASSERT_EQ(get_field_as_string(evt, "fd.name"), "/tmp/test"); ASSERT_EQ(get_field_as_string(evt, "fd.num"), "3"); } + +TEST_F(sinsp_with_test_input, memfd_create) +{ + add_default_init_thread(); + open_inspector(); + sinsp_evt* evt = NULL; + const char *name = "test_name"; + int64_t fd = 4; + + add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_MEMFD_CREATE_E, 0); + evt = add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_MEMFD_CREATE_X, 3, fd, name, 0); + + ASSERT_EQ(evt->get_type(), PPME_SYSCALL_MEMFD_CREATE_X); + ASSERT_EQ(get_field_as_string(evt, "fd.num"), std::to_string(fd)); + ASSERT_EQ(get_field_as_string(evt, "fd.name"), name); + ASSERT_EQ(get_field_as_string(evt, "fd.typechar"), "m"); + ASSERT_EQ(get_field_as_string(evt, "fd.type"), "memfd"); + +} \ No newline at end of file diff --git a/userspace/libsinsp/test/public_sinsp_API/ppm_sc_codes.cpp b/userspace/libsinsp/test/public_sinsp_API/ppm_sc_codes.cpp index c8ebf4240e..b205b1d2ae 100644 --- a/userspace/libsinsp/test/public_sinsp_API/ppm_sc_codes.cpp +++ b/userspace/libsinsp/test/public_sinsp_API/ppm_sc_codes.cpp @@ -205,6 +205,8 @@ const libsinsp::events::set expected_sinsp_state_event_set = { PPME_SYSCALL_PRCTL_E, PPME_SYSCALL_PRCTL_X, PPME_ASYNCEVENT_E, + PPME_SYSCALL_MEMFD_CREATE_E, + PPME_SYSCALL_MEMFD_CREATE_X }; const libsinsp::events::set expected_sinsp_state_sc_set = { @@ -271,6 +273,7 @@ const libsinsp::events::set expected_sinsp_state_sc_set = { PPM_SC_EPOLL_CREATE1, PPM_SC_SCHED_PROCESS_EXIT, PPM_SC_PRCTL, + PPM_SC_MEMFD_CREATE }; const libsinsp::events::set expected_unknown_event_set = {