From 43e08aea6e194b15195220288a8204aff9263fe2 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 27 Jan 2026 19:01:18 +0100 Subject: [PATCH 1/3] sd-bus/bus-socket: restore recvmsg_safe() during auth At auth stage we reject any fds, hence either way the connection would fail. Let's play it safe and check for MSG_(C)TRUNC still. --- src/libsystemd/sd-bus/bus-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 45f74cc7c7..e1ef6b8189 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -657,7 +657,7 @@ static int bus_socket_read_auth(sd_bus *b) { .msg_controllen = sizeof(control), }; - k = RET_NERRNO(recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC)); + k = recvmsg_safe(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (k == -ENOTSOCK) { b->prefer_readv = true; k = readv(b->input_fd, &iov, 1); From f452c324e71db04bbc754d9ae7f710ec168c8b44 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 28 Jan 2026 03:01:06 +0100 Subject: [PATCH 2/3] sd-bus/bus-socket: reinstate MSG_TRUNC handling in bus_socket_read_message() We switched away from recvmsg_safe() in order to gracefully handle MSG_CTRUNC. But MSG_TRUNC really shouldn't happen. While at it, do not use RET_NERRNO with ssize_t. --- src/libsystemd/sd-bus/bus-socket.c | 46 ++++++++++++++---------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index e1ef6b8189..4cac317dff 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -1397,14 +1397,8 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) { } int bus_socket_read_message(sd_bus *bus) { - struct msghdr mh; - struct iovec iov = {}; - ssize_t k; size_t need; int r; - void *b; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control; - bool handle_cmsg = false; assert(bus); assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); @@ -1416,19 +1410,18 @@ int bus_socket_read_message(sd_bus *bus) { if (bus->rbuffer_size >= need) return bus_socket_make_message(bus, need); - b = realloc(bus->rbuffer, need); + void *b = realloc(bus->rbuffer, need); if (!b) return -ENOMEM; - bus->rbuffer = b; - iov = IOVEC_MAKE((uint8_t *)bus->rbuffer + bus->rbuffer_size, need - bus->rbuffer_size); + struct iovec iov = IOVEC_MAKE((uint8_t*) bus->rbuffer + bus->rbuffer_size, need - bus->rbuffer_size); + CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control; + struct msghdr mh; + bool handle_cmsg = false; + ssize_t k; - if (bus->prefer_readv) { - k = readv(bus->input_fd, &iov, 1); - if (k < 0) - k = -errno; - } else { + if (!bus->prefer_readv) { mh = (struct msghdr) { .msg_iov = &iov, .msg_iovlen = 1, @@ -1436,24 +1429,29 @@ int bus_socket_read_message(sd_bus *bus) { .msg_controllen = sizeof(control), }; - k = RET_NERRNO(recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC)); - if (k == -ENOTSOCK) { + k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (k < 0 && errno == ENOTSOCK) bus->prefer_readv = true; - k = readv(bus->input_fd, &iov, 1); - if (k < 0) - k = -errno; - } else + else handle_cmsg = true; } - if (ERRNO_IS_NEG_TRANSIENT(k)) - return 0; - if (k < 0) - return (int) k; + if (bus->prefer_readv) + k = readv(bus->input_fd, &iov, 1); + if (k < 0) { + if (ERRNO_IS_TRANSIENT(errno)) + return 0; + + return -errno; + } if (k == 0) { if (handle_cmsg) cmsg_close_all(&mh); /* On EOF we shouldn't have gotten an fd, but let's make sure */ return -ECONNRESET; } + if (handle_cmsg && FLAGS_SET(mh.msg_flags, MSG_TRUNC)) { + cmsg_close_all(&mh); + return -EXFULL; + } bus->rbuffer_size += k; From c49c8331b978440434b9667582f087226c301eb5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 27 Jan 2026 19:10:41 +0100 Subject: [PATCH 3/3] sd-bus/bus-message: more prudently verify it's SCM_RIGHTS that got truncated Follow-up for 6c8de404c98fb9b965cba68360c2db1e3f55b776 As discussed in https://github.com/systemd/systemd/pull/40089#issuecomment-3672063388, if any other control msg got truncated it's a genuine error, and we should reject the message as a whole. --- src/libsystemd/sd-bus/bus-message.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 9d71823b38..69975c5371 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -4210,15 +4210,19 @@ static int message_parse_fields(sd_bus_message *m, bool got_ctrunc) { "Received a bus message with too many fds: %" PRIu32 " received vs. %" PRIu32 " declared", m->n_fds, n_unix_fds_declared); - if (m->n_fds < n_unix_fds_declared && !got_ctrunc) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), - "Received a bus message with too few fds: %" PRIu32 " received vs. %" PRIu32 " declared", - m->n_fds, n_unix_fds_declared); + if (m->n_fds < n_unix_fds_declared) { + if (!got_ctrunc) + return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), + "Received a bus message with too few fds: %" PRIu32 " received vs. %" PRIu32 " declared", + m->n_fds, n_unix_fds_declared); - if (got_ctrunc) log_error("Received a bus message with MSG_CTRUNC set with %" PRIu32 " fds received vs %" PRIu32 " declared", m->n_fds, n_unix_fds_declared); + } else if (got_ctrunc) + return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), + "Received a bus message with truncated control data, refusing."); + switch (m->header->type) { case SD_BUS_MESSAGE_SIGNAL: