basic/socket-util: reserve more space for timeval/timespec messages

As reported in https://github.com/systemd/systemd/issues/38222, we get the
buffer size calculation wrong on 32-bit arm. The reporter suggested checking if
__TIMESIZE == 64, but I think it's better to just use the bigger size in all
cases. The code to guesstimate the buffer size was already tweaked a few times
and apparently it's not easy to get it right. Systemd and glibc might be
compiled with different combinations of __TIMESIZE, so the compile-time check
is not super reliable, and by using the bigger size, we don't depend on the
details of how glibc decided whether to duplicate the struct or not. The cost
is negligible, 16 bytes on stack, so let's do the easy and robust thing.

Solution based on the suggestion by UZver24.

While at it, drop the mock struct definitions. They are only used to calculate
the size, but since the types involved are 8-bit values, there are no alignment
issues and we can just calculate the size directly.

Fixes https://github.com/systemd/systemd/issues/38222.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2025-07-18 02:06:37 +09:00
committed by Yu Watanabe
parent 9b31b3d5ee
commit 0c927c98a7
+2 -16
View File
@@ -254,27 +254,13 @@ int socket_bind_to_ifindex(int fd, int ifindex);
int socket_autobind(int fd, char **ret_name);
/* Define a 64-bit version of timeval/timespec in any case, even on 32-bit userspace. */
struct timeval_large {
uint64_t tvl_sec, tvl_usec;
};
struct timespec_large {
uint64_t tvl_sec, tvl_nsec;
};
/* glibc duplicates timespec/timeval on certain 32-bit arches, once in 32-bit and once in 64-bit.
* See __convert_scm_timestamps() in glibc source code. Hence, we need additional buffer space for them
* to prevent truncating control msg (recvmsg() MSG_CTRUNC). */
#define CMSG_SPACE_TIMEVAL \
((sizeof(struct timeval) == sizeof(struct timeval_large)) ? \
CMSG_SPACE(sizeof(struct timeval)) : \
CMSG_SPACE(sizeof(struct timeval)) + \
CMSG_SPACE(sizeof(struct timeval_large)))
(CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(2 * sizeof(uint64_t)))
#define CMSG_SPACE_TIMESPEC \
((sizeof(struct timespec) == sizeof(struct timespec_large)) ? \
CMSG_SPACE(sizeof(struct timespec)) : \
CMSG_SPACE(sizeof(struct timespec)) + \
CMSG_SPACE(sizeof(struct timespec_large)))
(CMSG_SPACE(sizeof(struct timespec)) + CMSG_SPACE(2 * sizeof(uint64_t)))
ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);