xref: /openbsd/lib/libutil/imsg-buffer.c (revision 4658a150)
1 /*	$OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 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 *
ibuf_open(size_t len)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 *
ibuf_dynamic(size_t len,size_t max)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
ibuf_realloc(struct ibuf * buf,size_t len)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 = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
98 	if (b == NULL)
99 		return (-1);
100 	buf->buf = b;
101 	buf->size = buf->wpos + len;
102 
103 	return (0);
104 }
105 
106 void *
ibuf_reserve(struct ibuf * buf,size_t len)107 ibuf_reserve(struct ibuf *buf, size_t len)
108 {
109 	void	*b;
110 
111 	if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
112 		errno = ERANGE;
113 		return (NULL);
114 	}
115 
116 	if (buf->wpos + len > buf->size)
117 		if (ibuf_realloc(buf, len) == -1)
118 			return (NULL);
119 
120 	b = buf->buf + buf->wpos;
121 	buf->wpos += len;
122 	return (b);
123 }
124 
125 int
ibuf_add(struct ibuf * buf,const void * data,size_t len)126 ibuf_add(struct ibuf *buf, const void *data, size_t len)
127 {
128 	void *b;
129 
130 	if ((b = ibuf_reserve(buf, len)) == NULL)
131 		return (-1);
132 
133 	memcpy(b, data, len);
134 	return (0);
135 }
136 
137 int
ibuf_add_ibuf(struct ibuf * buf,const struct ibuf * from)138 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
139 {
140 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
141 }
142 
143 /* remove after tree is converted */
144 int
ibuf_add_buf(struct ibuf * buf,const struct ibuf * from)145 ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
146 {
147 	return ibuf_add_ibuf(buf, from);
148 }
149 
150 int
ibuf_add_n8(struct ibuf * buf,uint64_t value)151 ibuf_add_n8(struct ibuf *buf, uint64_t value)
152 {
153 	uint8_t v;
154 
155 	if (value > UINT8_MAX) {
156 		errno = EINVAL;
157 		return (-1);
158 	}
159 	v = value;
160 	return ibuf_add(buf, &v, sizeof(v));
161 }
162 
163 int
ibuf_add_n16(struct ibuf * buf,uint64_t value)164 ibuf_add_n16(struct ibuf *buf, uint64_t value)
165 {
166 	uint16_t v;
167 
168 	if (value > UINT16_MAX) {
169 		errno = EINVAL;
170 		return (-1);
171 	}
172 	v = htobe16(value);
173 	return ibuf_add(buf, &v, sizeof(v));
174 }
175 
176 int
ibuf_add_n32(struct ibuf * buf,uint64_t value)177 ibuf_add_n32(struct ibuf *buf, uint64_t value)
178 {
179 	uint32_t v;
180 
181 	if (value > UINT32_MAX) {
182 		errno = EINVAL;
183 		return (-1);
184 	}
185 	v = htobe32(value);
186 	return ibuf_add(buf, &v, sizeof(v));
187 }
188 
189 int
ibuf_add_n64(struct ibuf * buf,uint64_t value)190 ibuf_add_n64(struct ibuf *buf, uint64_t value)
191 {
192 	value = htobe64(value);
193 	return ibuf_add(buf, &value, sizeof(value));
194 }
195 
196 int
ibuf_add_h16(struct ibuf * buf,uint64_t value)197 ibuf_add_h16(struct ibuf *buf, uint64_t value)
198 {
199 	uint16_t v;
200 
201 	if (value > UINT16_MAX) {
202 		errno = EINVAL;
203 		return (-1);
204 	}
205 	v = value;
206 	return ibuf_add(buf, &v, sizeof(v));
207 }
208 
209 int
ibuf_add_h32(struct ibuf * buf,uint64_t value)210 ibuf_add_h32(struct ibuf *buf, uint64_t value)
211 {
212 	uint32_t v;
213 
214 	if (value > UINT32_MAX) {
215 		errno = EINVAL;
216 		return (-1);
217 	}
218 	v = value;
219 	return ibuf_add(buf, &v, sizeof(v));
220 }
221 
222 int
ibuf_add_h64(struct ibuf * buf,uint64_t value)223 ibuf_add_h64(struct ibuf *buf, uint64_t value)
224 {
225 	return ibuf_add(buf, &value, sizeof(value));
226 }
227 
228 int
ibuf_add_zero(struct ibuf * buf,size_t len)229 ibuf_add_zero(struct ibuf *buf, size_t len)
230 {
231 	void *b;
232 
233 	if ((b = ibuf_reserve(buf, len)) == NULL)
234 		return (-1);
235 	memset(b, 0, len);
236 	return (0);
237 }
238 
239 void *
ibuf_seek(struct ibuf * buf,size_t pos,size_t len)240 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
241 {
242 	/* only allow seeking between rpos and wpos */
243 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
244 	    ibuf_size(buf) < pos + len) {
245 		errno = ERANGE;
246 		return (NULL);
247 	}
248 
249 	return (buf->buf + buf->rpos + pos);
250 }
251 
252 int
ibuf_set(struct ibuf * buf,size_t pos,const void * data,size_t len)253 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
254 {
255 	void *b;
256 
257 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
258 		return (-1);
259 
260 	memcpy(b, data, len);
261 	return (0);
262 }
263 
264 int
ibuf_set_n8(struct ibuf * buf,size_t pos,uint64_t value)265 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
266 {
267 	uint8_t v;
268 
269 	if (value > UINT8_MAX) {
270 		errno = EINVAL;
271 		return (-1);
272 	}
273 	v = value;
274 	return (ibuf_set(buf, pos, &v, sizeof(v)));
275 }
276 
277 int
ibuf_set_n16(struct ibuf * buf,size_t pos,uint64_t value)278 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
279 {
280 	uint16_t v;
281 
282 	if (value > UINT16_MAX) {
283 		errno = EINVAL;
284 		return (-1);
285 	}
286 	v = htobe16(value);
287 	return (ibuf_set(buf, pos, &v, sizeof(v)));
288 }
289 
290 int
ibuf_set_n32(struct ibuf * buf,size_t pos,uint64_t value)291 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
292 {
293 	uint32_t v;
294 
295 	if (value > UINT32_MAX) {
296 		errno = EINVAL;
297 		return (-1);
298 	}
299 	v = htobe32(value);
300 	return (ibuf_set(buf, pos, &v, sizeof(v)));
301 }
302 
303 int
ibuf_set_n64(struct ibuf * buf,size_t pos,uint64_t value)304 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
305 {
306 	value = htobe64(value);
307 	return (ibuf_set(buf, pos, &value, sizeof(value)));
308 }
309 
310 int
ibuf_set_h16(struct ibuf * buf,size_t pos,uint64_t value)311 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
312 {
313 	uint16_t v;
314 
315 	if (value > UINT16_MAX) {
316 		errno = EINVAL;
317 		return (-1);
318 	}
319 	v = value;
320 	return (ibuf_set(buf, pos, &v, sizeof(v)));
321 }
322 
323 int
ibuf_set_h32(struct ibuf * buf,size_t pos,uint64_t value)324 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
325 {
326 	uint32_t v;
327 
328 	if (value > UINT32_MAX) {
329 		errno = EINVAL;
330 		return (-1);
331 	}
332 	v = value;
333 	return (ibuf_set(buf, pos, &v, sizeof(v)));
334 }
335 
336 int
ibuf_set_h64(struct ibuf * buf,size_t pos,uint64_t value)337 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
338 {
339 	return (ibuf_set(buf, pos, &value, sizeof(value)));
340 }
341 
342 void *
ibuf_data(const struct ibuf * buf)343 ibuf_data(const struct ibuf *buf)
344 {
345 	return (buf->buf + buf->rpos);
346 }
347 
348 size_t
ibuf_size(const struct ibuf * buf)349 ibuf_size(const struct ibuf *buf)
350 {
351 	return (buf->wpos - buf->rpos);
352 }
353 
354 size_t
ibuf_left(const struct ibuf * buf)355 ibuf_left(const struct ibuf *buf)
356 {
357 	if (buf->max == 0)
358 		return (0);
359 	return (buf->max - buf->wpos);
360 }
361 
362 int
ibuf_truncate(struct ibuf * buf,size_t len)363 ibuf_truncate(struct ibuf *buf, size_t len)
364 {
365 	if (ibuf_size(buf) >= len) {
366 		buf->wpos = buf->rpos + len;
367 		return (0);
368 	}
369 	if (buf->max == 0) {
370 		/* only allow to truncate down */
371 		errno = ERANGE;
372 		return (-1);
373 	}
374 	return ibuf_add_zero(buf, len - ibuf_size(buf));
375 }
376 
377 void
ibuf_rewind(struct ibuf * buf)378 ibuf_rewind(struct ibuf *buf)
379 {
380 	buf->rpos = 0;
381 }
382 
383 void
ibuf_close(struct msgbuf * msgbuf,struct ibuf * buf)384 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
385 {
386 	ibuf_enqueue(msgbuf, buf);
387 }
388 
389 void
ibuf_from_buffer(struct ibuf * buf,void * data,size_t len)390 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
391 {
392 	memset(buf, 0, sizeof(*buf));
393 	buf->buf = data;
394 	buf->size = buf->wpos = len;
395 	buf->fd = -1;
396 }
397 
398 void
ibuf_from_ibuf(struct ibuf * buf,const struct ibuf * from)399 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
400 {
401 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
402 }
403 
404 int
ibuf_get(struct ibuf * buf,void * data,size_t len)405 ibuf_get(struct ibuf *buf, void *data, size_t len)
406 {
407 	if (ibuf_size(buf) < len) {
408 		errno = EBADMSG;
409 		return (-1);
410 	}
411 
412 	memcpy(data, ibuf_data(buf), len);
413 	buf->rpos += len;
414 	return (0);
415 }
416 
417 int
ibuf_get_ibuf(struct ibuf * buf,size_t len,struct ibuf * new)418 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
419 {
420 	if (ibuf_size(buf) < len) {
421 		errno = EBADMSG;
422 		return (-1);
423 	}
424 
425 	ibuf_from_buffer(new, ibuf_data(buf), len);
426 	buf->rpos += len;
427 	return (0);
428 }
429 
430 int
ibuf_get_n8(struct ibuf * buf,uint8_t * value)431 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
432 {
433 	return ibuf_get(buf, value, sizeof(*value));
434 }
435 
436 int
ibuf_get_n16(struct ibuf * buf,uint16_t * value)437 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
438 {
439 	int rv;
440 
441 	rv = ibuf_get(buf, value, sizeof(*value));
442 	*value = be16toh(*value);
443 	return (rv);
444 }
445 
446 int
ibuf_get_n32(struct ibuf * buf,uint32_t * value)447 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
448 {
449 	int rv;
450 
451 	rv = ibuf_get(buf, value, sizeof(*value));
452 	*value = be32toh(*value);
453 	return (rv);
454 }
455 
456 int
ibuf_get_n64(struct ibuf * buf,uint64_t * value)457 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
458 {
459 	int rv;
460 
461 	rv = ibuf_get(buf, value, sizeof(*value));
462 	*value = be64toh(*value);
463 	return (rv);
464 }
465 
466 int
ibuf_get_h16(struct ibuf * buf,uint16_t * value)467 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
468 {
469 	return ibuf_get(buf, value, sizeof(*value));
470 }
471 
472 int
ibuf_get_h32(struct ibuf * buf,uint32_t * value)473 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
474 {
475 	return ibuf_get(buf, value, sizeof(*value));
476 }
477 
478 int
ibuf_get_h64(struct ibuf * buf,uint64_t * value)479 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
480 {
481 	return ibuf_get(buf, value, sizeof(*value));
482 }
483 
484 int
ibuf_skip(struct ibuf * buf,size_t len)485 ibuf_skip(struct ibuf *buf, size_t len)
486 {
487 	if (ibuf_size(buf) < len) {
488 		errno = EBADMSG;
489 		return (-1);
490 	}
491 
492 	buf->rpos += len;
493 	return (0);
494 }
495 
496 void
ibuf_free(struct ibuf * buf)497 ibuf_free(struct ibuf *buf)
498 {
499 	if (buf == NULL)
500 		return;
501 	if (buf->max == 0)	/* if buf lives on the stack */
502 		abort();	/* abort before causing more harm */
503 	if (buf->fd != -1)
504 		close(buf->fd);
505 	freezero(buf->buf, buf->size);
506 	free(buf);
507 }
508 
509 int
ibuf_fd_avail(struct ibuf * buf)510 ibuf_fd_avail(struct ibuf *buf)
511 {
512 	return (buf->fd != -1);
513 }
514 
515 int
ibuf_fd_get(struct ibuf * buf)516 ibuf_fd_get(struct ibuf *buf)
517 {
518 	int fd;
519 
520 	fd = buf->fd;
521 	buf->fd = -1;
522 	return (fd);
523 }
524 
525 void
ibuf_fd_set(struct ibuf * buf,int fd)526 ibuf_fd_set(struct ibuf *buf, int fd)
527 {
528 	if (buf->max == 0)	/* if buf lives on the stack */
529 		abort();	/* abort before causing more harm */
530 	if (buf->fd != -1)
531 		close(buf->fd);
532 	buf->fd = fd;
533 }
534 
535 int
ibuf_write(struct msgbuf * msgbuf)536 ibuf_write(struct msgbuf *msgbuf)
537 {
538 	struct iovec	 iov[IOV_MAX];
539 	struct ibuf	*buf;
540 	unsigned int	 i = 0;
541 	ssize_t	n;
542 
543 	memset(&iov, 0, sizeof(iov));
544 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
545 		if (i >= IOV_MAX)
546 			break;
547 		iov[i].iov_base = ibuf_data(buf);
548 		iov[i].iov_len = ibuf_size(buf);
549 		i++;
550 	}
551 
552 again:
553 	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
554 		if (errno == EINTR)
555 			goto again;
556 		if (errno == ENOBUFS)
557 			errno = EAGAIN;
558 		return (-1);
559 	}
560 
561 	if (n == 0) {			/* connection closed */
562 		errno = 0;
563 		return (0);
564 	}
565 
566 	msgbuf_drain(msgbuf, n);
567 
568 	return (1);
569 }
570 
571 void
msgbuf_init(struct msgbuf * msgbuf)572 msgbuf_init(struct msgbuf *msgbuf)
573 {
574 	msgbuf->queued = 0;
575 	msgbuf->fd = -1;
576 	TAILQ_INIT(&msgbuf->bufs);
577 }
578 
579 static void
msgbuf_drain(struct msgbuf * msgbuf,size_t n)580 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
581 {
582 	struct ibuf	*buf, *next;
583 
584 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
585 	    buf = next) {
586 		next = TAILQ_NEXT(buf, entry);
587 		if (n >= ibuf_size(buf)) {
588 			n -= ibuf_size(buf);
589 			ibuf_dequeue(msgbuf, buf);
590 		} else {
591 			buf->rpos += n;
592 			n = 0;
593 		}
594 	}
595 }
596 
597 void
msgbuf_clear(struct msgbuf * msgbuf)598 msgbuf_clear(struct msgbuf *msgbuf)
599 {
600 	struct ibuf	*buf;
601 
602 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
603 		ibuf_dequeue(msgbuf, buf);
604 }
605 
606 int
msgbuf_write(struct msgbuf * msgbuf)607 msgbuf_write(struct msgbuf *msgbuf)
608 {
609 	struct iovec	 iov[IOV_MAX];
610 	struct ibuf	*buf, *buf0 = NULL;
611 	unsigned int	 i = 0;
612 	ssize_t		 n;
613 	struct msghdr	 msg;
614 	struct cmsghdr	*cmsg;
615 	union {
616 		struct cmsghdr	hdr;
617 		char		buf[CMSG_SPACE(sizeof(int))];
618 	} cmsgbuf;
619 
620 	memset(&iov, 0, sizeof(iov));
621 	memset(&msg, 0, sizeof(msg));
622 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
623 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
624 		if (i >= IOV_MAX)
625 			break;
626 		if (i > 0 && buf->fd != -1)
627 			break;
628 		iov[i].iov_base = ibuf_data(buf);
629 		iov[i].iov_len = ibuf_size(buf);
630 		i++;
631 		if (buf->fd != -1)
632 			buf0 = buf;
633 	}
634 
635 	msg.msg_iov = iov;
636 	msg.msg_iovlen = i;
637 
638 	if (buf0 != NULL) {
639 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
640 		msg.msg_controllen = sizeof(cmsgbuf.buf);
641 		cmsg = CMSG_FIRSTHDR(&msg);
642 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
643 		cmsg->cmsg_level = SOL_SOCKET;
644 		cmsg->cmsg_type = SCM_RIGHTS;
645 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
646 	}
647 
648 again:
649 	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
650 		if (errno == EINTR)
651 			goto again;
652 		if (errno == ENOBUFS)
653 			errno = EAGAIN;
654 		return (-1);
655 	}
656 
657 	if (n == 0) {			/* connection closed */
658 		errno = 0;
659 		return (0);
660 	}
661 
662 	/*
663 	 * assumption: fd got sent if sendmsg sent anything
664 	 * this works because fds are passed one at a time
665 	 */
666 	if (buf0 != NULL) {
667 		close(buf0->fd);
668 		buf0->fd = -1;
669 	}
670 
671 	msgbuf_drain(msgbuf, n);
672 
673 	return (1);
674 }
675 
676 uint32_t
msgbuf_queuelen(struct msgbuf * msgbuf)677 msgbuf_queuelen(struct msgbuf *msgbuf)
678 {
679 	return (msgbuf->queued);
680 }
681 
682 static void
ibuf_enqueue(struct msgbuf * msgbuf,struct ibuf * buf)683 ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
684 {
685 	if (buf->max == 0)	/* if buf lives on the stack */
686 		abort();	/* abort before causing more harm */
687 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
688 	msgbuf->queued++;
689 }
690 
691 static void
ibuf_dequeue(struct msgbuf * msgbuf,struct ibuf * buf)692 ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
693 {
694 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
695 	msgbuf->queued--;
696 	ibuf_free(buf);
697 }
698