summaryrefslogtreecommitdiff
path: root/src/libnm-systemd-shared/src/basic/socket-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-systemd-shared/src/basic/socket-util.c')
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c130
1 files changed, 80 insertions, 50 deletions
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index e7ea030008..9b411e07a2 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -228,7 +228,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
return false;
if (a->sockaddr.un.sun_path[0]) {
- if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
+ if (!path_equal_or_inode_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
return false;
} else {
if (a->size != b->size)
@@ -1054,7 +1054,7 @@ ssize_t receive_one_fd_iov(
}
if (found)
- *ret_fd = *(int*) CMSG_DATA(found);
+ *ret_fd = *CMSG_TYPED_DATA(found, int);
else
*ret_fd = -EBADF;
@@ -1181,6 +1181,24 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
return NULL;
}
+void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, size_t buf_len) {
+ struct cmsghdr *cmsg;
+
+ assert(mh);
+ assert(buf);
+ assert(buf_len > 0);
+
+ /* This is similar to cmsg_find_data(), but copy the found data to buf. This should be typically used
+ * when reading possibly unaligned data such as timestamp, as time_t is 64bit and size_t is 32bit on
+ * RISCV32. See issue #27241. */
+
+ cmsg = cmsg_find(mh, level, type, CMSG_LEN(buf_len));
+ if (!cmsg)
+ return NULL;
+
+ return memcpy_safe(buf, CMSG_DATA(cmsg), buf_len);
+}
+
#if 0 /* NM_IGNORED */
int socket_ioctl_fd(void) {
int fd;
@@ -1320,7 +1338,7 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) {
}
#if 0 /* NM_IGNORED */
-int socket_get_family(int fd, int *ret) {
+int socket_get_family(int fd) {
int af;
socklen_t sl = sizeof(af);
@@ -1334,12 +1352,11 @@ int socket_get_family(int fd, int *ret) {
}
int socket_set_recvpktinfo(int fd, int af, bool b) {
- int r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
@@ -1363,12 +1380,11 @@ int socket_set_recvpktinfo(int fd, int af, bool b) {
int socket_set_unicast_if(int fd, int af, int ifi) {
be32_t ifindex_be = htobe32(ifi);
- int r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
@@ -1385,12 +1401,10 @@ int socket_set_unicast_if(int fd, int af, int ifi) {
}
int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) {
- int r;
-
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
@@ -1410,9 +1424,9 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
int mtu, r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
@@ -1439,52 +1453,60 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
}
#endif /* NM_IGNORED */
-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. */
+ /* 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);
- inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC);
- if (inode_fd < 0)
- return -errno;
+ /* 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. */
- 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;
- }
+ 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) {
@@ -1515,13 +1537,20 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
_cleanup_free_ char *n = NULL;
char *e, *cid_start;
unsigned port, cid;
- int r;
+ int type, r;
assert(ret_address);
assert(s);
- cid_start = startswith(s, "vsock:");
- if (!cid_start)
+ if ((cid_start = startswith(s, "vsock:")))
+ type = 0;
+ else if ((cid_start = startswith(s, "vsock-dgram:")))
+ type = SOCK_DGRAM;
+ else if ((cid_start = startswith(s, "vsock-seqpacket:")))
+ type = SOCK_SEQPACKET;
+ else if ((cid_start = startswith(s, "vsock-stream:")))
+ type = SOCK_STREAM;
+ else
return -EPROTO;
e = strchr(cid_start, ':');
@@ -1550,6 +1579,7 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
.svm_family = AF_VSOCK,
.svm_port = port,
},
+ .type = type,
.size = sizeof(struct sockaddr_vm),
};