From cc8428fe61fea8dd76ea2581e20474484132f64f Mon Sep 17 00:00:00 2001 From: Leonardo Di Giovanna Date: Mon, 22 Dec 2025 17:42:12 +0100 Subject: [PATCH] fix(userspace/libsinsp/parsers): guard against invalid cmsg_len values Guard against invalid `cmsg_len` values while accessing control messages in ancillary data. This is achieved by checking there is enough space between the current control message and the end of the buffer to hold both the current control message and the next one. This change sync the implementation of `ppm_cmsg_nxthdr()` with the current glibc implementation: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/cmsg_nxthdr.c;h=0e602a16053ed6742ea1556d75de8540e49157f1;hb=170550da27f68a08589e91b541883dcc58dee640 Signed-off-by: Leonardo Di Giovanna --- userspace/libsinsp/parsers.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index cb93b9e58d..15f14efcfb 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -3180,6 +3180,11 @@ struct ppm_cmsghdr { #define PPM_CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~(sizeof(size_t) - 1)) +// Given a length, return the additional padding necessary such that +// `len + __PPM_CMSG_PADDING(len) == PPM_CMSG_ALIGN(len)`. +#define __PPM_CMSG_PADDING(len) \ + ((sizeof(size_t) - ((len) & (sizeof(size_t) - 1))) & (sizeof(size_t) - 1)) + #define PPM_CMSG_NXTHDR(msg_control, msg_controllen, cmsg) \ ppm_cmsg_nxthdr(msg_control, msg_controllen, cmsg) static ppm_cmsghdr *ppm_cmsg_nxthdr(char const *msg_control, @@ -3191,17 +3196,18 @@ static ppm_cmsghdr *ppm_cmsg_nxthdr(char const *msg_control, return nullptr; } - size_t const cmsg_aligned_len = PPM_CMSG_ALIGN(cmsg_len); - // Guard against infinite loop: ensure we advance by at least sizeof(ppm_cmsghdr) - if(cmsg_aligned_len < sizeof(ppm_cmsghdr)) { - return nullptr; - } - cmsg = reinterpret_cast(reinterpret_cast(cmsg) + cmsg_aligned_len); - if(reinterpret_cast(cmsg + 1) > msg_control + msg_controllen || - reinterpret_cast(cmsg) + cmsg_aligned_len > msg_control + msg_controllen) { + // Check that there is enough space between cmsg and the end of the buffer to hold the current + // cmsg *and* the next one. + const size_t size_needed = sizeof(ppm_cmsghdr) + __PPM_CMSG_PADDING(cmsg_len); + const size_t remaining_room = + static_cast(msg_control + msg_controllen - reinterpret_cast(cmsg)); + if(remaining_room < size_needed || remaining_room - size_needed < cmsg_len) { return nullptr; } - return cmsg; + + // Now, we trust cmsg_len and can use it to find the next header. + return reinterpret_cast(reinterpret_cast(cmsg) + + PPM_CMSG_ALIGN(cmsg_len)); } #define PPM_CMSG_DATA(cmsg) ((char *)((ppm_cmsghdr *)(cmsg) + 1))