Commit Diff


commit - eaecb958183f6eb4fdb79b3258d465a4fd8cb72e
commit + 278c2ee8f22638aca522d05826589261d36409b8
blob - eac3e6ce0d139fe8d66e270264e48b4d3230572f
blob + fc8ef7dbd7609263755a10aec3f4dfb6ab8d94fb
--- compat/imsg-buffer.c
+++ compat/imsg-buffer.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg-buffer.c,v 1.28 2024/11/21 13:03:21 claudio Exp $	*/
+/*	$OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -38,7 +38,7 @@ struct msgbuf {
 	uint32_t		 queued;
 	char			*rbuf;
 	struct ibuf		*rpmsg;
-	ssize_t			(*readhdr)(struct ibuf *, void *);
+	struct ibuf		*(*readhdr)(struct ibuf *, void *, int *);
 	void			*rarg;
 	size_t			 roff;
 	size_t			 hdrsize;
@@ -574,8 +574,8 @@ msgbuf_new(void)
 }
 
 struct msgbuf *
-msgbuf_new_reader(size_t hdrsz, ssize_t (*readhdr)(struct ibuf *, void *),
-    void *arg)
+msgbuf_new_reader(size_t hdrsz,
+    struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
 {
 	struct msgbuf *msgbuf;
 	char *buf;
@@ -605,8 +605,9 @@ msgbuf_new_reader(size_t hdrsz, ssize_t (*readhdr)(str
 void
 msgbuf_free(struct msgbuf *msgbuf)
 {
-	if (msgbuf != NULL)
-		msgbuf_clear(msgbuf);
+	if (msgbuf == NULL)
+		return;
+	msgbuf_clear(msgbuf);
 	free(msgbuf->rbuf);
 	free(msgbuf);
 }
@@ -757,33 +758,16 @@ ibuf_read_process(struct msgbuf *msgbuf, int fd)
 
 	ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
 
-	/* fds must be passed at start of message of at least hdrsize bytes */
-	if (msgbuf->rpmsg != NULL && fd != -1) {
-		close(fd);
-		fd = -1;
-	}
-
 	do {
 		if (msgbuf->rpmsg == NULL) {
-			if (ibuf_size(&rbuf) < msgbuf->hdrsize) {
-				if (fd != -1) {
-					close(fd);
-					fd = -1;
-				}
+			if (ibuf_size(&rbuf) < msgbuf->hdrsize)
 				break;
-			}
 			/* get size from header */
 			ibuf_from_buffer(&msg, ibuf_data(&rbuf),
 			    msgbuf->hdrsize);
-			sz = msgbuf->readhdr(&msg, msgbuf->rarg);
-			if (sz == -1)
+			if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
+			    msgbuf->rarg, &fd)) == NULL)
 				goto fail;
-			if ((msgbuf->rpmsg = ibuf_open(sz)) == NULL)
-				goto fail;
-			if (fd != -1) {
-				ibuf_fd_set(msgbuf->rpmsg, fd);
-				fd = -1;
-			}
 		}
 
 		if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
@@ -806,10 +790,14 @@ ibuf_read_process(struct msgbuf *msgbuf, int fd)
 		memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
 	msgbuf->roff = ibuf_size(&rbuf);
 
+	if (fd != -1)
+		close(fd);
 	return (1);
 
  fail:
-	/* XXX cleanup */
+	/* XXX how to properly clean up is unclear */
+	if (fd != -1)
+		close(fd);
 	return (-1);
 }
 
