Commit Diff


commit - 90cee84d4c2eb546ed31ba65a01289429ea7f544
commit + f229e00955140395f8685f5812c064b7fa44090d
blob - 7bd827d6354db030b1fbffc9a365200e017a557e
blob + d3eb6036cea805e9b0c6fe5e8ba685cbda71c43b
--- compat/imsg-buffer.c
+++ compat/imsg-buffer.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg-buffer.c,v 1.12 2019/01/20 02:50:03 bcook Exp $	*/
+/*	$OpenBSD: imsg-buffer.c,v 1.16 2023/06/19 17:19:50 claudio Exp $	*/
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -33,15 +33,20 @@
 static int	ibuf_realloc(struct ibuf *, size_t);
 static void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
 static void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
+static void	msgbuf_drain(struct msgbuf *, size_t);
 
 struct ibuf *
 ibuf_open(size_t len)
 {
 	struct ibuf	*buf;
 
+	if (len == 0) {
+		errno = EINVAL;
+		return (NULL);
+	}
 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
 		return (NULL);
-	if ((buf->buf = malloc(len)) == NULL) {
+	if ((buf->buf = calloc(len, 1)) == NULL) {
 		free(buf);
 		return (NULL);
 	}
@@ -56,15 +61,23 @@ ibuf_dynamic(size_t len, size_t max)
 {
 	struct ibuf	*buf;
 
-	if (max < len)
+	if (max < len) {
+		errno = EINVAL;
 		return (NULL);
+	}
 
-	if ((buf = ibuf_open(len)) == NULL)
+	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
 		return (NULL);
+	if (len > 0) {
+		if ((buf->buf = calloc(len, 1)) == NULL) {
+			free(buf);
+			return (NULL);
+		}
+	}
+	buf->size = len;
+	buf->max = max;
+	buf->fd = -1;
 
-	if (max > 0)
-		buf->max = max;
-
 	return (buf);
 }
 
@@ -74,7 +87,7 @@ ibuf_realloc(struct ibuf *buf, size_t len)
 	unsigned char	*b;
 
 	/* on static buffers max is eq size and so the following fails */
-	if (buf->wpos + len > buf->max) {
+	if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
 		errno = ERANGE;
 		return (-1);
 	}
@@ -88,42 +101,176 @@ ibuf_realloc(struct ibuf *buf, size_t len)
 	return (0);
 }
 
-int
-ibuf_add(struct ibuf *buf, const void *data, size_t len)
-{
-	if (buf->wpos + len > buf->size)
-		if (ibuf_realloc(buf, len) == -1)
-			return (-1);
-
-	memcpy(buf->buf + buf->wpos, data, len);
-	buf->wpos += len;
-	return (0);
-}
-
 void *
 ibuf_reserve(struct ibuf *buf, size_t len)
 {
 	void	*b;
 
+	if (len > SIZE_MAX - buf->wpos) {
+		errno = ERANGE;
+		return (NULL);
+	}
+
 	if (buf->wpos + len > buf->size)
 		if (ibuf_realloc(buf, len) == -1)
 			return (NULL);
 
 	b = buf->buf + buf->wpos;
 	buf->wpos += len;
+	memset(b, 0, len);
 	return (b);
 }
 
+int
+ibuf_add(struct ibuf *buf, const void *data, size_t len)
+{
+	void *b;
+
+	if ((b = ibuf_reserve(buf, len)) == NULL)
+		return (-1);
+
+	memcpy(b, data, len);
+	return (0);
+}
+
+int
+ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
+{
+	return ibuf_add(buf, from->buf, from->wpos);
+}
+
+int
+ibuf_add_n8(struct ibuf *buf, uint64_t value)
+{
+	uint8_t v;
+
+	if (value > UINT8_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = value;
+	return ibuf_add(buf, &v, sizeof(v));
+}
+
+int
+ibuf_add_n16(struct ibuf *buf, uint64_t value)
+{
+	uint16_t v;
+
+	if (value > UINT16_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = htobe16(value);
+	return ibuf_add(buf, &v, sizeof(v));
+}
+
+int
+ibuf_add_n32(struct ibuf *buf, uint64_t value)
+{
+	uint32_t v;
+
+	if (value > UINT32_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = htobe32(value);
+	return ibuf_add(buf, &v, sizeof(v));
+}
+
+int
+ibuf_add_n64(struct ibuf *buf, uint64_t value)
+{
+	value = htobe64(value);
+	return ibuf_add(buf, &value, sizeof(value));
+}
+
+int
+ibuf_add_zero(struct ibuf *buf, size_t len)
+{
+	void *b;
+
+	if ((b = ibuf_reserve(buf, len)) == NULL)
+		return (-1);
+	return (0);
+}
+
 void *
 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
 {
 	/* only allowed to seek in already written parts */
-	if (pos + len > buf->wpos)
+	if (len > SIZE_MAX - pos || pos + len > buf->wpos) {
+		errno = ERANGE;
 		return (NULL);
+	}
 
 	return (buf->buf + pos);
 }
 
+int
+ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
+{
+	void *b;
+
+	if ((b = ibuf_seek(buf, pos, len)) == NULL)
+		return (-1);
+
+	memcpy(b, data, len);
+	return (0);
+}
+
+int
+ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
+{
+	uint8_t v;
+
+	if (value > UINT8_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = value;
+	return (ibuf_set(buf, pos, &v, sizeof(v)));
+}
+
+int
+ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
+{
+	uint16_t v;
+
+	if (value > UINT16_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = htobe16(value);
+	return (ibuf_set(buf, pos, &v, sizeof(v)));
+}
+
+int
+ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
+{
+	uint32_t v;
+
+	if (value > UINT32_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+	v = htobe32(value);
+	return (ibuf_set(buf, pos, &v, sizeof(v)));
+}
+
+int
+ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
+{
+	value = htobe64(value);
+	return (ibuf_set(buf, pos, &value, sizeof(value)));
+}
+
+void *
+ibuf_data(struct ibuf *buf)
+{
+	return (buf->buf);
+}
+
 size_t
 ibuf_size(struct ibuf *buf)
 {
@@ -142,7 +289,46 @@ ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
 	ibuf_enqueue(msgbuf, buf);
 }
 
+void
+ibuf_free(struct ibuf *buf)
+{
+	if (buf == NULL)
+		return;
+#ifdef NOTYET
+	if (buf->fd != -1)
+		close(buf->fd);
+#endif
+	freezero(buf->buf, buf->size);
+	free(buf);
+}
+
 int
+ibuf_fd_avail(struct ibuf *buf)
+{
+	return (buf->fd != -1);
+}
+
+int
+ibuf_fd_get(struct ibuf *buf)
+{
+	int fd;
+
+	fd = buf->fd;
+#ifdef NOTYET
+	buf->fd = -1;
+#endif
+	return (fd);
+}
+
+void
+ibuf_fd_set(struct ibuf *buf, int fd)
+{
+	if (buf->fd != -1)
+		close(buf->fd);
+	buf->fd = fd;
+}
+
+int
 ibuf_write(struct msgbuf *msgbuf)
 {
 	struct iovec	 iov[IOV_MAX];
@@ -179,15 +365,6 @@ again:
 }
 
 void
-ibuf_free(struct ibuf *buf)
-{
-	if (buf == NULL)
-		return;
-	freezero(buf->buf, buf->size);
-	free(buf);
-}
-
-void
 msgbuf_init(struct msgbuf *msgbuf)
 {
 	msgbuf->queued = 0;
@@ -195,7 +372,7 @@ msgbuf_init(struct msgbuf *msgbuf)
 	TAILQ_INIT(&msgbuf->bufs);
 }
 
-void
+static void
 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
 {
 	struct ibuf	*buf, *next;
@@ -203,7 +380,7 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n)
 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
 	    buf = next) {
 		next = TAILQ_NEXT(buf, entry);
-		if (buf->rpos + n >= buf->wpos) {
+		if (n >= buf->wpos - buf->rpos) {
 			n -= buf->wpos - buf->rpos;
 			ibuf_dequeue(msgbuf, buf);
 		} else {
@@ -226,7 +403,7 @@ int
 msgbuf_write(struct msgbuf *msgbuf)
 {
 	struct iovec	 iov[IOV_MAX];
-	struct ibuf	*buf;
+	struct ibuf	*buf, *buf0 = NULL;
 	unsigned int	 i = 0;
 	ssize_t		 n;
 	struct msghdr	 msg;
@@ -242,24 +419,26 @@ msgbuf_write(struct msgbuf *msgbuf)
 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
 		if (i >= IOV_MAX)
 			break;
+		if (i > 0 && buf->fd != -1)
+			break;
 		iov[i].iov_base = buf->buf + buf->rpos;
 		iov[i].iov_len = buf->wpos - buf->rpos;
 		i++;
 		if (buf->fd != -1)
-			break;
+			buf0 = buf;
 	}
 
 	msg.msg_iov = iov;
 	msg.msg_iovlen = i;
 
-	if (buf != NULL && buf->fd != -1) {
+	if (buf0 != NULL) {
 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
 		msg.msg_controllen = sizeof(cmsgbuf.buf);
 		cmsg = CMSG_FIRSTHDR(&msg);
 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 		cmsg->cmsg_level = SOL_SOCKET;
 		cmsg->cmsg_type = SCM_RIGHTS;
-		*(int *)CMSG_DATA(cmsg) = buf->fd;
+		*(int *)CMSG_DATA(cmsg) = buf0->fd;
 	}
 
 again:
@@ -280,9 +459,9 @@ again:
 	 * assumption: fd got sent if sendmsg sent anything
 	 * this works because fds are passed one at a time
 	 */
-	if (buf != NULL && buf->fd != -1) {
-		close(buf->fd);
-		buf->fd = -1;
+	if (buf0 != NULL) {
+		close(buf0->fd);
+		buf0->fd = -1;
 	}
 
 	msgbuf_drain(msgbuf, n);
@@ -302,8 +481,10 @@ ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
 {
 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
 
-	if (buf->fd != -1)
+	if (buf->fd != -1) {
 		close(buf->fd);
+		buf->fd = -1;
+	}
 
 	msgbuf->queued--;
 	ibuf_free(buf);
blob - 59998a5321d7c7e0dc8c44be2e5371e1213a7371
blob + 5d5201ab369fc1a4016a84f7a33fe9e898332f76
--- compat/imsg.c
+++ compat/imsg.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.c,v 1.17 2022/01/28 10:41:44 claudio Exp $	*/
+/*	$OpenBSD: imsg.c,v 1.19 2023/06/19 17:19:50 claudio Exp $	*/
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -176,8 +176,7 @@ imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint
 	if (imsg_add(wbuf, data, datalen) == -1)
 		return (-1);
 
-	wbuf->fd = fd;
-
+	ibuf_fd_set(wbuf, fd);
 	imsg_close(ibuf, wbuf);
 
 	return (1);
@@ -200,14 +199,49 @@ imsg_composev(struct imsgbuf *ibuf, uint32_t type, uin
 		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
 			return (-1);
 
-	wbuf->fd = fd;
-
+	ibuf_fd_set(wbuf, fd);
 	imsg_close(ibuf, wbuf);
 
 	return (1);
 }
 
-/* ARGSUSED */
+int
+imsg_compose_ibuf(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
+    pid_t pid, struct ibuf *buf)
+{
+	struct ibuf	*wbuf = NULL;
+	struct imsg_hdr	 hdr;
+	int save_errno;
+
+	if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) {
+		errno = ERANGE;
+		goto fail;
+	}
+
+	hdr.type = type;
+	hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
+	hdr.flags = 0;
+	hdr.peerid = peerid;
+	if ((hdr.pid = pid) == 0)
+		hdr.pid = ibuf->pid;
+
+	if ((wbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
+		goto fail;
+	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
+		goto fail;
+
+	ibuf_close(&ibuf->w, wbuf);
+	ibuf_close(&ibuf->w, buf);
+	return (1);
+
+ fail:
+	save_errno = errno;
+	ibuf_free(buf);
+	ibuf_free(wbuf);
+	errno = save_errno;
+	return (-1);
+}
+
 struct ibuf *
 imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
     uint16_t datalen)
@@ -254,11 +288,10 @@ imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
 	hdr = (struct imsg_hdr *)msg->buf;
 
 	hdr->flags &= ~IMSGF_HASFD;
-	if (msg->fd != -1)
+	if (ibuf_fd_avail(msg))
 		hdr->flags |= IMSGF_HASFD;
+	hdr->len = ibuf_size(msg);
 
-	hdr->len = (uint16_t)msg->wpos;
-
 	ibuf_close(&ibuf->w, msg);
 }
 
blob - 5b092cfcfd53b5b09a2d5932010f421d6795e0aa
blob + fb516e30287318ec10ccdddc451e5d8658db0a12
--- compat/imsg.h
+++ compat/imsg.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.h,v 1.5 2019/01/20 02:50:03 bcook Exp $	*/
+/*	$OpenBSD: imsg.h,v 1.7 2023/06/19 17:19:50 claudio Exp $	*/
 
 /*
  * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -78,22 +78,37 @@ struct imsg {
 	void		*data;
 };
 
+struct iovec;
 
-/* buffer.c */
+/* imsg-buffer.c */
 struct ibuf	*ibuf_open(size_t);
 struct ibuf	*ibuf_dynamic(size_t, size_t);
 int		 ibuf_add(struct ibuf *, const void *, size_t);
+int		 ibuf_add_buf(struct ibuf *, const struct ibuf *);
+int		 ibuf_add_zero(struct ibuf *, size_t);
+int		 ibuf_add_n8(struct ibuf *, uint64_t);
+int		 ibuf_add_n16(struct ibuf *, uint64_t);
+int		 ibuf_add_n32(struct ibuf *, uint64_t);
+int		 ibuf_add_n64(struct ibuf *, uint64_t);
 void		*ibuf_reserve(struct ibuf *, size_t);
 void		*ibuf_seek(struct ibuf *, size_t, size_t);
+int		 ibuf_set(struct ibuf *, size_t, const void *, size_t);
+int		 ibuf_set_n8(struct ibuf *, size_t, uint64_t);
+int		 ibuf_set_n16(struct ibuf *, size_t, uint64_t);
+int		 ibuf_set_n32(struct ibuf *, size_t, uint64_t);
+int		 ibuf_set_n64(struct ibuf *, size_t, uint64_t);
+void		*ibuf_data(struct ibuf *);
 size_t		 ibuf_size(struct ibuf *);
 size_t		 ibuf_left(struct ibuf *);
 void		 ibuf_close(struct msgbuf *, struct ibuf *);
-int		 ibuf_write(struct msgbuf *);
 void		 ibuf_free(struct ibuf *);
+int		 ibuf_fd_avail(struct ibuf *);
+int		 ibuf_fd_get(struct ibuf *);
+void		 ibuf_fd_set(struct ibuf *, int);
+int		 ibuf_write(struct msgbuf *);
 void		 msgbuf_init(struct msgbuf *);
 void		 msgbuf_clear(struct msgbuf *);
 int		 msgbuf_write(struct msgbuf *);
-void		 msgbuf_drain(struct msgbuf *, size_t);
 
 /* imsg.c */
 void	 imsg_init(struct imsgbuf *, int);
@@ -103,6 +118,8 @@ int	 imsg_compose(struct imsgbuf *, uint32_t, uint32_t
 	    const void *, uint16_t);
 int	 imsg_composev(struct imsgbuf *, uint32_t, uint32_t,  pid_t, int,
 	    const struct iovec *, int);
+int	 imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t,
+	    struct ibuf *);
 struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, uint16_t);
 int	 imsg_add(struct ibuf *, const void *, uint16_t);
 void	 imsg_close(struct imsgbuf *, struct ibuf *);