Skip to content

Commit

Permalink
feat(userspace/libsinsp): improve recvmsg SCM_RIGHTS cmsg handling
Browse files Browse the repository at this point in the history
Parse all control messages instead of parsing just the first one.
Leverage the new scap_get_fdinfo API to get info only from the file
in procfs associated to the file descriptor, instead of scanning each
time the entire procfs fd directory.

Signed-off-by: Leonardo Di Giovanna <[email protected]>
  • Loading branch information
ekoops committed Jan 29, 2025
1 parent 710a236 commit 9183259
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 34 deletions.
78 changes: 44 additions & 34 deletions userspace/libsinsp/parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3662,6 +3662,49 @@ void sinsp_parser::parse_fspath_related_exit(sinsp_evt *evt) {
}
}

#ifndef _WIN32
inline void sinsp_parser::process_recvmsg_ancillary_data(sinsp_evt *evt,

Check warning on line 3666 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3666

Added line #L3666 was not covered by tests
sinsp_evt_param const *parinfo) const {
// Create a msg header to be used with CMSG_* macros.
msghdr msgh;
memcpy(&msgh.msg_control, parinfo->m_val, sizeof(void *));
memcpy(&msgh.msg_controllen, &parinfo->m_len, sizeof(parinfo->m_len));

Check warning on line 3671 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3669-L3671

Added lines #L3669 - L3671 were not covered by tests
// Seek for SCM_RIGHTS control message headers and extract passed file
// descriptors.
for(cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
cmsghdr c;
memcpy(&c, cmsg, sizeof(cmsghdr));

Check warning on line 3676 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3675-L3676

Added lines #L3675 - L3676 were not covered by tests
if(c.cmsg_type == SCM_RIGHTS) {
char error[SCAP_LASTERR_SIZE];
scap_threadinfo scap_tinfo{};
memset(&scap_tinfo, 0, sizeof(scap_tinfo));
m_inspector->m_thread_manager->thread_to_scap(*evt->get_tinfo(), &scap_tinfo);

Check warning on line 3681 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3678-L3681

Added lines #L3678 - L3681 were not covered by tests
#define SCM_MAX_FD 253 // Taken from kernel.
int fds[SCM_MAX_FD];
unsigned long const data_size = c.cmsg_len - CMSG_LEN(0);
unsigned long const fds_len = data_size / sizeof(int);

Check warning on line 3685 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3683-L3685

Added lines #L3683 - L3685 were not covered by tests
// Guard against malformed event, by checking that data size is a multiple of
// sizeof(int) (file descriptor size) and the control message doesn't contain more data
// than allowed by kernel constraints.
if(data_size % sizeof(int) || fds_len > SCM_MAX_FD) {
continue;

Check warning on line 3690 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3690

Added line #L3690 was not covered by tests
}
#undef SCM_MAX_FD
memcpy(&fds, CMSG_DATA(&c), data_size);

Check warning on line 3693 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3693

Added line #L3693 was not covered by tests
for(int i = 0; i < fds_len; i++) {
if(scap_get_fdinfo(m_inspector->get_scap_platform(), &scap_tinfo, fds[i], error) !=
SCAP_SUCCESS) {
libsinsp_logger()->format(sinsp_logger::SEV_DEBUG,

Check warning on line 3697 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3697

Added line #L3697 was not covered by tests
"scap_get_fdinfo failed: %s, proc table will not be "
"updated with new fd.",
error);
}
}
}
}
}
#endif

void sinsp_parser::parse_rw_exit(sinsp_evt *evt) {
const sinsp_evt_param *parinfo;
int64_t retval;
Expand Down Expand Up @@ -3792,40 +3835,7 @@ void sinsp_parser::parse_rw_exit(sinsp_evt *evt) {

if(cmparam != -1) {
parinfo = evt->get_param(cmparam);
if(parinfo->m_len > sizeof(cmsghdr)) {
cmsghdr cmsg;
memcpy(&cmsg, parinfo->m_val, sizeof(cmsghdr));
if(cmsg.cmsg_type == SCM_RIGHTS) {
char error[SCAP_LASTERR_SIZE];
scap_threadinfo scap_tinfo{};

memset(&scap_tinfo, 0, sizeof(scap_tinfo));

m_inspector->m_thread_manager->thread_to_scap(*evt->get_tinfo(),
&scap_tinfo);

// Store current fd; it might get changed by scap_get_fdlist below.
int64_t fd = -1;
if(evt->get_fd_info()) {
fd = evt->get_fd_info()->m_fd;
}

// Get the new fds. The callbacks we have registered populate the fd table
// with the new file descriptors.
if(scap_get_fdlist(m_inspector->get_scap_platform(), &scap_tinfo, error) !=
SCAP_SUCCESS) {
libsinsp_logger()->format(sinsp_logger::SEV_DEBUG,
"scap_get_fdlist failed: %s, proc table will "
"not be updated with new fds.",
error);
}

// Force refresh event fdinfo
if(fd != -1) {
evt->set_fd_info(evt->get_tinfo()->get_fd(fd));
}
}
}
process_recvmsg_ancillary_data(evt, parinfo);

Check warning on line 3838 in userspace/libsinsp/parsers.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/parsers.cpp#L3838

Added line #L3838 was not covered by tests
}
#endif

Expand Down
5 changes: 5 additions & 0 deletions userspace/libsinsp/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ class sinsp_parser {
inline void add_pipe(sinsp_evt* evt, int64_t fd, uint64_t ino, uint32_t openflags);
// Return false if the update didn't happen (for example because the tuple is NULL)
bool update_fd(sinsp_evt* evt, const sinsp_evt_param* parinfo);
#ifndef _WIN32
// Process recvmsg ancillary data
inline void process_recvmsg_ancillary_data(sinsp_evt* evt,
sinsp_evt_param const* parinfo) const;
#endif

// Next 4 return false if the update didn't happen because the tuple is identical to the given
// address
Expand Down

0 comments on commit 9183259

Please sign in to comment.