xref: /openbsd-src/lib/libutil/imsg-buffer.c (revision dcc91c2622318df8f66a9bca2d2864253df1bfc3)
1 /*	$OpenBSD: imsg-buffer.c,v 1.19 2024/08/26 13:57:34 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
23 #include <sys/uio.h>
24 
25 #include <limits.h>
26 #include <errno.h>
27 #include <endian.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include "imsg.h"
34 
35 static int	ibuf_realloc(struct ibuf *, size_t);
36 static void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
37 static void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
38 static void	msgbuf_drain(struct msgbuf *, size_t);
39 
40 struct ibuf *
41 ibuf_open(size_t len)
42 {
43 	struct ibuf	*buf;
44 
45 	if (len == 0) {
46 		errno = EINVAL;
47 		return (NULL);
48 	}
49 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
50 		return (NULL);
51 	if ((buf->buf = calloc(len, 1)) == NULL) {
52 		free(buf);
53 		return (NULL);
54 	}
55 	buf->size = buf->max = len;
56 	buf->fd = -1;
57 
58 	return (buf);
59 }
60 
61 struct ibuf *
62 ibuf_dynamic(size_t len, size_t max)
63 {
64 	struct ibuf	*buf;
65 
66 	if (max == 0 || max < len) {
67 		errno = EINVAL;
68 		return (NULL);
69 	}
70 
71 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
72 		return (NULL);
73 	if (len > 0) {
74 		if ((buf->buf = calloc(len, 1)) == NULL) {
75 			free(buf);
76 			return (NULL);
77 		}
78 	}
79 	buf->size = len;
80 	buf->max = max;
81 	buf->fd = -1;
82 
83 	return (buf);
84 }
85 
86 static int
87 ibuf_realloc(struct ibuf *buf, size_t len)
88 {
89 	unsigned char	*b;
90 
91 	/* on static buffers max is eq size and so the following fails */
92 	if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
93 		errno = ERANGE;
94 		return (-1);
95 	}
96 
97 	b = realloc(buf->buf, buf->wpos + len);
98 	if (b == NULL)
99 		return (-1);
100 	memset(b + buf->size, 0, buf->wpos + len - buf->size);
101 	buf->buf = b;
102 	buf->size = buf->wpos + len;
103 
104 	return (0);
105 }
106 
107 void *
108 ibuf_reserve(struct ibuf *buf, size_t len)
109 {
110 	void	*b;
111 
112 	if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
113 		errno = ERANGE;
114 		return (NULL);
115 	}
116 
117 	if (buf->wpos + len > buf->size)
118 		if (ibuf_realloc(buf, len) == -1)
119 			return (NULL);
120 
121 	b = buf->buf + buf->wpos;
122 	buf->wpos += len;
123 	return (b);
124 }
125 
126 int
127 ibuf_add(struct ibuf *buf, const void *data, size_t len)
128 {
129 	void *b;
130 
131 	if ((b = ibuf_reserve(buf, len)) == NULL)
132 		return (-1);
133 
134 	memcpy(b, data, len);
135 	return (0);
136 }
137 
138 int
139 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
140 {
141 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
142 }
143 
144 /* remove after tree is converted */
145 int
146 ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
147 {
148 	return ibuf_add_ibuf(buf, from);
149 }
150 
151 int
152 ibuf_add_n8(struct ibuf *buf, uint64_t value)
153 {
154 	uint8_t v;
155 
156 	if (value > UINT8_MAX) {
157 		errno = EINVAL;
158 		return (-1);
159 	}
160 	v = value;
161 	return ibuf_add(buf, &v, sizeof(v));
162 }
163 
164 int
165 ibuf_add_n16(struct ibuf *buf, uint64_t value)
166 {
167 	uint16_t v;
168 
169 	if (value > UINT16_MAX) {
170 		errno = EINVAL;
171 		return (-1);
172 	}
173 	v = htobe16(value);
174 	return ibuf_add(buf, &v, sizeof(v));
175 }
176 
177 int
178 ibuf_add_n32(struct ibuf *buf, uint64_t value)
179 {
180 	uint32_t v;
181 
182 	if (value > UINT32_MAX) {
183 		errno = EINVAL;
184 		return (-1);
185 	}
186 	v = htobe32(value);
187 	return ibuf_add(buf, &v, sizeof(v));
188 }
189 
190 int
191 ibuf_add_n64(struct ibuf *buf, uint64_t value)
192 {
193 	value = htobe64(value);
194 	return ibuf_add(buf, &value, sizeof(value));
195 }
196 
197 int
198 ibuf_add_h16(struct ibuf *buf, uint64_t value)
199 {
200 	uint16_t v;
201 
202 	if (value > UINT16_MAX) {
203 		errno = EINVAL;
204 		return (-1);
205 	}
206 	v = value;
207 	return ibuf_add(buf, &v, sizeof(v));
208 }
209 
210 int
211 ibuf_add_h32(struct ibuf *buf, uint64_t value)
212 {
213 	uint32_t v;
214 
215 	if (value > UINT32_MAX) {
216 		errno = EINVAL;
217 		return (-1);
218 	}
219 	v = value;
220 	return ibuf_add(buf, &v, sizeof(v));
221 }
222 
223 int
224 ibuf_add_h64(struct ibuf *buf, uint64_t value)
225 {
226 	return ibuf_add(buf, &value, sizeof(value));
227 }
228 
229 int
230 ibuf_add_zero(struct ibuf *buf, size_t len)
231 {
232 	void *b;
233 
234 	if ((b = ibuf_reserve(buf, len)) == NULL)
235 		return (-1);
236 	memset(b, 0, len);
237 	return (0);
238 }
239 
240 void *
241 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
242 {
243 	/* only allow seeking between rpos and wpos */
244 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
245 	    ibuf_size(buf) < pos + len) {
246 		errno = ERANGE;
247 		return (NULL);
248 	}
249 
250 	return (buf->buf + buf->rpos + pos);
251 }
252 
253 int
254 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
255 {
256 	void *b;
257 
258 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
259 		return (-1);
260 
261 	memcpy(b, data, len);
262 	return (0);
263 }
264 
265 int
266 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
267 {
268 	uint8_t v;
269 
270 	if (value > UINT8_MAX) {
271 		errno = EINVAL;
272 		return (-1);
273 	}
274 	v = value;
275 	return (ibuf_set(buf, pos, &v, sizeof(v)));
276 }
277 
278 int
279 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
280 {
281 	uint16_t v;
282 
283 	if (value > UINT16_MAX) {
284 		errno = EINVAL;
285 		return (-1);
286 	}
287 	v = htobe16(value);
288 	return (ibuf_set(buf, pos, &v, sizeof(v)));
289 }
290 
291 int
292 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
293 {
294 	uint32_t v;
295 
296 	if (value > UINT32_MAX) {
297 		errno = EINVAL;
298 		return (-1);
299 	}
300 	v = htobe32(value);
301 	return (ibuf_set(buf, pos, &v, sizeof(v)));
302 }
303 
304 int
305 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
306 {
307 	value = htobe64(value);
308 	return (ibuf_set(buf, pos, &value, sizeof(value)));
309 }
310 
311 int
312 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
313 {
314 	uint16_t v;
315 
316 	if (value > UINT16_MAX) {
317 		errno = EINVAL;
318 		return (-1);
319 	}
320 	v = value;
321 	return (ibuf_set(buf, pos, &v, sizeof(v)));
322 }
323 
324 int
325 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
326 {
327 	uint32_t v;
328 
329 	if (value > UINT32_MAX) {
330 		errno = EINVAL;
331 		return (-1);
332 	}
333 	v = value;
334 	return (ibuf_set(buf, pos, &v, sizeof(v)));
335 }
336 
337 int
338 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
339 {
340 	return (ibuf_set(buf, pos, &value, sizeof(value)));
341 }
342 
343 void *
344 ibuf_data(const struct ibuf *buf)
345 {
346 	return (buf->buf + buf->rpos);
347 }
348 
349 size_t
350 ibuf_size(const struct ibuf *buf)
351 {
352 	return (buf->wpos - buf->rpos);
353 }
354 
355 size_t
356 ibuf_left(const struct ibuf *buf)
357 {
358 	if (buf->max == 0)
359 		return (0);
360 	return (buf->max - buf->wpos);
361 }
362 
363 int
364 ibuf_truncate(struct ibuf *buf, size_t len)
365 {
366 	if (ibuf_size(buf) >= len) {
367 		buf->wpos = buf->rpos + len;
368 		return (0);
369 	}
370 	if (buf->max == 0) {
371 		/* only allow to truncate down */
372 		errno = ERANGE;
373 		return (-1);
374 	}
375 	return ibuf_add_zero(buf, len - ibuf_size(buf));
376 }
377 
378 void
379 ibuf_rewind(struct ibuf *buf)
380 {
381 	buf->rpos = 0;
382 }
383 
384 void
385 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
386 {
387 	ibuf_enqueue(msgbuf, buf);
388 }
389 
390 void
391 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
392 {
393 	memset(buf, 0, sizeof(*buf));
394 	buf->buf = data;
395 	buf->size = buf->wpos = len;
396 	buf->fd = -1;
397 }
398 
399 void
400 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
401 {
402 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
403 }
404 
405 int
406 ibuf_get(struct ibuf *buf, void *data, size_t len)
407 {
408 	if (ibuf_size(buf) < len) {
409 		errno = EBADMSG;
410 		return (-1);
411 	}
412 
413 	memcpy(data, ibuf_data(buf), len);
414 	buf->rpos += len;
415 	return (0);
416 }
417 
418 int
419 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
420 {
421 	if (ibuf_size(buf) < len) {
422 		errno = EBADMSG;
423 		return (-1);
424 	}
425 
426 	ibuf_from_buffer(new, ibuf_data(buf), len);
427 	buf->rpos += len;
428 	return (0);
429 }
430 
431 int
432 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
433 {
434 	return ibuf_get(buf, value, sizeof(*value));
435 }
436 
437 int
438 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
439 {
440 	int rv;
441 
442 	rv = ibuf_get(buf, value, sizeof(*value));
443 	*value = be16toh(*value);
444 	return (rv);
445 }
446 
447 int
448 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
449 {
450 	int rv;
451 
452 	rv = ibuf_get(buf, value, sizeof(*value));
453 	*value = be32toh(*value);
454 	return (rv);
455 }
456 
457 int
458 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
459 {
460 	int rv;
461 
462 	rv = ibuf_get(buf, value, sizeof(*value));
463 	*value = be64toh(*value);
464 	return (rv);
465 }
466 
467 int
468 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
469 {
470 	return ibuf_get(buf, value, sizeof(*value));
471 }
472 
473 int
474 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
475 {
476 	return ibuf_get(buf, value, sizeof(*value));
477 }
478 
479 int
480 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
481 {
482 	return ibuf_get(buf, value, sizeof(*value));
483 }
484 
485 int
486 ibuf_skip(struct ibuf *buf, size_t len)
487 {
488 	if (ibuf_size(buf) < len) {
489 		errno = EBADMSG;
490 		return (-1);
491 	}
492 
493 	buf->rpos += len;
494 	return (0);
495 }
496 
497 void
498 ibuf_free(struct ibuf *buf)
499 {
500 	if (buf == NULL)
501 		return;
502 	if (buf->max == 0)	/* if buf lives on the stack */
503 		abort();	/* abort before causing more harm */
504 	if (buf->fd != -1)
505 		close(buf->fd);
506 	freezero(buf->buf, buf->size);
507 	free(buf);
508 }
509 
510 int
511 ibuf_fd_avail(struct ibuf *buf)
512 {
513 	return (buf->fd != -1);
514 }
515 
516 int
517 ibuf_fd_get(struct ibuf *buf)
518 {
519 	int fd;
520 
521 	fd = buf->fd;
522 	buf->fd = -1;
523 	return (fd);
524 }
525 
526 void
527 ibuf_fd_set(struct ibuf *buf, int fd)
528 {
529 	if (buf->max == 0)	/* if buf lives on the stack */
530 		abort();	/* abort before causing more harm */
531 	if (buf->fd != -1)
532 		close(buf->fd);
533 	buf->fd = fd;
534 }
535 
536 int
537 ibuf_write(struct msgbuf *msgbuf)
538 {
539 	struct iovec	 iov[IOV_MAX];
540 	struct ibuf	*buf;
541 	unsigned int	 i = 0;
542 	ssize_t	n;
543 
544 	memset(&iov, 0, sizeof(iov));
545 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
546 		if (i >= IOV_MAX)
547 			break;
548 		iov[i].iov_base = ibuf_data(buf);
549 		iov[i].iov_len = ibuf_size(buf);
550 		i++;
551 	}
552 
553 again:
554 	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
555 		if (errno == EINTR)
556 			goto again;
557 		if (errno == ENOBUFS)
558 			errno = EAGAIN;
559 		return (-1);
560 	}
561 
562 	if (n == 0) {			/* connection closed */
563 		errno = 0;
564 		return (0);
565 	}
566 
567 	msgbuf_drain(msgbuf, n);
568 
569 	return (1);
570 }
571 
572 void
573 msgbuf_init(struct msgbuf *msgbuf)
574 {
575 	msgbuf->queued = 0;
576 	msgbuf->fd = -1;
577 	TAILQ_INIT(&msgbuf->bufs);
578 }
579 
580 static void
581 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
582 {
583 	struct ibuf	*buf, *next;
584 
585 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
586 	    buf = next) {
587 		next = TAILQ_NEXT(buf, entry);
588 		if (n >= ibuf_size(buf)) {
589 			n -= ibuf_size(buf);
590 			ibuf_dequeue(msgbuf, buf);
591 		} else {
592 			buf->rpos += n;
593 			n = 0;
594 		}
595 	}
596 }
597 
598 void
599 msgbuf_clear(struct msgbuf *msgbuf)
600 {
601 	struct ibuf	*buf;
602 
603 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
604 		ibuf_dequeue(msgbuf, buf);
605 }
606 
607 int
608 msgbuf_write(struct msgbuf *msgbuf)
609 {
610 	struct iovec	 iov[IOV_MAX];
611 	struct ibuf	*buf, *buf0 = NULL;
612 	unsigned int	 i = 0;
613 	ssize_t		 n;
614 	struct msghdr	 msg;
615 	struct cmsghdr	*cmsg;
616 	union {
617 		struct cmsghdr	hdr;
618 		char		buf[CMSG_SPACE(sizeof(int))];
619 	} cmsgbuf;
620 
621 	memset(&iov, 0, sizeof(iov));
622 	memset(&msg, 0, sizeof(msg));
623 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
624 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
625 		if (i >= IOV_MAX)
626 			break;
627 		if (i > 0 && buf->fd != -1)
628 			break;
629 		iov[i].iov_base = ibuf_data(buf);
630 		iov[i].iov_len = ibuf_size(buf);
631 		i++;
632 		if (buf->fd != -1)
633 			buf0 = buf;
634 	}
635 
636 	msg.msg_iov = iov;
637 	msg.msg_iovlen = i;
638 
639 	if (buf0 != NULL) {
640 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
641 		msg.msg_controllen = sizeof(cmsgbuf.buf);
642 		cmsg = CMSG_FIRSTHDR(&msg);
643 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
644 		cmsg->cmsg_level = SOL_SOCKET;
645 		cmsg->cmsg_type = SCM_RIGHTS;
646 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
647 	}
648 
649 again:
650 	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
651 		if (errno == EINTR)
652 			goto again;
653 		if (errno == ENOBUFS)
654 			errno = EAGAIN;
655 		return (-1);
656 	}
657 
658 	if (n == 0) {			/* connection closed */
659 		errno = 0;
660 		return (0);
661 	}
662 
663 	/*
664 	 * assumption: fd got sent if sendmsg sent anything
665 	 * this works because fds are passed one at a time
666 	 */
667 	if (buf0 != NULL) {
668 		close(buf0->fd);
669 		buf0->fd = -1;
670 	}
671 
672 	msgbuf_drain(msgbuf, n);
673 
674 	return (1);
675 }
676 
677 uint32_t
678 msgbuf_queuelen(struct msgbuf *msgbuf)
679 {
680 	return (msgbuf->queued);
681 }
682 
683 static void
684 ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
685 {
686 	if (buf->max == 0)	/* if buf lives on the stack */
687 		abort();	/* abort before causing more harm */
688 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
689 	msgbuf->queued++;
690 }
691 
692 static void
693 ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
694 {
695 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
696 	msgbuf->queued--;
697 	ibuf_free(buf);
698 }
699