From: Lennart Poettering Date: Tue, 10 May 2022 14:16:29 +0000 (+0200) Subject: socket-util: add new connect_unix_path() helper X-Git-Tag: v252-rc1~951^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2679aee440409b89b8922f268c3e27f4327f8093;p=thirdparty%2Fsystemd.git socket-util: add new connect_unix_path() helper This is a short helper for connecting to AF_UNIX sockets in the file system. It works around the 108ch limit of sockaddr_un, and supports "at" style fds. This doesn't come with a test of its own, but the next patch will add that. --- diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 0dfe2a7dbca..bd6d329d941 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1426,3 +1426,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) { *ret = (size_t) mtu; return 0; } + +int connect_unix_path(int fd, int dir_fd, const char *path) { + _cleanup_close_ int inode_fd = -1; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + size_t path_len; + socklen_t salen; + + assert(fd >= 0); + assert(dir_fd == AT_FDCWD || dir_fd >= 0); + assert(path); + + /* Connects to the specified AF_UNIX socket in the file system. Works around the 108 byte size limit + * in sockaddr_un, by going via O_PATH if needed. This hence works for any kind of path. */ + + path_len = strlen(path); + + /* Refuse zero length path early, to make sure AF_UNIX stack won't mistake this for an abstract + * namespace path, since first char is NUL */ + if (path_len <= 0) + return -EINVAL; + + if (dir_fd == AT_FDCWD && path_len < sizeof(sa.un.sun_path)) { + memcpy(sa.un.sun_path, path, path_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + path_len + 1; + } else { + const char *proc; + size_t proc_len; + + /* If dir_fd is specified, then we need to go the indirect O_PATH route, because connectat() + * does not exist. If the path is too long, we also need to take the indirect route, since we + * can't fit this into a sockaddr_un directly. */ + + inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC); + if (inode_fd < 0) + return -errno; + + proc = FORMAT_PROC_FD_PATH(inode_fd); + proc_len = strlen(proc); + + assert(proc_len < sizeof(sa.un.sun_path)); + memcpy(sa.un.sun_path, proc, proc_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + proc_len + 1; + } + + return RET_NERRNO(connect(fd, &sa.sa, salen)); +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 5d9c0567443..fdadc9c6869 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -332,3 +332,5 @@ int socket_get_mtu(int fd, int af, size_t *ret); /* an initializer for struct ucred that initialized all fields to the invalid value appropriate for each */ #define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID } + +int connect_unix_path(int fd, int dir_fd, const char *path);