diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index 1d2c31e6a7..ecb1c0fd9f 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -3664,53 +3664,58 @@ void sinsp_parser::parse_fspath_related_exit(sinsp_evt *evt) { #ifndef _WIN32 -// "No aligned" macros definitions. These macros are equivalent to the corresponding variants -// without the "no aligned suffix" but avoid unaligned access to the underlaying data. -extern struct cmsghdr *__cmsg_nxthdr_no_aligned(struct msghdr *__mhdr, - struct cmsghdr *__cmsg) __THROW; -#define CMSG_NXTHDR_NO_ALIGNED(mhdr, cmsg) __cmsg_nxthdr_no_aligned(mhdr, cmsg) -#ifdef __USE_EXTERN_INLINES -#ifndef _EXTERN_INLINE -#define _EXTERN_INLINE __extern_inline -#endif -_EXTERN_INLINE struct cmsghdr *__NTH(__cmsg_nxthdr_no_aligned(struct msghdr *__mhdr, - struct cmsghdr *__cmsg)) { +struct ppm_cmsghdr { + // Length of ppm_cmsghdr structure plus data following it. + size_t cmsg_len; + // Originating protocol. + int cmsg_level; + // Protocol specific type. + int cmsg_type; +}; + +// PPM_CMSG_* macros definitions. These macros are equivalent to the corresponding variants +// without PPM_* prefix, but they don't depend on msghdr definition as we don't need it at the +// moment. +#define PPM_CMSG_FIRSTHDR(msg_control, msg_controllen) \ + ((size_t)msg_controllen >= sizeof(struct ppm_cmsghdr) ? (struct ppm_cmsghdr *)msg_control \ + : (struct ppm_cmsghdr *)0) + +#define PPM_CMSG_UNALIGNED_ACCESS(cmsg, field, dest) \ + (memcpy((void *)&(dest), (cmsg) + offsetof(struct ppm_cmsghdr, field), sizeof((cmsg)->field))) + +#define PPM_CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~(sizeof(size_t) - 1)) + +#define PPM_CMSG_NXTHDR(msg_control, msg_controllen, cmsg) \ + __ppm_cmsg_nxthdr(msg_control, msg_controllen, cmsg) +static struct ppm_cmsghdr *__ppm_cmsg_nxthdr(void const *__msg_control, + size_t __msg_controllen, + struct ppm_cmsghdr *__cmsg) { size_t cmsg_len; - memcpy(&cmsg_len, __cmsg + offsetof(struct cmsghdr, cmsg_len), sizeof(size_t)); - if((size_t)cmsg_len < sizeof(struct cmsghdr)) + PPM_CMSG_UNALIGNED_ACCESS(__cmsg, cmsg_len, cmsg_len); + if(cmsg_len < sizeof(struct ppm_cmsghdr)) // The kernel header does this so there may be a reason. - return (struct cmsghdr *)0; + return (struct ppm_cmsghdr *)0; - __cmsg = (struct cmsghdr *)((unsigned char *)__cmsg + CMSG_ALIGN(cmsg_len)); - if((unsigned char *)(__cmsg + 1) > - ((unsigned char *)__mhdr->msg_control + __mhdr->msg_controllen) || - ((unsigned char *)__cmsg + CMSG_ALIGN(cmsg_len) > - ((unsigned char *)__mhdr->msg_control + __mhdr->msg_controllen))) + __cmsg = (struct ppm_cmsghdr *)((unsigned char *)__cmsg + PPM_CMSG_ALIGN(cmsg_len)); + if((unsigned char *)(__cmsg + 1) > ((unsigned char *)__msg_control + __msg_controllen) || + ((unsigned char *)__cmsg + PPM_CMSG_ALIGN(cmsg_len) > + ((unsigned char *)__msg_control + __msg_controllen))) // No more entries. - return (struct cmsghdr *)0; + return (struct ppm_cmsghdr *)0; return __cmsg; } -#endif // Use `extern inline'. -#if __glibc_c99_flexarr_available -#define CMSG_DATA_NO_ALIGNED(cmsg) (cmsg + offsetof(struct cmsghdr, __cmsg_data)) -#else -#define CMSG_DATA_NO_ALIGNED(cmsg) ((unsigned char *)((struct cmsghdr *)(cmsg) + 1)) -#endif +#define PPM_CMSG_DATA(cmsg) ((unsigned char *)((struct ppm_cmsghdr *)(cmsg) + 1)) inline void sinsp_parser::process_recvmsg_ancillary_data(sinsp_evt *evt, sinsp_evt_param const *parinfo) const { - // Create a msg header to be used with CMSG_* macros. - msghdr msgh; - msgh.msg_control = (void *)parinfo->m_val; - msgh.msg_controllen = parinfo->m_len; // Seek for SCM_RIGHTS control message headers and extract passed file descriptors. - for(cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != nullptr; - cmsg = CMSG_NXTHDR_NO_ALIGNED(&msgh, cmsg)) { - cmsghdr c; - memcpy(&c, cmsg, sizeof(cmsghdr)); - int const cmsg_type = c.cmsg_type; - size_t const cmsg_len = c.cmsg_len; + void const *msg_control = (void *)parinfo->m_val; + size_t msg_controllen = parinfo->m_len; + for(ppm_cmsghdr *cmsg = PPM_CMSG_FIRSTHDR(msg_control, msg_controllen); cmsg != nullptr; + cmsg = PPM_CMSG_NXTHDR(msg_control, msg_controllen, cmsg)) { + int cmsg_type; + PPM_CMSG_UNALIGNED_ACCESS(cmsg, cmsg_type, cmsg_type); if(cmsg_type == SCM_RIGHTS) { char error[SCAP_LASTERR_SIZE]; scap_threadinfo scap_tinfo{}; @@ -3718,16 +3723,18 @@ inline void sinsp_parser::process_recvmsg_ancillary_data(sinsp_evt *evt, m_inspector->m_thread_manager->thread_to_scap(*evt->get_tinfo(), &scap_tinfo); #define SCM_MAX_FD 253 // Taken from kernel. int fds[SCM_MAX_FD]; + size_t cmsg_len; + PPM_CMSG_UNALIGNED_ACCESS(cmsg, cmsg_len, cmsg_len); unsigned long const data_size = cmsg_len - CMSG_LEN(0); unsigned long const fds_len = data_size / sizeof(int); // 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. + // 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; } #undef SCM_MAX_FD - memcpy(&fds, CMSG_DATA_NO_ALIGNED(cmsg), data_size); + memcpy(&fds, PPM_CMSG_DATA(cmsg), data_size); for(unsigned long i = 0; i < fds_len; i++) { if(scap_get_fdinfo(m_inspector->get_scap_platform(), &scap_tinfo, fds[i], error) != SCAP_SUCCESS) {