From 1eeb4f9f47ebd05418ff459630d40e509645b37b Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 29 Mar 2025 21:33:58 +0100 Subject: [PATCH] socket-util: introduce socket_autobind() helper Prompted by https://github.com/systemd/systemd/pull/36858#discussion_r2017719305 and #36833 --- src/basic/socket-util.c | 31 +++++++++++++++++++++++++++++++ src/basic/socket-util.h | 2 ++ src/notify/notify.c | 11 ++--------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c095168ed19..3160f922988 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -28,6 +28,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "random-util.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -1454,6 +1455,36 @@ int socket_bind_to_ifindex(int fd, int ifindex) { return setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex); } +int socket_autobind(int fd, char **ret_name) { + _cleanup_free_ char *name = NULL; + uint64_t random; + int r; + + /* Generate a random abstract socket name and bind fd to it. This is modeled after the kernel + * "autobind" feature, but uses 64-bit random number internally. */ + + assert(fd >= 0); + assert(ret_name); + + random = random_u64(); + + if (asprintf(&name, "@%" PRIu64, random) < 0) + return -ENOMEM; + + union sockaddr_union sa; + assert_cc(DECIMAL_STR_MAX(uint64_t) < sizeof(sa.un.sun_path)); + + r = sockaddr_un_set_path(&sa.un, name); + if (r < 0) + return r; + + if (bind(fd, &sa.sa, r) < 0) + return -errno; + + *ret_name = TAKE_PTR(name); + return 0; +} + ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { ssize_t n; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index e21a4427f0d..c5e389ca3a7 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -322,6 +322,8 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) { int socket_bind_to_ifname(int fd, const char *ifname); 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; diff --git a/src/notify/notify.c b/src/notify/notify.c index b736bf704fb..2b7f1c4177d 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -506,17 +506,10 @@ static int action_fork(char *const *_command) { if (r < 0) log_debug_errno(r, "Failed to enable SO_PASSPIDFD, ignoring: %m"); - /* Pick an address via auto-bind */ - union sockaddr_union sa = { - .sa.sa_family = AF_UNIX, - }; - if (bind(socket_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path)) < 0) - return log_error_errno(errno, "Failed to bind AF_UNIX socket: %m"); - _cleanup_free_ char *addr_string = NULL; - r = getsockname_pretty(socket_fd, &addr_string); + r = socket_autobind(socket_fd, &addr_string); if (r < 0) - return log_error_errno(r, "Failed to get socket name: %m"); + return log_error_errno(r, "Failed to bind notify socket: %m"); _cleanup_free_ char *c = strv_join(command, " "); if (!c) -- 2.47.3