From c0af0c9c0243285e8930009e36b5205cd70a4b6c Mon Sep 17 00:00:00 2001 From: mbuhl Date: Wed, 13 Nov 2024 11:38:48 +0100 Subject: [PATCH 1/3] Update compat files. --- compat/ibuf-compat.c | 3 +- compat/imsg-buffer.c | 270 ++++++++++++++++++++++++++++++++++++++----- compat/imsg.c | 268 +++++++++++++++++++++++++++++------------- compat/imsg.h | 53 +++++++-- 4 files changed, 471 insertions(+), 123 deletions(-) diff --git a/compat/ibuf-compat.c b/compat/ibuf-compat.c index 72bf329d..2b70f994 100644 --- a/compat/ibuf-compat.c +++ b/compat/ibuf-compat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg-buffer.c,v 1.16 2023/06/19 17:19:50 claudio Exp $ */ +/* $OpenBSD: imsg-buffer.c,v 1.19 2024/08/26 13:57:34 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -59,6 +59,7 @@ ibuf_add_zero(struct ibuf *buf, size_t len) if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); + memset(b, 0, len); return (0); } #endif /* !defined(HAVE_IBUF_ADD_ZERO) */ diff --git a/compat/imsg-buffer.c b/compat/imsg-buffer.c index 68f7ecbc..715d02a0 100644 --- a/compat/imsg-buffer.c +++ b/compat/imsg-buffer.c @@ -1,6 +1,7 @@ -/* $OpenBSD: imsg-buffer.c,v 1.16 2023/06/19 17:19:50 claudio Exp $ */ +/* $OpenBSD: imsg-buffer.c,v 1.19 2024/08/26 13:57:34 claudio Exp $ */ /* + * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +64,7 @@ ibuf_dynamic(size_t len, size_t max) { struct ibuf *buf; - if (max < len) { + if (max == 0 || max < len) { errno = EINVAL; return (NULL); } @@ -93,9 +95,10 @@ ibuf_realloc(struct ibuf *buf, size_t len) return (-1); } - b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1); + b = realloc(buf->buf, buf->wpos + len); if (b == NULL) return (-1); + memset(b + buf->size, 0, buf->wpos + len - buf->size); buf->buf = b; buf->size = buf->wpos + len; @@ -107,7 +110,7 @@ ibuf_reserve(struct ibuf *buf, size_t len) { void *b; - if (len > SIZE_MAX - buf->wpos) { + if (len > SIZE_MAX - buf->wpos || buf->max == 0) { errno = ERANGE; return (NULL); } @@ -118,7 +121,6 @@ ibuf_reserve(struct ibuf *buf, size_t len) b = buf->buf + buf->wpos; buf->wpos += len; - memset(b, 0, len); return (b); } @@ -134,11 +136,17 @@ ibuf_add(struct ibuf *buf, const void *data, size_t len) return (0); } +int +ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from) +{ + return ibuf_add(buf, ibuf_data(from), ibuf_size(from)); +} +/* remove after tree is converted */ int ibuf_add_buf(struct ibuf *buf, const struct ibuf *from) { - return ibuf_add(buf, from->buf, from->wpos); + return ibuf_add_ibuf(buf, from); } int @@ -187,6 +195,38 @@ ibuf_add_n64(struct ibuf *buf, uint64_t value) return ibuf_add(buf, &value, sizeof(value)); } +int +ibuf_add_h16(struct ibuf *buf, uint64_t value) +{ + uint16_t v; + + if (value > UINT16_MAX) { + errno = EINVAL; + return (-1); + } + v = value; + return ibuf_add(buf, &v, sizeof(v)); +} + +int +ibuf_add_h32(struct ibuf *buf, uint64_t value) +{ + uint32_t v; + + if (value > UINT32_MAX) { + errno = EINVAL; + return (-1); + } + v = value; + return ibuf_add(buf, &v, sizeof(v)); +} + +int +ibuf_add_h64(struct ibuf *buf, uint64_t value) +{ + return ibuf_add(buf, &value, sizeof(value)); +} + int ibuf_add_zero(struct ibuf *buf, size_t len) { @@ -194,19 +234,21 @@ ibuf_add_zero(struct ibuf *buf, size_t len) if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); + memset(b, 0, len); return (0); } void * ibuf_seek(struct ibuf *buf, size_t pos, size_t len) { - /* only allowed to seek in already written parts */ - if (len > SIZE_MAX - pos || pos + len > buf->wpos) { + /* only allow seeking between rpos and wpos */ + if (ibuf_size(buf) < pos || SIZE_MAX - pos < len || + ibuf_size(buf) < pos + len) { errno = ERANGE; return (NULL); } - return (buf->buf + pos); + return (buf->buf + buf->rpos + pos); } int @@ -267,39 +309,201 @@ ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value) return (ibuf_set(buf, pos, &value, sizeof(value))); } +int +ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value) +{ + uint16_t v; + + if (value > UINT16_MAX) { + errno = EINVAL; + return (-1); + } + v = value; + return (ibuf_set(buf, pos, &v, sizeof(v))); +} + +int +ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value) +{ + uint32_t v; + + if (value > UINT32_MAX) { + errno = EINVAL; + return (-1); + } + v = value; + return (ibuf_set(buf, pos, &v, sizeof(v))); +} + +int +ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value) +{ + return (ibuf_set(buf, pos, &value, sizeof(value))); +} + void * -ibuf_data(struct ibuf *buf) +ibuf_data(const struct ibuf *buf) { - return (buf->buf); + return (buf->buf + buf->rpos); } size_t -ibuf_size(struct ibuf *buf) +ibuf_size(const struct ibuf *buf) { - return (buf->wpos); + return (buf->wpos - buf->rpos); } size_t -ibuf_left(struct ibuf *buf) +ibuf_left(const struct ibuf *buf) { + if (buf->max == 0) + return (0); return (buf->max - buf->wpos); } +int +ibuf_truncate(struct ibuf *buf, size_t len) +{ + if (ibuf_size(buf) >= len) { + buf->wpos = buf->rpos + len; + return (0); + } + if (buf->max == 0) { + /* only allow to truncate down */ + errno = ERANGE; + return (-1); + } + return ibuf_add_zero(buf, len - ibuf_size(buf)); +} + +void +ibuf_rewind(struct ibuf *buf) +{ + buf->rpos = 0; +} + void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { ibuf_enqueue(msgbuf, buf); } +void +ibuf_from_buffer(struct ibuf *buf, void *data, size_t len) +{ + memset(buf, 0, sizeof(*buf)); + buf->buf = data; + buf->size = buf->wpos = len; + buf->fd = -1; +} + +void +ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from) +{ + ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from)); +} + +int +ibuf_get(struct ibuf *buf, void *data, size_t len) +{ + if (ibuf_size(buf) < len) { + errno = EBADMSG; + return (-1); + } + + memcpy(data, ibuf_data(buf), len); + buf->rpos += len; + return (0); +} + +int +ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new) +{ + if (ibuf_size(buf) < len) { + errno = EBADMSG; + return (-1); + } + + ibuf_from_buffer(new, ibuf_data(buf), len); + buf->rpos += len; + return (0); +} + +int +ibuf_get_n8(struct ibuf *buf, uint8_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_get_n16(struct ibuf *buf, uint16_t *value) +{ + int rv; + + rv = ibuf_get(buf, value, sizeof(*value)); + *value = be16toh(*value); + return (rv); +} + +int +ibuf_get_n32(struct ibuf *buf, uint32_t *value) +{ + int rv; + + rv = ibuf_get(buf, value, sizeof(*value)); + *value = be32toh(*value); + return (rv); +} + +int +ibuf_get_n64(struct ibuf *buf, uint64_t *value) +{ + int rv; + + rv = ibuf_get(buf, value, sizeof(*value)); + *value = be64toh(*value); + return (rv); +} + +int +ibuf_get_h16(struct ibuf *buf, uint16_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_get_h32(struct ibuf *buf, uint32_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_get_h64(struct ibuf *buf, uint64_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_skip(struct ibuf *buf, size_t len) +{ + if (ibuf_size(buf) < len) { + errno = EBADMSG; + return (-1); + } + + buf->rpos += len; + return (0); +} + void ibuf_free(struct ibuf *buf) { if (buf == NULL) return; -#ifdef NOTYET + if (buf->max == 0) /* if buf lives on the stack */ + abort(); /* abort before causing more harm */ if (buf->fd != -1) close(buf->fd); -#endif freezero(buf->buf, buf->size); free(buf); } @@ -316,15 +520,15 @@ 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->max == 0) /* if buf lives on the stack */ + abort(); /* abort before causing more harm */ if (buf->fd != -1) close(buf->fd); buf->fd = fd; @@ -345,8 +549,8 @@ ibuf_write(struct msgbuf *msgbuf) TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IBUF_WSABUF_WRITE_MAX) break; - iov[i].buf = buf->buf + buf->rpos; - iov[i].len = buf->wpos - buf->rpos; + iov[i].buf = ibuf_data(buf); + iov[i].len = ibuf_size(buf); i++; } @@ -376,8 +580,8 @@ ibuf_write(struct msgbuf *msgbuf) TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IOV_MAX) break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; + iov[i].iov_base = ibuf_data(buf); + iov[i].iov_len = ibuf_size(buf); i++; } @@ -417,8 +621,8 @@ 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 (n >= buf->wpos - buf->rpos) { - n -= buf->wpos - buf->rpos; + if (n >= ibuf_size(buf)) { + n -= ibuf_size(buf); ibuf_dequeue(msgbuf, buf); } else { buf->rpos += n; @@ -470,8 +674,8 @@ msgbuf_write(struct msgbuf *msgbuf) break; if (i > 0 && buf->fd != -1) break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; + iov[i].iov_base = ibuf_data(buf); + iov[i].iov_len = ibuf_size(buf); i++; if (buf->fd != -1) buf0 = buf; @@ -519,9 +723,17 @@ msgbuf_write(struct msgbuf *msgbuf) } #endif /* !_WIN32 */ +uint32_t +msgbuf_queuelen(struct msgbuf *msgbuf) +{ + return (msgbuf->queued); +} + static void ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) { + if (buf->max == 0) /* if buf lives on the stack */ + abort(); /* abort before causing more harm */ TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); msgbuf->queued++; } @@ -530,12 +742,6 @@ static void ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_REMOVE(&msgbuf->bufs, buf, entry); - - if (buf->fd != -1) { - close(buf->fd); - buf->fd = -1; - } - msgbuf->queued--; ibuf_free(buf); } diff --git a/compat/imsg.c b/compat/imsg.c index d17c4958..90fff346 100644 --- a/compat/imsg.c +++ b/compat/imsg.c @@ -1,6 +1,7 @@ -/* $OpenBSD: imsg.c,v 1.19 2023/06/19 17:19:50 claudio Exp $ */ +/* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */ /* + * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any @@ -29,42 +30,47 @@ #include "openbsd-compat.h" #include "imsg.h" +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + int imsg_fd_overhead = 0; -static int imsg_get_fd(struct imsgbuf *); +static int imsg_dequeue_fd(struct imsgbuf *); void -imsg_init(struct imsgbuf *ibuf, int fd) +imsg_init(struct imsgbuf *imsgbuf, int fd) { - msgbuf_init(&ibuf->w); - memset(&ibuf->r, 0, sizeof(ibuf->r)); - ibuf->fd = fd; - ibuf->w.fd = fd; - ibuf->pid = getpid(); - TAILQ_INIT(&ibuf->fds); + msgbuf_init(&imsgbuf->w); + memset(&imsgbuf->r, 0, sizeof(imsgbuf->r)); + imsgbuf->fd = fd; + imsgbuf->w.fd = fd; + imsgbuf->pid = getpid(); + TAILQ_INIT(&imsgbuf->fds); } #ifdef _WIN32 ssize_t -imsg_read(struct imsgbuf *ibuf) +imsg_read(struct imsgbuf *imsgbuf) { ssize_t n; uint8_t *base; size_t len; - base = ibuf->r.buf + ibuf->r.wpos; - len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + base = imsgbuf->r.buf + imsgbuf->r.wpos; + len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos; - while ((n = recv(ibuf->fd, base, len, 0)) == -1) { + while ((n = recv(imsgbuf->fd, base, len, 0)) == -1) { if (errno != EINTR) return (-1); } - ibuf->r.wpos += n; + imsgbuf->r.wpos += n; return (n); } #else ssize_t -imsg_read(struct imsgbuf *ibuf) +imsg_read(struct imsgbuf *imsgbuf) { struct msghdr msg; struct cmsghdr *cmsg; @@ -80,8 +86,8 @@ imsg_read(struct imsgbuf *ibuf) memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - iov.iov_base = ibuf->r.buf + ibuf->r.wpos; - iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos; + iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; @@ -99,13 +105,13 @@ imsg_read(struct imsgbuf *ibuf) return (-1); } - if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; goto fail; } - ibuf->r.wpos += n; + imsgbuf->r.wpos += n; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { @@ -125,7 +131,7 @@ imsg_read(struct imsgbuf *ibuf) fd = ((int *)CMSG_DATA(cmsg))[i]; if (ifd != NULL) { ifd->fd = fd; - TAILQ_INSERT_TAIL(&ibuf->fds, ifd, + TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd, entry); ifd = NULL; } else @@ -142,55 +148,122 @@ imsg_read(struct imsgbuf *ibuf) #endif ssize_t -imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg) { + struct imsg m; size_t av, left, datalen; - av = ibuf->r.wpos; + av = imsgbuf->r.wpos; if (IMSG_HEADER_SIZE > av) return (0); - memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); - if (imsg->hdr.len < IMSG_HEADER_SIZE || - imsg->hdr.len > MAX_IMSGSIZE) { + memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr)); + if (m.hdr.len < IMSG_HEADER_SIZE || + m.hdr.len > MAX_IMSGSIZE) { errno = ERANGE; return (-1); } - if (imsg->hdr.len > av) + if (m.hdr.len > av) return (0); - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; - if (datalen == 0) - imsg->data = NULL; - else if ((imsg->data = malloc(datalen)) == NULL) - return (-1); - if (imsg->hdr.flags & IMSGF_HASFD) - imsg->fd = imsg_get_fd(ibuf); - else - imsg->fd = -1; + m.fd = -1; + m.buf = NULL; + m.data = NULL; + + datalen = m.hdr.len - IMSG_HEADER_SIZE; + imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE; + if (datalen != 0) { + if ((m.buf = ibuf_open(datalen)) == NULL) + return (-1); + if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) { + /* this should never fail */ + ibuf_free(m.buf); + return (-1); + } + m.data = ibuf_data(m.buf); + } - if (datalen != 0) - memcpy(imsg->data, ibuf->r.rptr, datalen); + if (m.hdr.flags & IMSGF_HASFD) + m.fd = imsg_dequeue_fd(imsgbuf); - if (imsg->hdr.len < av) { - left = av - imsg->hdr.len; - memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); - ibuf->r.wpos = left; + if (m.hdr.len < av) { + left = av - m.hdr.len; + memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left); + imsgbuf->r.wpos = left; } else - ibuf->r.wpos = 0; + imsgbuf->r.wpos = 0; + *imsg = m; return (datalen + IMSG_HEADER_SIZE); } int -imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, - int fd, const void *data, uint16_t datalen) +imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf) +{ + if (imsg->buf == NULL) { + errno = EBADMSG; + return (-1); + } + return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf); +} + +int +imsg_get_data(struct imsg *imsg, void *data, size_t len) +{ + if (len == 0) { + errno = EINVAL; + return (-1); + } + if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) { + errno = EBADMSG; + return (-1); + } + return ibuf_get(imsg->buf, data, len); +} + +int +imsg_get_fd(struct imsg *imsg) +{ + int fd = imsg->fd; + + imsg->fd = -1; + return fd; +} + +uint32_t +imsg_get_id(struct imsg *imsg) +{ + return (imsg->hdr.peerid); +} + +size_t +imsg_get_len(struct imsg *imsg) +{ + if (imsg->buf == NULL) + return 0; + return ibuf_size(imsg->buf); +} + +pid_t +imsg_get_pid(struct imsg *imsg) +{ + return (imsg->hdr.pid); +} + +uint32_t +imsg_get_type(struct imsg *imsg) +{ + return (imsg->hdr.type); +} + +int +imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, + int fd, const void *data, size_t datalen) { struct ibuf *wbuf; - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) return (-1); if (imsg_add(wbuf, data, datalen) == -1) @@ -198,22 +271,23 @@ imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, ibuf_fd_set(wbuf, fd); - imsg_close(ibuf, wbuf); + imsg_close(imsgbuf, wbuf); return (1); } int -imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, - int fd, const struct iovec *iov, int iovcnt) +imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) { struct ibuf *wbuf; - int i, datalen = 0; + int i; + size_t datalen = 0; for (i = 0; i < iovcnt; i++) datalen += iov[i].iov_len; - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) return (-1); for (i = 0; i < iovcnt; i++) @@ -222,16 +296,20 @@ imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, ibuf_fd_set(wbuf, fd); - imsg_close(ibuf, wbuf); + imsg_close(imsgbuf, wbuf); return (1); } +/* + * Enqueue imsg with payload from ibuf buf. fd passing is not possible + * with this function. + */ int -imsg_compose_ibuf(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, +imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, struct ibuf *buf) { - struct ibuf *wbuf = NULL; + struct ibuf *hdrbuf = NULL; struct imsg_hdr hdr; int save_errno; @@ -243,30 +321,64 @@ imsg_compose_ibuf(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, hdr.type = type; hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE; hdr.flags = 0; - hdr.peerid = peerid; + hdr.peerid = id; if ((hdr.pid = pid) == 0) - hdr.pid = ibuf->pid; + hdr.pid = imsgbuf->pid; - if ((wbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL) + if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL) goto fail; - if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1) goto fail; - ibuf_close(&ibuf->w, wbuf); - ibuf_close(&ibuf->w, buf); + ibuf_close(&imsgbuf->w, hdrbuf); + ibuf_close(&imsgbuf->w, buf); return (1); fail: save_errno = errno; ibuf_free(buf); - ibuf_free(wbuf); + ibuf_free(hdrbuf); errno = save_errno; return (-1); } +/* + * Forward imsg to another channel. Any attached fd is closed. + */ +int +imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg) +{ + struct ibuf *wbuf; + size_t len = 0; + + if (msg->fd != -1) { + close(msg->fd); + msg->fd = -1; + } + + if (msg->buf != NULL) { + ibuf_rewind(msg->buf); + len = ibuf_size(msg->buf); + } + + if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid, + msg->hdr.pid, len)) == NULL) + return (-1); + + if (msg->buf != NULL) { + if (ibuf_add_buf(wbuf, msg->buf) == -1) { + ibuf_free(wbuf); + return (-1); + } + } + + imsg_close(imsgbuf, wbuf); + return (1); +} + struct ibuf * -imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, - uint16_t datalen) +imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, + size_t datalen) { struct ibuf *wbuf; struct imsg_hdr hdr; @@ -279,9 +391,9 @@ imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, hdr.type = type; hdr.flags = 0; - hdr.peerid = peerid; + hdr.peerid = id; if ((hdr.pid = pid) == 0) - hdr.pid = ibuf->pid; + hdr.pid = imsgbuf->pid; if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { return (NULL); } @@ -292,7 +404,7 @@ imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, } int -imsg_add(struct ibuf *msg, const void *data, uint16_t datalen) +imsg_add(struct ibuf *msg, const void *data, size_t datalen) { if (datalen) if (ibuf_add(msg, data, datalen) == -1) { @@ -303,7 +415,7 @@ imsg_add(struct ibuf *msg, const void *data, uint16_t datalen) } void -imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) +imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg) { struct imsg_hdr *hdr; @@ -314,46 +426,46 @@ imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) hdr->flags |= IMSGF_HASFD; hdr->len = ibuf_size(msg); - ibuf_close(&ibuf->w, msg); + ibuf_close(&imsgbuf->w, msg); } void imsg_free(struct imsg *imsg) { - freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); + ibuf_free(imsg->buf); } static int -imsg_get_fd(struct imsgbuf *ibuf) +imsg_dequeue_fd(struct imsgbuf *imsgbuf) { int fd; struct imsg_fd *ifd; - if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL) return (-1); fd = ifd->fd; - TAILQ_REMOVE(&ibuf->fds, ifd, entry); + TAILQ_REMOVE(&imsgbuf->fds, ifd, entry); free(ifd); return (fd); } int -imsg_flush(struct imsgbuf *ibuf) +imsg_flush(struct imsgbuf *imsgbuf) { - while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) <= 0) + while (imsgbuf->w.queued) + if (msgbuf_write(&imsgbuf->w) <= 0) return (-1); return (0); } void -imsg_clear(struct imsgbuf *ibuf) +imsg_clear(struct imsgbuf *imsgbuf) { int fd; - msgbuf_clear(&ibuf->w); - while ((fd = imsg_get_fd(ibuf)) != -1) + msgbuf_clear(&imsgbuf->w); + while ((fd = imsg_dequeue_fd(imsgbuf)) != -1) close(fd); } diff --git a/compat/imsg.h b/compat/imsg.h index fb516e30..626ef7b8 100644 --- a/compat/imsg.h +++ b/compat/imsg.h @@ -1,6 +1,7 @@ -/* $OpenBSD: imsg.h,v 1.7 2023/06/19 17:19:50 claudio Exp $ */ +/* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */ /* + * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2006, 2007 Pierre-Yves Ritschard * Copyright (c) 2006, 2007, 2008 Reyk Floeter * Copyright (c) 2003, 2004 Henning Brauer @@ -22,6 +23,7 @@ #define _IMSG_H_ #include +#include #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) @@ -49,11 +51,7 @@ struct ibuf_read { size_t wpos; }; -struct imsg_fd { - TAILQ_ENTRY(imsg_fd) entry; - int fd; -}; - +struct imsg_fd; struct imsgbuf { TAILQ_HEAD(, imsg_fd) fds; struct ibuf_read r; @@ -76,6 +74,7 @@ struct imsg { struct imsg_hdr hdr; int fd; void *data; + struct ibuf *buf; }; struct iovec; @@ -85,11 +84,15 @@ 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_ibuf(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); +int ibuf_add_h16(struct ibuf *, uint64_t); +int ibuf_add_h32(struct ibuf *, uint64_t); +int ibuf_add_h64(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); @@ -97,10 +100,27 @@ 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 *); +int ibuf_set_h16(struct ibuf *, size_t, uint64_t); +int ibuf_set_h32(struct ibuf *, size_t, uint64_t); +int ibuf_set_h64(struct ibuf *, size_t, uint64_t); +void *ibuf_data(const struct ibuf *); +size_t ibuf_size(const struct ibuf *); +size_t ibuf_left(const struct ibuf *); +int ibuf_truncate(struct ibuf *, size_t); +void ibuf_rewind(struct ibuf *); void ibuf_close(struct msgbuf *, struct ibuf *); +void ibuf_from_buffer(struct ibuf *, void *, size_t); +void ibuf_from_ibuf(struct ibuf *, const struct ibuf *); +int ibuf_get(struct ibuf *, void *, size_t); +int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *); +int ibuf_get_n8(struct ibuf *, uint8_t *); +int ibuf_get_n16(struct ibuf *, uint16_t *); +int ibuf_get_n32(struct ibuf *, uint32_t *); +int ibuf_get_n64(struct ibuf *, uint64_t *); +int ibuf_get_h16(struct ibuf *, uint16_t *); +int ibuf_get_h32(struct ibuf *, uint32_t *); +int ibuf_get_h64(struct ibuf *, uint64_t *); +int ibuf_skip(struct ibuf *, size_t); void ibuf_free(struct ibuf *); int ibuf_fd_avail(struct ibuf *); int ibuf_fd_get(struct ibuf *); @@ -108,20 +128,29 @@ void ibuf_fd_set(struct ibuf *, int); int ibuf_write(struct msgbuf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); +uint32_t msgbuf_queuelen(struct msgbuf *); int msgbuf_write(struct msgbuf *); /* imsg.c */ void imsg_init(struct imsgbuf *, int); ssize_t imsg_read(struct imsgbuf *); ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_get_ibuf(struct imsg *, struct ibuf *); +int imsg_get_data(struct imsg *, void *, size_t); +int imsg_get_fd(struct imsg *); +uint32_t imsg_get_id(struct imsg *); +size_t imsg_get_len(struct imsg *); +pid_t imsg_get_pid(struct imsg *); +uint32_t imsg_get_type(struct imsg *); +int imsg_forward(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, - const void *, uint16_t); + const void *, size_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); +struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t); +int imsg_add(struct ibuf *, const void *, size_t); void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); From de29178079b3b73b2bf8df5b5edf478677973631 Mon Sep 17 00:00:00 2001 From: mbuhl Date: Wed, 13 Nov 2024 12:02:58 +0100 Subject: [PATCH 2/3] Fixup macos. --- compat/endian.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/endian.h b/compat/endian.h index 84d43be9..e39a33f3 100644 --- a/compat/endian.h +++ b/compat/endian.h @@ -20,6 +20,9 @@ #define htobe64(x) OSSwapHostToBigInt64(x) #define letoh64(x) OSSwapLittleToHostInt64(x) #define betoh64(x) OSSwapBigToHostInt64(x) +#define be16toh betoh16 +#define be32toh betoh32 +#define be64toh betoh64 #endif /* __APPLE__ && !HAVE_ENDIAN_H */ #if defined(_WIN32) && !defined(HAVE_ENDIAN_H) @@ -30,6 +33,9 @@ #define htobe32(x) ntohl((x)) #define betoh64(x) ntohll((x)) #define htobe64(x) ntohll((x)) +#define be16toh betoh16 +#define be32toh betoh32 +#define be64toh betoh64 #endif /* _WIN32 && !HAVE_ENDIAN_H */ #ifdef __linux__ From 692aaed441b89f062fd0e1c799e8eefbc0f0adef Mon Sep 17 00:00:00 2001 From: mbuhl Date: Thu, 21 Nov 2024 22:30:23 +0100 Subject: [PATCH 3/3] Copy imsg.h, imsg.c, and imsg-buffer.c from src, adjust CMake. --- CMakeLists.txt | 14 +- compat/CMakeLists.txt | 5 +- compat/ibuf-compat.c | 77 ------ compat/imsg-buffer.c | 562 +++++++++++++++++++++++++++++------------- compat/imsg.c | 298 +++++++--------------- compat/imsg.h | 56 ++--- 6 files changed, 514 insertions(+), 498 deletions(-) delete mode 100644 compat/ibuf-compat.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f90a3f0..c4e3b4b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -365,17 +365,9 @@ if(HAVE_GETOPT) add_definitions(-DHAVE_GETOPT) endif() -check_function_exists(ibuf_add_buf HAVE_IBUF_ADD_BUF) -if(HAVE_IBUF_ADD_BUF) - add_definitions(-DHAVE_IBUF_ADD_BUF) -endif() -check_function_exists(ibuf_add_zero HAVE_IBUF_ADD_ZERO) -if(HAVE_IBUF_ADD_ZERO) - add_definitions(-DHAVE_IBUF_ADD_ZERO) -endif() -check_function_exists(ibuf_data HAVE_IBUF_DATA) -if(HAVE_IBUF_DATA) - add_definitions(-DHAVE_IBUF_DATA) +check_function_exists(msgbuf_new_reader HAVE_MSGBUF_NEW_READER) +if(HAVE_MSGBUF_NEW_READER) + add_definitions(-DHAVE_MSGBUF_NEW_READER) endif() if(HAVE_VROUTE OR HAVE_VROUTE_NETLINK) diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index b714c139..01d4d5c7 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -42,7 +42,7 @@ endif() if(NOT HAVE_GETOPT) list(APPEND SRCS ${IKED_COMPAT}/getopt_long.c) endif() -if(NOT HAVE_IMSG_H) +if(NOT HAVE_IMSG_H OR NOT HAVE_MSGBUF_NEW_READER) list(APPEND SRCS # imsg ${IKED_COMPAT}/imsg.c @@ -73,9 +73,6 @@ endif() if(NOT HAVE_VIS) list(APPEND SRCS ${IKED_COMPAT}/vis.c) endif() -if(NOT HAVE_IBUF_ADD_BUF OR NOT HAVE_IBUF_ADD_ZERO OR NOT HAVE_IBUF_DATA) - list(APPEND SRCS ${IKED_COMPAT}/ibuf-compat.c) -endif() set(CFLAGS) list(APPEND CFLAGS diff --git a/compat/ibuf-compat.c b/compat/ibuf-compat.c deleted file mode 100644 index 2b70f994..00000000 --- a/compat/ibuf-compat.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $OpenBSD: imsg-buffer.c,v 1.19 2024/08/26 13:57:34 claudio Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* ibuf API functions added to OpenBSD's imsg-buffer.c in June 2023. */ - -#ifdef HAVE_IMSG_H - -#if !defined(HAVE_IBUF_ADD_BUF) || !defined(HAVE_IBUF_ADD_ZERO) -#include - -#include -#include -#endif /* !defined(HAVE_IBUF_ADD_BUF) || !defined(HAVE_IBUF_ADD_ZERO) */ - -#if !defined(HAVE_IBUF_ADD_BUF) -void *ibuf_reserve(struct ibuf *, size_t); - -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); -} -#endif /* !defined(HAVE_IBUF_ADD_BUF) */ - -#if !defined(HAVE_IBUF_ADD_ZERO) -void *ibuf_reserve(struct ibuf *, size_t); - -int -ibuf_add_zero(struct ibuf *buf, size_t len) -{ - void *b; - - if ((b = ibuf_reserve(buf, len)) == NULL) - return (-1); - memset(b, 0, len); - return (0); -} -#endif /* !defined(HAVE_IBUF_ADD_ZERO) */ - -#if !defined(HAVE_IBUF_DATA) -void *ibuf_seek(struct ibuf *, size_t, size_t); - -void * -ibuf_data(struct ibuf *buf) -{ - return (ibuf_seek(buf, 0, 0)); -} -#endif /* !defined(HAVE_IBUF_DATA) */ - -#endif /* HAVE_IMSG_H */ diff --git a/compat/imsg-buffer.c b/compat/imsg-buffer.c index 715d02a0..d0e697f8 100644 --- a/compat/imsg-buffer.c +++ b/compat/imsg-buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg-buffer.c,v 1.19 2024/08/26 13:57:34 claudio Exp $ */ +/* $OpenBSD: imsg-buffer.c,v 1.30 2024/11/22 07:20:50 tb Exp $ */ /* * Copyright (c) 2023 Claudio Jeker @@ -33,25 +33,37 @@ #include "openbsd-compat.h" #include "imsg.h" -static int ibuf_realloc(struct ibuf *, size_t); -static void ibuf_enqueue(struct msgbuf *, struct ibuf *); -static void ibuf_dequeue(struct msgbuf *, struct ibuf *); +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + TAILQ_HEAD(, ibuf) rbufs; + uint32_t queued; + char *rbuf; + struct ibuf *rpmsg; + ssize_t (*readhdr)(struct ibuf *, void *); + void *rarg; + size_t roff; + size_t hdrsize; +}; + +static void msgbuf_read_enqueue(struct msgbuf *, struct ibuf *); +static void msgbuf_enqueue(struct msgbuf *, struct ibuf *); +static void msgbuf_dequeue(struct msgbuf *, struct ibuf *); static void msgbuf_drain(struct msgbuf *, size_t); +#define IBUF_FD_MARK_ON_STACK -2 + 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 = calloc(len, 1)) == NULL) { - free(buf); - return (NULL); + if (len > 0) { + if ((buf->buf = calloc(len, 1)) == NULL) { + free(buf); + return (NULL); + } } buf->size = buf->max = len; buf->fd = -1; @@ -84,40 +96,36 @@ ibuf_dynamic(size_t len, size_t max) return (buf); } -static int -ibuf_realloc(struct ibuf *buf, size_t len) -{ - unsigned char *b; - - /* on static buffers max is eq size and so the following fails */ - if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) { - errno = ERANGE; - return (-1); - } - - b = realloc(buf->buf, buf->wpos + len); - if (b == NULL) - return (-1); - memset(b + buf->size, 0, buf->wpos + len - buf->size); - buf->buf = b; - buf->size = buf->wpos + len; - - return (0); -} - void * ibuf_reserve(struct ibuf *buf, size_t len) { void *b; - if (len > SIZE_MAX - buf->wpos || buf->max == 0) { + if (len > SIZE_MAX - buf->wpos) { errno = ERANGE; return (NULL); } + if (buf->fd == IBUF_FD_MARK_ON_STACK) { + /* can not grow stack buffers */ + errno = EINVAL; + return (NULL); + } - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) + if (buf->wpos + len > buf->size) { + unsigned char *nb; + + /* check if buffer is allowed to grow */ + if (buf->wpos + len > buf->max) { + errno = ERANGE; + return (NULL); + } + nb = realloc(buf->buf, buf->wpos + len); + if (nb == NULL) return (NULL); + memset(nb + buf->size, 0, buf->wpos + len - buf->size); + buf->buf = nb; + buf->size = buf->wpos + len; + } b = buf->buf + buf->wpos; buf->wpos += len; @@ -142,13 +150,6 @@ ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from) return ibuf_add(buf, ibuf_data(from), ibuf_size(from)); } -/* remove after tree is converted */ -int -ibuf_add_buf(struct ibuf *buf, const struct ibuf *from) -{ - return ibuf_add_ibuf(buf, from); -} - int ibuf_add_n8(struct ibuf *buf, uint64_t value) { @@ -356,7 +357,8 @@ ibuf_size(const struct ibuf *buf) size_t ibuf_left(const struct ibuf *buf) { - if (buf->max == 0) + /* on stack buffers have no space left */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) return (0); return (buf->max - buf->wpos); } @@ -368,8 +370,8 @@ ibuf_truncate(struct ibuf *buf, size_t len) buf->wpos = buf->rpos + len; return (0); } - if (buf->max == 0) { - /* only allow to truncate down */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) { + /* only allow to truncate down for stack buffers */ errno = ERANGE; return (-1); } @@ -385,7 +387,7 @@ ibuf_rewind(struct ibuf *buf) void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { - ibuf_enqueue(msgbuf, buf); + msgbuf_enqueue(msgbuf, buf); } void @@ -394,7 +396,7 @@ ibuf_from_buffer(struct ibuf *buf, void *data, size_t len) memset(buf, 0, sizeof(*buf)); buf->buf = data; buf->size = buf->wpos = len; - buf->fd = -1; + buf->fd = IBUF_FD_MARK_ON_STACK; } void @@ -429,6 +431,24 @@ ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new) return (0); } +int +ibuf_get_h16(struct ibuf *buf, uint16_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_get_h32(struct ibuf *buf, uint32_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + +int +ibuf_get_h64(struct ibuf *buf, uint64_t *value) +{ + return ibuf_get(buf, value, sizeof(*value)); +} + int ibuf_get_n8(struct ibuf *buf, uint8_t *value) { @@ -465,22 +485,21 @@ ibuf_get_n64(struct ibuf *buf, uint64_t *value) return (rv); } -int -ibuf_get_h16(struct ibuf *buf, uint16_t *value) +char * +ibuf_get_string(struct ibuf *buf, size_t len) { - return ibuf_get(buf, value, sizeof(*value)); -} + char *str; -int -ibuf_get_h32(struct ibuf *buf, uint32_t *value) -{ - return ibuf_get(buf, value, sizeof(*value)); -} + if (ibuf_size(buf) < len) { + errno = EBADMSG; + return (NULL); + } -int -ibuf_get_h64(struct ibuf *buf, uint64_t *value) -{ - return ibuf_get(buf, value, sizeof(*value)); + str = strndup(ibuf_data(buf), len); + if (str == NULL) + return (NULL); + buf->rpos += len; + return (str); } int @@ -500,9 +519,10 @@ ibuf_free(struct ibuf *buf) { if (buf == NULL) return; - if (buf->max == 0) /* if buf lives on the stack */ - abort(); /* abort before causing more harm */ - if (buf->fd != -1) + /* if buf lives on the stack abort before causing more harm */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) + abort(); + if (buf->fd >= 0) close(buf->fd); freezero(buf->buf, buf->size); free(buf); @@ -511,7 +531,7 @@ ibuf_free(struct ibuf *buf) int ibuf_fd_avail(struct ibuf *buf) { - return (buf->fd != -1); + return (buf->fd >= 0); } int @@ -519,6 +539,9 @@ ibuf_fd_get(struct ibuf *buf) { int fd; + /* negative fds are internal use and equivalent to -1 */ + if (buf->fd < 0) + return (-1); fd = buf->fd; buf->fd = -1; return (fd); @@ -527,108 +550,73 @@ ibuf_fd_get(struct ibuf *buf) void ibuf_fd_set(struct ibuf *buf, int fd) { - if (buf->max == 0) /* if buf lives on the stack */ - abort(); /* abort before causing more harm */ - if (buf->fd != -1) + /* if buf lives on the stack abort before causing more harm */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) + abort(); + if (buf->fd >= 0) close(buf->fd); - buf->fd = fd; + buf->fd = -1; + if (fd >= 0) + buf->fd = fd; } -#ifdef _WIN32 -#define IBUF_WSABUF_WRITE_MAX 16 -int -ibuf_write(struct msgbuf *msgbuf) +struct msgbuf * +msgbuf_new(void) { - DWORD bytesSent; - WSABUF iov[IBUF_WSABUF_WRITE_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; + struct msgbuf *msgbuf; - memset(&iov, 0, sizeof(iov)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IBUF_WSABUF_WRITE_MAX) - break; - iov[i].buf = ibuf_data(buf); - iov[i].len = ibuf_size(buf); - i++; - } - - if (WSASend(msgbuf->fd, iov, i, &bytesSent, 0, NULL, NULL)) - return (-1); - n = bytesSent; - - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - - msgbuf_drain(msgbuf, n); + if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL) + return (NULL); + msgbuf->queued = 0; + TAILQ_INIT(&msgbuf->bufs); + TAILQ_INIT(&msgbuf->rbufs); - return (1); + return msgbuf; } -#else -int -ibuf_write(struct msgbuf *msgbuf) + +struct msgbuf * +msgbuf_new_reader(size_t hdrsz, ssize_t (*readhdr)(struct ibuf *, void *), + void *arg) { - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; + struct msgbuf *msgbuf; + char *buf; - memset(&iov, 0, sizeof(iov)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = ibuf_data(buf); - iov[i].iov_len = ibuf_size(buf); - i++; + if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) { + errno = EINVAL; + return (NULL); } -again: - if ((n = writev(msgbuf->fd, iov, i)) == -1) { - if (errno == EINTR) - goto again; - if (errno == ENOBUFS) - errno = EAGAIN; - return (-1); - } + if ((buf = malloc(IBUF_READ_SIZE)) == NULL) + return (NULL); - if (n == 0) { /* connection closed */ - errno = 0; - return (0); + msgbuf = msgbuf_new(); + if (msgbuf == NULL) { + free(buf); + return (NULL); } - msgbuf_drain(msgbuf, n); + msgbuf->rbuf = buf; + msgbuf->hdrsize = hdrsz; + msgbuf->readhdr = readhdr; + msgbuf->rarg = arg; - return (1); + return (msgbuf); } -#endif /* !_WIN32 */ void -msgbuf_init(struct msgbuf *msgbuf) +msgbuf_free(struct msgbuf *msgbuf) { - msgbuf->queued = 0; - msgbuf->fd = -1; - TAILQ_INIT(&msgbuf->bufs); + if (msgbuf == NULL) + return; + msgbuf_clear(msgbuf); + free(msgbuf->rbuf); + free(msgbuf); } -static void -msgbuf_drain(struct msgbuf *msgbuf, size_t n) +uint32_t +msgbuf_queuelen(struct msgbuf *msgbuf) { - struct ibuf *buf, *next; - - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (n >= ibuf_size(buf)) { - n -= ibuf_size(buf); - ibuf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } + return (msgbuf->queued); } void @@ -636,24 +624,66 @@ msgbuf_clear(struct msgbuf *msgbuf) { struct ibuf *buf; + /* write side */ while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) - ibuf_dequeue(msgbuf, buf); + msgbuf_dequeue(msgbuf, buf); + msgbuf->queued = 0; + + /* read side */ + while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) { + TAILQ_REMOVE(&msgbuf->rbufs, buf, entry); + ibuf_free(buf); + } + msgbuf->roff = 0; + ibuf_free(msgbuf->rpmsg); + msgbuf->rpmsg = NULL; +} + +struct ibuf * +msgbuf_get(struct msgbuf *msgbuf) +{ + struct ibuf *buf; + + if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) + TAILQ_REMOVE(&msgbuf->rbufs, buf, entry); + return buf; } -#ifdef _WIN32 int -msgbuf_write(struct msgbuf *msgbuf) +ibuf_write(int fd, struct msgbuf *msgbuf) { + struct iovec iov[IOV_MAX]; struct ibuf *buf; + unsigned int i = 0; + ssize_t n; - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) - if (buf->fd != -1) - return (-1); - return ibuf_write(msgbuf); + memset(&iov, 0, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = ibuf_data(buf); + iov[i].iov_len = ibuf_size(buf); + i++; + } + if (i == 0) + return (0); /* nothing queued */ + + again: + if ((n = writev(fd, iov, i)) == -1) { + if (errno == EINTR) + goto again; + if (errno == EAGAIN || errno == ENOBUFS) + /* lets retry later again */ + return (0); + return (-1); + } + + msgbuf_drain(msgbuf, n); + return (0); } -#else + int -msgbuf_write(struct msgbuf *msgbuf) +msgbuf_write(int fd, struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf, *buf0 = NULL; @@ -681,6 +711,9 @@ msgbuf_write(struct msgbuf *msgbuf) buf0 = buf; } + if (i == 0) + return (0); /* nothing queued */ + msg.msg_iov = iov; msg.msg_iovlen = i; @@ -694,20 +727,16 @@ msgbuf_write(struct msgbuf *msgbuf) *(int *)CMSG_DATA(cmsg) = buf0->fd; } -again: - if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + again: + if ((n = sendmsg(fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; - if (errno == ENOBUFS) - errno = EAGAIN; + if (errno == EAGAIN || errno == ENOBUFS) + /* lets retry later again */ + return (0); return (-1); } - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - /* * assumption: fd got sent if sendmsg sent anything * this works because fds are passed one at a time @@ -719,29 +748,222 @@ msgbuf_write(struct msgbuf *msgbuf) msgbuf_drain(msgbuf, n); + return (0); +} + +static int +ibuf_read_process(struct msgbuf *msgbuf, int fd) +{ + struct ibuf rbuf, msg; + ssize_t sz; + + 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; + } + break; + } + /* get size from header */ + ibuf_from_buffer(&msg, ibuf_data(&rbuf), + msgbuf->hdrsize); + sz = msgbuf->readhdr(&msg, msgbuf->rarg); + if (sz == -1) + 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)) + sz = ibuf_left(msgbuf->rpmsg); + else + sz = ibuf_size(&rbuf); + + /* neither call below can fail */ + if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 || + ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1) + goto fail; + + if (ibuf_left(msgbuf->rpmsg) == 0) { + msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg); + msgbuf->rpmsg = NULL; + } + } while (ibuf_size(&rbuf) > 0); + + if (ibuf_size(&rbuf) > 0) + memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf)); + msgbuf->roff = ibuf_size(&rbuf); + return (1); + + fail: + /* XXX cleanup */ + return (-1); } -#endif /* !_WIN32 */ -uint32_t -msgbuf_queuelen(struct msgbuf *msgbuf) +int +ibuf_read(int fd, struct msgbuf *msgbuf) { - return (msgbuf->queued); + struct iovec iov; + ssize_t n; + + if (msgbuf->rbuf == NULL) { + errno = EINVAL; + return (-1); + } + + iov.iov_base = msgbuf->rbuf + msgbuf->roff; + iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; + + again: + if ((n = readv(fd, &iov, 1)) == -1) { + if (errno == EINTR) + goto again; + if (errno == EAGAIN) + /* lets retry later again */ + return (1); + return (-1); + } + if (n == 0) /* connection closed */ + return (0); + + msgbuf->roff += n; + /* new data arrived, try to process it */ + return (ibuf_read_process(msgbuf, -1)); +} + +int +msgbuf_read(int fd, struct msgbuf *msgbuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 1)]; + } cmsgbuf; + struct iovec iov; + ssize_t n; + int fdpass = -1; + + if (msgbuf->rbuf == NULL) { + errno = EINVAL; + return (-1); + } + + memset(&msg, 0, sizeof(msg)); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + + iov.iov_base = msgbuf->rbuf + msgbuf->roff; + iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + +again: + if ((n = recvmsg(fd, &msg, 0)) == -1) { + if (errno == EINTR) + goto again; + if (errno == EMSGSIZE) + /* + * Not enough fd slots: fd passing failed, retry + * to receive the message without fd. + * imsg_get_fd() will return -1 in that case. + */ + goto again; + if (errno == EAGAIN) + /* lets retry later again */ + return (1); + return (-1); + } + if (n == 0) /* connection closed */ + return (0); + + msgbuf->roff += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int i, j, f; + + /* + * We only accept one file descriptor. Due to C + * padding rules, our control buffer might contain + * more than one fd, and we must close them. + */ + j = ((char *)cmsg + cmsg->cmsg_len - + (char *)CMSG_DATA(cmsg)) / sizeof(int); + for (i = 0; i < j; i++) { + f = ((int *)CMSG_DATA(cmsg))[i]; + if (i == 0) + fdpass = f; + else + close(f); + } + } + /* we do not handle other ctl data level */ + } + + /* new data arrived, try to process it */ + return (ibuf_read_process(msgbuf, fdpass)); +} + +static void +msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + /* if buf lives on the stack abort before causing more harm */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) + abort(); + TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry); } static void -ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) { - if (buf->max == 0) /* if buf lives on the stack */ - abort(); /* abort before causing more harm */ + /* if buf lives on the stack abort before causing more harm */ + if (buf->fd == IBUF_FD_MARK_ON_STACK) + abort(); TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); msgbuf->queued++; } static void -ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) +msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_REMOVE(&msgbuf->bufs, buf, entry); msgbuf->queued--; ibuf_free(buf); } + +static void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct ibuf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (n >= ibuf_size(buf)) { + n -= ibuf_size(buf); + msgbuf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} diff --git a/compat/imsg.c b/compat/imsg.c index 90fff346..54caec05 100644 --- a/compat/imsg.c +++ b/compat/imsg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */ +/* $OpenBSD: imsg.c,v 1.36 2024/11/21 13:03:21 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker @@ -30,178 +30,105 @@ #include "openbsd-compat.h" #include "imsg.h" -struct imsg_fd { - TAILQ_ENTRY(imsg_fd) entry; - int fd; -}; +#define IMSG_ALLOW_FDPASS 0x01 -int imsg_fd_overhead = 0; +static ssize_t imsg_parse_hdr(struct ibuf *, void *); -static int imsg_dequeue_fd(struct imsgbuf *); - -void -imsg_init(struct imsgbuf *imsgbuf, int fd) +int +imsgbuf_init(struct imsgbuf *imsgbuf, int fd) { - msgbuf_init(&imsgbuf->w); - memset(&imsgbuf->r, 0, sizeof(imsgbuf->r)); - imsgbuf->fd = fd; - imsgbuf->w.fd = fd; + imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr, + imsgbuf); + if (imsgbuf->w == NULL) + return (-1); imsgbuf->pid = getpid(); - TAILQ_INIT(&imsgbuf->fds); + imsgbuf->maxsize = MAX_IMSGSIZE; + imsgbuf->fd = fd; + imsgbuf->flags = 0; + return (0); } -#ifdef _WIN32 -ssize_t -imsg_read(struct imsgbuf *imsgbuf) +void +imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf) { - ssize_t n; - uint8_t *base; - size_t len; - - base = imsgbuf->r.buf + imsgbuf->r.wpos; - len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos; + imsgbuf->flags |= IMSG_ALLOW_FDPASS; +} - while ((n = recv(imsgbuf->fd, base, len, 0)) == -1) { - if (errno != EINTR) - return (-1); - } - imsgbuf->r.wpos += n; - return (n); +void +imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize) +{ + if (maxsize < IMSG_HEADER_SIZE) + return; + imsgbuf->maxsize = maxsize; } -#else -ssize_t -imsg_read(struct imsgbuf *imsgbuf) + +int +imsgbuf_read(struct imsgbuf *imsgbuf) { - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int) * 1)]; - } cmsgbuf; - struct iovec iov; - ssize_t n = -1; - int fd; - struct imsg_fd *ifd; - - memset(&msg, 0, sizeof(msg)); - memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - - iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos; - iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - - if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) - return (-1); + if (imsgbuf->flags & IMSG_ALLOW_FDPASS) + return msgbuf_read(imsgbuf->fd, imsgbuf->w); + else + return ibuf_read(imsgbuf->fd, imsgbuf->w); +} -again: - if (getdtablecount() + imsg_fd_overhead + - (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) - >= getdtablesize()) { - errno = EAGAIN; - free(ifd); - return (-1); - } +int +imsgbuf_write(struct imsgbuf *imsgbuf) +{ + if (imsgbuf->flags & IMSG_ALLOW_FDPASS) + return msgbuf_write(imsgbuf->fd, imsgbuf->w); + else + return ibuf_write(imsgbuf->fd, imsgbuf->w); +} - if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) { - if (errno == EINTR) - goto again; - goto fail; +int +imsgbuf_flush(struct imsgbuf *imsgbuf) +{ + while (imsgbuf_queuelen(imsgbuf) > 0) { + if (imsgbuf_write(imsgbuf) == -1) + return (-1); } + return (0); +} - imsgbuf->r.wpos += n; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - int i; - int j; - - /* - * We only accept one file descriptor. Due to C - * padding rules, our control buffer might contain - * more than one fd, and we must close them. - */ - j = ((char *)cmsg + cmsg->cmsg_len - - (char *)CMSG_DATA(cmsg)) / sizeof(int); - for (i = 0; i < j; i++) { - fd = ((int *)CMSG_DATA(cmsg))[i]; - if (ifd != NULL) { - ifd->fd = fd; - TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd, - entry); - ifd = NULL; - } else - close(fd); - } - } - /* we do not handle other ctl data level */ - } +void +imsgbuf_clear(struct imsgbuf *imsgbuf) +{ + msgbuf_free(imsgbuf->w); + imsgbuf->w = NULL; +} -fail: - free(ifd); - return (n); +uint32_t +imsgbuf_queuelen(struct imsgbuf *imsgbuf) +{ + return msgbuf_queuelen(imsgbuf->w); } -#endif ssize_t imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg) { struct imsg m; - size_t av, left, datalen; - - av = imsgbuf->r.wpos; + struct ibuf *buf; - if (IMSG_HEADER_SIZE > av) + if ((buf = msgbuf_get(imsgbuf->w)) == NULL) return (0); - memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr)); - if (m.hdr.len < IMSG_HEADER_SIZE || - m.hdr.len > MAX_IMSGSIZE) { - errno = ERANGE; + if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1) return (-1); - } - if (m.hdr.len > av) - return (0); - - m.fd = -1; - m.buf = NULL; - m.data = NULL; - - datalen = m.hdr.len - IMSG_HEADER_SIZE; - imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE; - if (datalen != 0) { - if ((m.buf = ibuf_open(datalen)) == NULL) - return (-1); - if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) { - /* this should never fail */ - ibuf_free(m.buf); - return (-1); - } - m.data = ibuf_data(m.buf); - } - - if (m.hdr.flags & IMSGF_HASFD) - m.fd = imsg_dequeue_fd(imsgbuf); - if (m.hdr.len < av) { - left = av - m.hdr.len; - memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left); - imsgbuf->r.wpos = left; - } else - imsgbuf->r.wpos = 0; + if (ibuf_size(buf)) + m.data = ibuf_data(buf); + else + m.data = NULL; + m.buf = buf; *imsg = m; - return (datalen + IMSG_HEADER_SIZE); + return (ibuf_size(buf) + IMSG_HEADER_SIZE); } int imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf) { - if (imsg->buf == NULL) { + if (ibuf_size(imsg->buf) == 0) { errno = EBADMSG; return (-1); } @@ -215,7 +142,7 @@ imsg_get_data(struct imsg *imsg, void *data, size_t len) errno = EINVAL; return (-1); } - if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) { + if (ibuf_size(imsg->buf) != len) { errno = EBADMSG; return (-1); } @@ -225,10 +152,7 @@ imsg_get_data(struct imsg *imsg, void *data, size_t len) int imsg_get_fd(struct imsg *imsg) { - int fd = imsg->fd; - - imsg->fd = -1; - return fd; + return ibuf_fd_get(imsg->buf); } uint32_t @@ -240,8 +164,6 @@ imsg_get_id(struct imsg *imsg) size_t imsg_get_len(struct imsg *imsg) { - if (imsg->buf == NULL) - return 0; return ibuf_size(imsg->buf); } @@ -270,15 +192,14 @@ imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, return (-1); ibuf_fd_set(wbuf, fd); - imsg_close(imsgbuf, wbuf); return (1); } int -imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, - pid_t pid, int fd, const struct iovec *iov, int iovcnt) +imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, + int fd, const struct iovec *iov, int iovcnt) { struct ibuf *wbuf; int i; @@ -295,14 +216,13 @@ imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, return (-1); ibuf_fd_set(wbuf, fd); - imsg_close(imsgbuf, wbuf); return (1); } /* - * Enqueue imsg with payload from ibuf buf. fd passing is not possible + * Enqueue imsg with payload from ibuf buf. fd passing is not possible * with this function. */ int @@ -313,14 +233,13 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, struct imsg_hdr hdr; int save_errno; - if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) { + if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) { errno = ERANGE; goto fail; } hdr.type = type; hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE; - hdr.flags = 0; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; @@ -330,8 +249,8 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1) goto fail; - ibuf_close(&imsgbuf->w, hdrbuf); - ibuf_close(&imsgbuf->w, buf); + ibuf_close(imsgbuf->w, hdrbuf); + ibuf_close(imsgbuf->w, buf); return (1); fail: @@ -351,22 +270,16 @@ imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg) struct ibuf *wbuf; size_t len = 0; - if (msg->fd != -1) { - close(msg->fd); - msg->fd = -1; - } - - if (msg->buf != NULL) { - ibuf_rewind(msg->buf); - len = ibuf_size(msg->buf); - } + ibuf_rewind(msg->buf); + ibuf_skip(msg->buf, sizeof(msg->hdr)); + len = ibuf_size(msg->buf); if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid, msg->hdr.pid, len)) == NULL) return (-1); if (msg->buf != NULL) { - if (ibuf_add_buf(wbuf, msg->buf) == -1) { + if (ibuf_add_ibuf(wbuf, msg->buf) == -1) { ibuf_free(wbuf); return (-1); } @@ -384,17 +297,16 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, struct imsg_hdr hdr; datalen += IMSG_HEADER_SIZE; - if (datalen > MAX_IMSGSIZE) { + if (datalen > imsgbuf->maxsize) { errno = ERANGE; return (NULL); } hdr.type = type; - hdr.flags = 0; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; - if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) { return (NULL); } if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) @@ -420,13 +332,8 @@ imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg) struct imsg_hdr *hdr; hdr = (struct imsg_hdr *)msg->buf; - - hdr->flags &= ~IMSGF_HASFD; - if (ibuf_fd_avail(msg)) - hdr->flags |= IMSGF_HASFD; hdr->len = ibuf_size(msg); - - ibuf_close(&imsgbuf->w, msg); + ibuf_close(imsgbuf->w, msg); } void @@ -435,37 +342,18 @@ imsg_free(struct imsg *imsg) ibuf_free(imsg->buf); } -static int -imsg_dequeue_fd(struct imsgbuf *imsgbuf) +static ssize_t +imsg_parse_hdr(struct ibuf *buf, void *arg) { - int fd; - struct imsg_fd *ifd; + struct imsgbuf *imsgbuf = arg; + struct imsg_hdr hdr; - if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL) + if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1) + return -1; + if (hdr.len < IMSG_HEADER_SIZE || + hdr.len > imsgbuf->maxsize) { + errno = ERANGE; return (-1); - - fd = ifd->fd; - TAILQ_REMOVE(&imsgbuf->fds, ifd, entry); - free(ifd); - - return (fd); -} - -int -imsg_flush(struct imsgbuf *imsgbuf) -{ - while (imsgbuf->w.queued) - if (msgbuf_write(&imsgbuf->w) <= 0) - return (-1); - return (0); -} - -void -imsg_clear(struct imsgbuf *imsgbuf) -{ - int fd; - - msgbuf_clear(&imsgbuf->w); - while ((fd = imsg_dequeue_fd(imsgbuf)) != -1) - close(fd); + } + return hdr.len; } diff --git a/compat/imsg.h b/compat/imsg.h index 626ef7b8..8d78beb3 100644 --- a/compat/imsg.h +++ b/compat/imsg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */ +/* $OpenBSD: imsg.h,v 1.18 2024/11/21 13:03:21 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker @@ -22,7 +22,6 @@ #ifndef _IMSG_H_ #define _IMSG_H_ -#include #include #define IBUF_READ_SIZE 65535 @@ -39,40 +38,25 @@ struct ibuf { int fd; }; -struct msgbuf { - TAILQ_HEAD(, ibuf) bufs; - uint32_t queued; - int fd; -}; - -struct ibuf_read { - unsigned char buf[IBUF_READ_SIZE]; - unsigned char *rptr; - size_t wpos; -}; +struct msgbuf; -struct imsg_fd; struct imsgbuf { - TAILQ_HEAD(, imsg_fd) fds; - struct ibuf_read r; - struct msgbuf w; - int fd; + struct msgbuf *w; pid_t pid; + uint32_t maxsize; + int fd; + int flags; }; -#define IMSGF_HASFD 1 - struct imsg_hdr { uint32_t type; - uint16_t len; - uint16_t flags; + uint32_t len; uint32_t peerid; uint32_t pid; }; struct imsg { struct imsg_hdr hdr; - int fd; void *data; struct ibuf *buf; }; @@ -83,7 +67,6 @@ struct iovec; 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_ibuf(struct ibuf *, const struct ibuf *); int ibuf_add_zero(struct ibuf *, size_t); int ibuf_add_n8(struct ibuf *, uint64_t); @@ -120,20 +103,33 @@ int ibuf_get_n64(struct ibuf *, uint64_t *); int ibuf_get_h16(struct ibuf *, uint16_t *); int ibuf_get_h32(struct ibuf *, uint32_t *); int ibuf_get_h64(struct ibuf *, uint64_t *); +char *ibuf_get_string(struct ibuf *, size_t); int ibuf_skip(struct ibuf *, size_t); 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 *); +struct msgbuf *msgbuf_new(void); +struct msgbuf *msgbuf_new_reader(size_t, ssize_t (*)(struct ibuf *, void *), + void *); +void msgbuf_free(struct msgbuf *); void msgbuf_clear(struct msgbuf *); uint32_t msgbuf_queuelen(struct msgbuf *); -int msgbuf_write(struct msgbuf *); +int ibuf_write(int, struct msgbuf *); +int msgbuf_write(int, struct msgbuf *); +int ibuf_read(int, struct msgbuf *); +int msgbuf_read(int, struct msgbuf *); +struct ibuf *msgbuf_get(struct msgbuf *); /* imsg.c */ -void imsg_init(struct imsgbuf *, int); -ssize_t imsg_read(struct imsgbuf *); +int imsgbuf_init(struct imsgbuf *, int); +void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf); +void imsgbuf_set_maxsize(struct imsgbuf *, uint32_t); +int imsgbuf_read(struct imsgbuf *); +int imsgbuf_write(struct imsgbuf *); +int imsgbuf_flush(struct imsgbuf *); +void imsgbuf_clear(struct imsgbuf *); +uint32_t imsgbuf_queuelen(struct imsgbuf *); ssize_t imsg_get(struct imsgbuf *, struct imsg *); int imsg_get_ibuf(struct imsg *, struct ibuf *); int imsg_get_data(struct imsg *, void *, size_t); @@ -153,7 +149,5 @@ struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t); int imsg_add(struct ibuf *, const void *, size_t); void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); -int imsg_flush(struct imsgbuf *); -void imsg_clear(struct imsgbuf *); #endif