From 67ffd130ea53a4958ee177db57aed72194d7cc2a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 Nov 2026 17:07:50 +0100 Subject: [PATCH] tree-wide: use getsockopt_int() where appropriate Replace open-coded getsockopt() calls for int-typed socket options (SO_TYPE, SO_PROTOCOL, SO_DOMAIN, SO_ACCEPTCONN, SO_ERROR, SO_SNDBUF, SO_RCVBUF) with getsockopt_int(), which also validates the returned size. This also fixes an operator precedence issue in fd_set_sndbuf() and fd_set_rcvbuf(): "r >= 0 && l == sizeof(value) && increase ? a : b" parses as "(r >= 0 && l == sizeof(value) && increase) ? a : b", hence with increase=false the possibly uninitialized value was compared even if getsockopt() failed. --- src/basic/socket-util.c | 46 ++++++++++---------------- src/libsystemd/sd-bus/bus-socket.c | 6 ++-- src/libsystemd/sd-daemon/sd-daemon.c | 23 +++++-------- src/libsystemd/sd-event/event-future.c | 4 +-- src/libsystemd/sd-varlink/sd-varlink.c | 16 ++++----- src/resolve/resolved-dns-stream.c | 8 +++-- src/socket-proxy/socket-proxyd.c | 9 +++-- 7 files changed, 46 insertions(+), 66 deletions(-) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 4015aebbf10..743376a53c3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -331,7 +331,6 @@ bool socket_ipv6_is_enabled(void) { bool socket_address_matches_fd(const SocketAddress *a, int fd) { SocketAddress b; - socklen_t solen; assert(a); assert(fd >= 0); @@ -343,16 +342,14 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family) return false; - solen = sizeof(b.type); - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0) + if (getsockopt_int(fd, SOL_SOCKET, SO_TYPE, &b.type) < 0) return false; if (b.type != a->type) return false; if (a->protocol != 0) { - solen = sizeof(b.protocol); - if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0) + if (getsockopt_int(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol) < 0) return false; if (b.protocol != a->protocol) @@ -699,13 +696,12 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b int fd_set_sndbuf(int fd, size_t n, bool increase) { int r, value; - socklen_t l = sizeof(value); if (n > INT_MAX) return -ERANGE; - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + if (getsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, &value) >= 0 && + (increase ? (size_t) value >= n*2 : (size_t) value == n*2)) return 0; /* First, try to set the buffer size with SO_SNDBUF. */ @@ -715,9 +711,8 @@ int fd_set_sndbuf(int fd, size_t n, bool increase) { /* SO_SNDBUF above may set to the kernel limit, instead of the requested size. * So, we need to check the actual buffer size here. */ - l = sizeof(value); - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + if (getsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, &value) >= 0 && + (increase ? (size_t) value >= n*2 : (size_t) value == n*2)) return 1; /* If we have the privileges we will ignore the kernel limit. */ @@ -730,13 +725,12 @@ int fd_set_sndbuf(int fd, size_t n, bool increase) { int fd_set_rcvbuf(int fd, size_t n, bool increase) { int r, value; - socklen_t l = sizeof(value); if (n > INT_MAX) return -ERANGE; - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + if (getsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, &value) >= 0 && + (increase ? (size_t) value >= n*2 : (size_t) value == n*2)) return 0; /* First, try to set the buffer size with SO_RCVBUF. */ @@ -746,9 +740,8 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) { /* SO_RCVBUF above may set to the kernel limit, instead of the requested size. * So, we need to check the actual buffer size here. */ - l = sizeof(value); - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + if (getsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, &value) >= 0 && + (increase ? (size_t) value >= n*2 : (size_t) value == n*2)) return 1; /* If we have the privileges we will ignore the kernel limit. */ @@ -1141,15 +1134,13 @@ fallback: int flush_accept(int fd) { int r, b; - socklen_t l = sizeof(b); /* Similar to flush_fd() but flushes all incoming connections by accepting and immediately closing * them. */ - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0) - return -errno; - - assert(l == sizeof(b)); + r = getsockopt_int(fd, SOL_SOCKET, SO_ACCEPTCONN, &b); + if (r < 0) + return r; if (!b) /* Let's check if this socket accepts connections before calling accept(). accept4() can * return EOPNOTSUPP if the fd is not a listening socket, which we should treat as a fatal * error, or in case the incoming TCP connection triggered a network issue, which we want to @@ -1493,14 +1484,11 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { } int socket_get_family(int fd) { - int af; - socklen_t sl = sizeof(af); + int af, r; - if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &af, &sl) < 0) - return -errno; - - if (sl != sizeof(af)) - return -EINVAL; + r = getsockopt_int(fd, SOL_SOCKET, SO_DOMAIN, &af); + if (r < 0) + return r; return af; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index dccba6384c7..8de918d80a4 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -26,6 +26,7 @@ #include "path-util.h" #include "process-util.h" #include "random-util.h" +#include "socket-util.h" #include "stdio-util.h" #include "string-util.h" #include "time-util.h" @@ -1476,7 +1477,6 @@ int bus_socket_read_message(sd_bus *bus) { int bus_socket_process_opening(sd_bus *b) { int error = 0, events, r; - socklen_t slen = sizeof(error); assert(b->state == BUS_OPENING); @@ -1488,9 +1488,9 @@ int bus_socket_process_opening(sd_bus *b) { if (!(events & (POLLOUT|POLLERR|POLLHUP))) return 0; - r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen); + r = getsockopt_int(b->output_fd, SOL_SOCKET, SO_ERROR, &error); if (r < 0) - b->last_connect_error = errno; + b->last_connect_error = -r; else if (error != 0) b->last_connect_error = error; else if (events & (POLLERR|POLLHUP)) diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 1819f03501e..80855620a6e 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -210,6 +210,7 @@ _public_ int sd_is_special(int fd, const char *path) { static int is_socket_internal(int fd, int type, int listening) { struct stat st_fd; + int r; assert_return(fd >= 0, -EBADF); assert_return(type >= 0, -EINVAL); @@ -221,28 +222,22 @@ static int is_socket_internal(int fd, int type, int listening) { return 0; if (type != 0) { - int other_type = 0; - socklen_t l = sizeof(other_type); + int other_type; - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) - return -errno; - - if (l != sizeof(other_type)) - return -EINVAL; + r = getsockopt_int(fd, SOL_SOCKET, SO_TYPE, &other_type); + if (r < 0) + return r; if (other_type != type) return 0; } if (listening >= 0) { - int accepting = 0; - socklen_t l = sizeof(accepting); + int accepting; - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) - return -errno; - - if (l != sizeof(accepting)) - return -EINVAL; + r = getsockopt_int(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting); + if (r < 0) + return r; if (!accepting != !listening) return 0; diff --git a/src/libsystemd/sd-event/event-future.c b/src/libsystemd/sd-event/event-future.c index 55c39f14daf..3179e5c16bb 100644 --- a/src/libsystemd/sd-event/event-future.c +++ b/src/libsystemd/sd-event/event-future.c @@ -10,6 +10,7 @@ #include "event-util.h" #include "fd-util.h" #include "pidref.h" +#include "socket-util.h" #include "time-util.h" int event_source_inherit_fiber_priority(sd_event_source *s) { @@ -68,9 +69,8 @@ static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userda * directly without re-querying. */ if (FLAGS_SET(revents, EPOLLERR)) { int error = 0; - socklen_t len = sizeof(error); - int r = RET_NERRNO(getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len)); + int r = getsockopt_int(fd, SOL_SOCKET, SO_ERROR, &error); if (r == -ENOTSOCK) return sd_future_resolve(f, (int) revents); if (r >= 0 && error != 0) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 76b892f9f65..01c906821da 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -3852,17 +3852,15 @@ _public_ int sd_varlink_server_listen_name(sd_varlink_server *s, const char *nam for (int i = 0; i < m; i++) { int b, fd; - socklen_t l = sizeof(b); if (!streq(names[i], name)) continue; fd = SD_LISTEN_FDS_START + i; - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0) - return -errno; - - assert(l == sizeof(b)); + r = getsockopt_int(fd, SOL_SOCKET, SO_ACCEPTCONN, &b); + if (r < 0) + return r; if (b) /* Listening socket? */ r = sd_varlink_server_listen_fd(s, fd); @@ -4323,7 +4321,6 @@ _public_ int sd_varlink_server_set_description(sd_varlink_server *s, const char _public_ int sd_varlink_invocation(sd_varlink_invocation_flags_t flags) { _cleanup_strv_free_ char **names = NULL; int r, b; - socklen_t l = sizeof(b); /* Returns true if this is a "pure" varlink server invocation, i.e. with one fd passed. */ @@ -4348,10 +4345,9 @@ _public_ int sd_varlink_invocation(sd_varlink_invocation_flags_t flags) { if ((flags & (SD_VARLINK_ALLOW_LISTEN|SD_VARLINK_ALLOW_ACCEPT)) == 0) /* Neither is set, then fail */ return -EISCONN; - if (getsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0) - return -errno; - - assert(l == sizeof(b)); + r = getsockopt_int(SD_LISTEN_FDS_START, SOL_SOCKET, SO_ACCEPTCONN, &b); + if (r < 0) + return r; if (!FLAGS_SET(flags, b ? SD_VARLINK_ALLOW_LISTEN : SD_VARLINK_ALLOW_ACCEPT)) return -EISCONN; diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index aa31872336d..e0ac9fd08e9 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -16,6 +16,7 @@ #include "resolved-dns-stream.h" #include "resolved-manager.h" #include "set.h" +#include "socket-util.h" #include "time-util.h" #define DNS_STREAMS_MAX 128 @@ -333,9 +334,10 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use } if (revents & EPOLLERR) { - socklen_t errlen = sizeof(r); - if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &r, &errlen) == 0) - return dns_stream_complete(s, r); + int error; + + if (getsockopt_int(s->fd, SOL_SOCKET, SO_ERROR, &error) >= 0) + return dns_stream_complete(s, error); } if ((revents & EPOLLOUT) && diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index cf031305fc8..6dc930c5e45 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -270,15 +270,14 @@ static int connection_complete(Connection *c) { static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) { Connection *c = ASSERT_PTR(userdata); - socklen_t solen; - int error; + int error, r; assert(s); assert(fd >= 0); - solen = sizeof(error); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &solen) < 0) { - log_error_errno(errno, "Failed to issue SO_ERROR: %m"); + r = getsockopt_int(fd, SOL_SOCKET, SO_ERROR, &error); + if (r < 0) { + log_error_errno(r, "Failed to issue SO_ERROR: %m"); goto fail; }