Merge branch 'fix-cmsg' into 'main'

connection: properly use sendmsg(2) and recvmsg(2)

See merge request wayland/wayland!445
This commit is contained in:
Demi Marie Obenour 2026-01-30 02:11:11 -05:00
commit 83b741e68e
2 changed files with 34 additions and 16 deletions

View file

@ -424,14 +424,23 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
continue; continue;
size = cmsg->cmsg_len - CMSG_LEN(0); 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) { if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) {
const unsigned char *data = CMSG_DATA(cmsg);
overflow = 1; overflow = 1;
size /= sizeof(int32_t); for (i = 0; i < size; i += sizeof(int)) {
for (i = 0; i < size; i++) /* man:cmsg(3) requires that memcpy()
close(((int*)CMSG_DATA(cmsg))[i]); * 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) { } else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
return -1; return -1;
} }
} }
@ -443,22 +452,26 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
return 0; return 0;
} }
int ssize_t
wl_connection_flush(struct wl_connection *connection) wl_connection_flush(struct wl_connection *connection)
{ {
struct iovec iov[2]; struct iovec iov[2];
struct msghdr msg = {0}; struct msghdr msg = {0};
char cmsg[CLEN]; ssize_t len = 0;
int len = 0, count; union {
char cmsg[CLEN];
struct cmsghdr align;
} u;
size_t clen; size_t clen;
size_t tail; size_t tail;
int count;
if (!connection->want_flush) if (!connection->want_flush)
return 0; return 0;
tail = connection->out.tail; tail = connection->out.tail;
while (ring_buffer_size(&connection->out) > 0) { 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) { if (clen >= CLEN) {
/* UNIX domain sockets allows to send file descriptors /* UNIX domain sockets allows to send file descriptors
@ -487,7 +500,7 @@ wl_connection_flush(struct wl_connection *connection)
msg.msg_namelen = 0; msg.msg_namelen = 0;
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = count; msg.msg_iovlen = count;
msg.msg_control = (clen > 0) ? cmsg : NULL; msg.msg_control = (clen > 0) ? u.cmsg : NULL;
msg.msg_controllen = clen; msg.msg_controllen = clen;
do { do {
@ -514,13 +527,17 @@ wl_connection_pending_input(struct wl_connection *connection)
return ring_buffer_size(&connection->in); return ring_buffer_size(&connection->in);
} }
int ssize_t
wl_connection_read(struct wl_connection *connection) wl_connection_read(struct wl_connection *connection)
{ {
struct iovec iov[2]; struct iovec iov[2];
struct msghdr msg; struct msghdr msg;
char cmsg[CLEN]; union {
int len, count, ret; char cmsg[CLEN];
struct cmsghdr align;
} u;
int count, ret;
ssize_t len;
while (1) { while (1) {
int data_size = ring_buffer_size(&connection->in); int data_size = ring_buffer_size(&connection->in);
@ -538,8 +555,8 @@ wl_connection_read(struct wl_connection *connection)
msg.msg_namelen = 0; msg.msg_namelen = 0;
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = count; msg.msg_iovlen = count;
msg.msg_control = cmsg; msg.msg_control = u.cmsg;
msg.msg_controllen = sizeof cmsg; msg.msg_controllen = sizeof u.cmsg;
msg.msg_flags = 0; msg.msg_flags = 0;
do { do {

View file

@ -32,6 +32,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h>
#define WL_HIDE_DEPRECATED 1 #define WL_HIDE_DEPRECATED 1
@ -144,13 +145,13 @@ wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
void void
wl_connection_consume(struct wl_connection *connection, size_t size); wl_connection_consume(struct wl_connection *connection, size_t size);
int ssize_t
wl_connection_flush(struct wl_connection *connection); wl_connection_flush(struct wl_connection *connection);
uint32_t uint32_t
wl_connection_pending_input(struct wl_connection *connection); wl_connection_pending_input(struct wl_connection *connection);
int ssize_t
wl_connection_read(struct wl_connection *connection); wl_connection_read(struct wl_connection *connection);
int int