From f180ff5983b94781c0a03e046fec1cb9e274f114 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 1 Apr 2026 17:29:45 +0200 Subject: [PATCH] sd-varlink: fix fd handling in upgrade code path This commit fixes an issue with the fd handling in sd_varlink_call_and_upgrade() when one direction of the output FDs is unset. Thanks to Lennart for spotting this and suggesting the fix. --- src/libsystemd/sd-varlink/sd-varlink.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 64606adcea..4beb785199 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -2452,26 +2452,30 @@ _public_ int sd_varlink_call_and_upgrade( } } - /* Handle the case where the caller is not interested in one of the fds. We need - * to consider the case when (input_fd == output_fd) just clear the alias - * rather than closing it, since the other branch may hand it out. */ + /* Hand out the fds to the caller. When the caller doesn't want one direction, shut it + * down: but avoid closing the underlying fd if the other direction still needs it + * (i.e. when input_fd == output_fd). */ bool same_fd = v->input_fd == v->output_fd; if (ret_input_fd) *ret_input_fd = TAKE_FD(v->input_fd); - else if (!same_fd) { + else { (void) shutdown(v->input_fd, SHUT_RD); - v->input_fd = safe_close(v->input_fd); - } else - v->input_fd = -EBADF; + if (same_fd && ret_output_fd) + TAKE_FD(v->input_fd); /* don't close yet, output branch needs it */ + else + v->input_fd = safe_close(v->input_fd); + } if (ret_output_fd) *ret_output_fd = TAKE_FD(v->output_fd); - else if (!same_fd) { + else { (void) shutdown(v->output_fd, SHUT_WR); - v->output_fd = safe_close(v->output_fd); - } else - v->output_fd = -EBADF; + if (same_fd && ret_input_fd) + TAKE_FD(v->output_fd); + else + v->output_fd = safe_close(v->output_fd); + } varlink_set_state(v, VARLINK_DISCONNECTED); assert(v->n_pending == 1);