socket-util: make connect_unix_path() work with a NULL path
This commit is contained in:
+36
-28
@@ -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(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);
|
||||
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);
|
||||
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;
|
||||
/* 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);
|
||||
|
||||
/* 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. */
|
||||
/* 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;
|
||||
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));
|
||||
return connect_unix_inode(fd, inode_fd);
|
||||
}
|
||||
|
||||
int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
|
||||
|
||||
Reference in New Issue
Block a user