blob - ef796315dfbe8543a11eeff1b38a8d2b185ce7d3
blob + 89ac7fa4313e8d70079d81cc0f19f2ae2d8a02c3
--- compat/imsg.c
+++ compat/imsg.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.c,v 1.36 2024/11/21 13:03:21 claudio Exp $	*/
+/*	$OpenBSD: imsg.c,v 1.37 2024/11/26 13:57:31 claudio Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -23,6 +23,7 @@
 #include <sys/uio.h>
 
 #include <errno.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -31,8 +32,9 @@
 #include "imsg.h"
 
 #define IMSG_ALLOW_FDPASS	0x01
+#define IMSG_FD_MARK		0x80000000U
 
-static ssize_t	 imsg_parse_hdr(struct ibuf *, void *);
+static struct ibuf	*imsg_parse_hdr(struct ibuf *, void *, int *);
 
 int
 imsgbuf_init(struct imsgbuf *imsgbuf, int fd)
@@ -54,12 +56,15 @@ imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf)
 	imsgbuf->flags |= IMSG_ALLOW_FDPASS;
 }
 
-void
+int
 imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize)
 {
-	if (maxsize < IMSG_HEADER_SIZE)
-		return;
+	if (maxsize < IMSG_HEADER_SIZE || maxsize & IMSG_FD_MARK) {
+		errno = EINVAL;
+		return (-1);
+	}
 	imsgbuf->maxsize = maxsize;
+	return (0);
 }
 
 int
@@ -120,6 +125,7 @@ imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
 	else
 		m.data = NULL;
 	m.buf = buf;
+	m.hdr.len &= ~IMSG_FD_MARK;
 
 	*imsg = m;
 	return (ibuf_size(buf) + IMSG_HEADER_SIZE);
@@ -268,7 +274,7 @@ int
 imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
 {
 	struct ibuf	*wbuf;
-	size_t		 len = 0;
+	size_t		 len;
 
 	ibuf_rewind(msg->buf);
 	ibuf_skip(msg->buf, sizeof(msg->hdr));
@@ -278,7 +284,7 @@ imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg
 	    msg->hdr.pid, len)) == NULL)
 		return (-1);
 
-	if (msg->buf != NULL) {
+	if (len != 0) {
 		if (ibuf_add_ibuf(wbuf, msg->buf) == -1) {
 			ibuf_free(wbuf);
 			return (-1);
@@ -330,9 +336,12 @@ void
 imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
 {
 	struct imsg_hdr	*hdr;
+	uint32_t len;
 
-	hdr = (struct imsg_hdr *)msg->buf;
-	hdr->len = ibuf_size(msg);
+	len = ibuf_size(msg);
+	if (ibuf_fd_avail(msg))
+		len |= IMSG_FD_MARK;
+	(void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len);
 	ibuf_close(imsgbuf->w, msg);
 }
 
@@ -342,18 +351,29 @@ imsg_free(struct imsg *imsg)
 	ibuf_free(imsg->buf);
 }
 
-static ssize_t
-imsg_parse_hdr(struct ibuf *buf, void *arg)
+static struct ibuf *
+imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd)
 {
 	struct imsgbuf *imsgbuf = arg;
 	struct imsg_hdr hdr;
+	struct ibuf *b;
+	uint32_t len;
 
 	if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1)
-		return -1;
-	if (hdr.len < IMSG_HEADER_SIZE ||
-	    hdr.len > imsgbuf->maxsize) {
+		return (NULL);
+
+	len = hdr.len & ~IMSG_FD_MARK;
+
+	if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) {
 		errno = ERANGE;
-		return (-1);
+		return (NULL);
 	}
-	return hdr.len;
+	if ((b = ibuf_open(len)) == NULL)
+		return (NULL);
+	if (hdr.len & IMSG_FD_MARK) {
+		ibuf_fd_set(b, *fd);
+		*fd = -1;
+	}
+
+	return b;
 }
blob - 8d78beb34ebecd8de026b31a3ac9e60c0f31edec
blob + 462bfc97ffccdfc7bc6deae66c8b185c4ae1621d
--- compat/imsg.h
+++ compat/imsg.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.h,v 1.18 2024/11/21 13:03:21 claudio Exp $	*/
+/*	$OpenBSD: imsg.h,v 1.19 2024/11/26 13:57:31 claudio Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -110,8 +110,8 @@ int		 ibuf_fd_avail(struct ibuf *);
 int		 ibuf_fd_get(struct ibuf *);
 void		 ibuf_fd_set(struct ibuf *, int);
 struct msgbuf	*msgbuf_new(void);
-struct msgbuf	*msgbuf_new_reader(size_t, ssize_t (*)(struct ibuf *, void *),
-		    void *);
+struct msgbuf	*msgbuf_new_reader(size_t,
+		    struct ibuf *(*)(struct ibuf *, void *, int *), void *);
 void		 msgbuf_free(struct msgbuf *);
 void		 msgbuf_clear(struct msgbuf *);
 uint32_t	 msgbuf_queuelen(struct msgbuf *);
@@ -124,7 +124,7 @@ struct ibuf	*msgbuf_get(struct msgbuf *);
 /* imsg.c */
 int	 imsgbuf_init(struct imsgbuf *, int);
 void	 imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf);
-void	 imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
+int	 imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
 int	 imsgbuf_read(struct imsgbuf *);
 int	 imsgbuf_write(struct imsgbuf *);
 int	 imsgbuf_flush(struct imsgbuf *);