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.
This commit is contained in:
Lennart Poettering
2022-05-14 05:01:38 +09:00
committed by Yu Watanabe
parent bf7a24e50f
commit 2679aee440
2 changed files with 50 additions and 0 deletions
+48
View File
@@ -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));
}
+2
View File
@@ -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);