From b9d8c43d304ac0e9d19e268b2b090a21e0ab0d90 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Sat, 27 Jul 2024 18:15:33 -0400 Subject: [PATCH] connection: properly use sendmsg(2) and recvmsg(2) - Properly align cmsg as per man:cmsg(3). - Use ssize_t to hold the return value of sendmsg(2) and recvmsg(2). - Avoid casting the return value of CMSG_DATA as per man:cmsg(3). Signed-off-by: Demi Marie Obenour --- src/connection.c | 45 +++++++++++++++++++++++++++++-------------- src/wayland-private.h | 5 +++-- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/connection.c b/src/connection.c index 34495211..2bd535d1 100644 --- a/src/connection.c +++ b/src/connection.c @@ -422,14 +422,23 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) continue; size = cmsg->cmsg_len - CMSG_LEN(0); + if (size % sizeof(int) != 0) { + /* This indicates a kernel bug. */ + wl_abort("SOL_SOCKET SCM_RIGHTS cmsg has invalid size %zu\n", size); + } if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) { + const unsigned char *data = CMSG_DATA(cmsg); overflow = 1; - size /= sizeof(int32_t); - for (i = 0; i < size; i++) - close(((int*)CMSG_DATA(cmsg))[i]); + for (i = 0; i < size; i += sizeof(int)) { + /* man:cmsg(3) requires that memcpy() + * be used instead of a pointer cast. */ + int fd; + memcpy(&fd, data + i, sizeof(fd)); + close(fd); + } } else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) { - return -1; + return -1; } } @@ -441,22 +450,26 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) return 0; } -int +ssize_t wl_connection_flush(struct wl_connection *connection) { struct iovec iov[2]; struct msghdr msg = {0}; - char cmsg[CLEN]; - int len = 0, count; + ssize_t len = 0; + union { + char cmsg[CLEN]; + struct cmsghdr align; + } u; size_t clen; size_t tail; + int count; if (!connection->want_flush) return 0; tail = connection->out.tail; while (ring_buffer_size(&connection->out) > 0) { - build_cmsg(&connection->fds_out, cmsg, &clen); + build_cmsg(&connection->fds_out, u.cmsg, &clen); if (clen >= CLEN) { /* UNIX domain sockets allows to send file descriptors @@ -485,7 +498,7 @@ wl_connection_flush(struct wl_connection *connection) msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; - msg.msg_control = (clen > 0) ? cmsg : NULL; + msg.msg_control = (clen > 0) ? u.cmsg : NULL; msg.msg_controllen = clen; do { @@ -512,13 +525,17 @@ wl_connection_pending_input(struct wl_connection *connection) return ring_buffer_size(&connection->in); } -int +ssize_t wl_connection_read(struct wl_connection *connection) { struct iovec iov[2]; struct msghdr msg; - char cmsg[CLEN]; - int len, count, ret; + union { + char cmsg[CLEN]; + struct cmsghdr align; + } u; + int count, ret; + ssize_t len; while (1) { int data_size = ring_buffer_size(&connection->in); @@ -536,8 +553,8 @@ wl_connection_read(struct wl_connection *connection) msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; - msg.msg_control = cmsg; - msg.msg_controllen = sizeof cmsg; + msg.msg_control = u.cmsg; + msg.msg_controllen = sizeof u.cmsg; msg.msg_flags = 0; do { diff --git a/src/wayland-private.h b/src/wayland-private.h index fe9120af..3ceb0811 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -32,6 +32,7 @@ #include #include #include +#include #define WL_HIDE_DEPRECATED 1 @@ -133,13 +134,13 @@ wl_connection_copy(struct wl_connection *connection, void *data, size_t size); void wl_connection_consume(struct wl_connection *connection, size_t size); -int +ssize_t wl_connection_flush(struct wl_connection *connection); uint32_t wl_connection_pending_input(struct wl_connection *connection); -int +ssize_t wl_connection_read(struct wl_connection *connection); int