From: Lennart Poettering Date: Fri, 10 Feb 2023 15:43:58 +0000 (+0100) Subject: socket-util: make connect_unix_path() work with a NULL path X-Git-Tag: v254-rc1~1252 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9a603dc2518493f2e39ead4599b30a80f75f8c57;p=thirdparty%2Fsystemd.git socket-util: make connect_unix_path() work with a NULL path --- diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index d7946a3641a..f01873e6080 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1425,52 +1425,60 @@ int socket_get_mtu(int fd, int af, size_t *ret) { return 0; } -int connect_unix_path(int fd, int dir_fd, const char *path) { - _cleanup_close_ int inode_fd = -EBADF; +static int connect_unix_path_simple(int fd, const char *path) { union sockaddr_union sa = { .un.sun_family = AF_UNIX, }; - size_t path_len; - socklen_t salen; + size_t l; assert(fd >= 0); - assert(dir_fd == AT_FDCWD || dir_fd >= 0); assert(path); + l = strlen(path); + assert(l > 0); + assert(l < sizeof(sa.un.sun_path)); + + memcpy(sa.un.sun_path, path, l + 1); + return RET_NERRNO(connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + l + 1)); +} + +static int connect_unix_inode(int fd, int inode_fd) { + assert(fd >= 0); + assert(inode_fd >= 0); + + return connect_unix_path_simple(fd, FORMAT_PROC_FD_PATH(inode_fd)); +} + +int connect_unix_path(int fd, int dir_fd, const char *path) { + _cleanup_close_ int inode_fd = -EBADF; + + assert(fd >= 0); + assert(dir_fd == AT_FDCWD || dir_fd >= 0); + /* 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); + if (!path) + return connect_unix_inode(fd, dir_fd); /* If no path is specified, then dir_fd refers to the socket inode to connect to. */ /* 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) + if (isempty(path)) 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; + /* Shortcut for the simple case */ + if (dir_fd == AT_FDCWD && strlen(path) < sizeof_field(struct sockaddr_un, sun_path)) + return connect_unix_path_simple(fd, path); - proc = FORMAT_PROC_FD_PATH(inode_fd); - proc_len = strlen(proc); + /* 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. */ - 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; - } + inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC); + if (inode_fd < 0) + return -errno; - return RET_NERRNO(connect(fd, &sa.sa, salen)); + return connect_unix_inode(fd, inode_fd); } int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {