Skip to content

Commit b49f986

Browse files
committed
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 between cmsg and the end of the buffer to hold the current cmsg 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 <[email protected]>
1 parent 9e6a8cc commit b49f986

File tree

1 file changed

+15
-9
lines changed

1 file changed

+15
-9
lines changed

userspace/libsinsp/parsers.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3180,6 +3180,11 @@ struct ppm_cmsghdr {
31803180

31813181
#define PPM_CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~(sizeof(size_t) - 1))
31823182

3183+
// Given a length, return the additional padding necessary such that
3184+
// `len + __PPM_CMSG_PADDING(len) == PPM_CMSG_ALIGN(len)`.
3185+
#define __PPM_CMSG_PADDING(len) \
3186+
((sizeof(size_t) - ((len) & (sizeof(size_t) - 1))) & (sizeof(size_t) - 1))
3187+
31833188
#define PPM_CMSG_NXTHDR(msg_control, msg_controllen, cmsg) \
31843189
ppm_cmsg_nxthdr(msg_control, msg_controllen, cmsg)
31853190
static ppm_cmsghdr *ppm_cmsg_nxthdr(char const *msg_control,
@@ -3191,17 +3196,18 @@ static ppm_cmsghdr *ppm_cmsg_nxthdr(char const *msg_control,
31913196
return nullptr;
31923197
}
31933198

3194-
size_t const cmsg_aligned_len = PPM_CMSG_ALIGN(cmsg_len);
3195-
// Guard against infinite loop: ensure we advance by at least sizeof(ppm_cmsghdr)
3196-
if(cmsg_aligned_len < sizeof(ppm_cmsghdr)) {
3197-
return nullptr;
3198-
}
3199-
cmsg = reinterpret_cast<ppm_cmsghdr *>(reinterpret_cast<char *>(cmsg) + cmsg_aligned_len);
3200-
if(reinterpret_cast<char *>(cmsg + 1) > msg_control + msg_controllen ||
3201-
reinterpret_cast<char *>(cmsg) + cmsg_aligned_len > msg_control + msg_controllen) {
3199+
// There isn't enough space between cmsg and the end of the buffer to hold the current cmsg
3200+
// *and* the next one.
3201+
const size_t size_needed = sizeof(ppm_cmsghdr) + __PPM_CMSG_PADDING(cmsg_len);
3202+
const size_t remaining_room =
3203+
static_cast<size_t>(msg_control + msg_controllen - reinterpret_cast<char *>(cmsg));
3204+
if(remaining_room < size_needed || remaining_room - size_needed < cmsg_len) {
32023205
return nullptr;
32033206
}
3204-
return cmsg;
3207+
3208+
// Now, we trust cmsg_len and can use it to find the next header.
3209+
return reinterpret_cast<ppm_cmsghdr *>(reinterpret_cast<char *>(cmsg) +
3210+
PPM_CMSG_ALIGN(cmsg_len));
32053211
}
32063212

32073213
#define PPM_CMSG_DATA(cmsg) ((char *)((ppm_cmsghdr *)(cmsg) + 1))

0 commit comments

Comments
 (0)