xref: /openbsd/lib/libutil/imsg-buffer.c (revision ff59764d)
1 /*	$OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 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 struct msgbuf {
36 	TAILQ_HEAD(, ibuf)	 bufs;
37 	TAILQ_HEAD(, ibuf)	 rbufs;
38 	uint32_t		 queued;
39 	char			*rbuf;
40 	struct ibuf		*rpmsg;
41 	struct ibuf		*(*readhdr)(struct ibuf *, void *, int *);
42 	void			*rarg;
43 	size_t			 roff;
44 	size_t			 hdrsize;
45 };
46 
47 static void	msgbuf_read_enqueue(struct msgbuf *, struct ibuf *);
48 static void	msgbuf_enqueue(struct msgbuf *, struct ibuf *);
49 static void	msgbuf_dequeue(struct msgbuf *, struct ibuf *);
50 static void	msgbuf_drain(struct msgbuf *, size_t);
51 
52 #define	IBUF_FD_MARK_ON_STACK	-2
53 
54 struct ibuf *
ibuf_open(size_t len)55 ibuf_open(size_t len)
56 {
57 	struct ibuf	*buf;
58 
59 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
60 		return (NULL);
61 	if (len > 0) {
62 		if ((buf->buf = calloc(len, 1)) == NULL) {
63 			free(buf);
64 			return (NULL);
65 		}
66 	}
67 	buf->size = buf->max = len;
68 	buf->fd = -1;
69 
70 	return (buf);
71 }
72 
73 struct ibuf *
ibuf_dynamic(size_t len,size_t max)74 ibuf_dynamic(size_t len, size_t max)
75 {
76 	struct ibuf	*buf;
77 
78 	if (max == 0 || max < len) {
79 		errno = EINVAL;
80 		return (NULL);
81 	}
82 
83 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
84 		return (NULL);
85 	if (len > 0) {
86 		if ((buf->buf = calloc(len, 1)) == NULL) {
87 			free(buf);
88 			return (NULL);
89 		}
90 	}
91 	buf->size = len;
92 	buf->max = max;
93 	buf->fd = -1;
94 
95 	return (buf);
96 }
97 
98 void *
ibuf_reserve(struct ibuf * buf,size_t len)99 ibuf_reserve(struct ibuf *buf, size_t len)
100 {
101 	void	*b;
102 
103 	if (len > SIZE_MAX - buf->wpos) {
104 		errno = ERANGE;
105 		return (NULL);
106 	}
107 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
108 		/* can not grow stack buffers */
109 		errno = EINVAL;
110 		return (NULL);
111 	}
112 
113 	if (buf->wpos + len > buf->size) {
114 		unsigned char	*nb;
115 
116 		/* check if buffer is allowed to grow */
117 		if (buf->wpos + len > buf->max) {
118 			errno = ERANGE;
119 			return (NULL);
120 		}
121 		nb = realloc(buf->buf, buf->wpos + len);
122 		if (nb == NULL)
123 			return (NULL);
124 		memset(nb + buf->size, 0, buf->wpos + len - buf->size);
125 		buf->buf = nb;
126 		buf->size = buf->wpos + len;
127 	}
128 
129 	b = buf->buf + buf->wpos;
130 	buf->wpos += len;
131 	return (b);
132 }
133 
134 int
ibuf_add(struct ibuf * buf,const void * data,size_t len)135 ibuf_add(struct ibuf *buf, const void *data, size_t len)
136 {
137 	void *b;
138 
139 	if ((b = ibuf_reserve(buf, len)) == NULL)
140 		return (-1);
141 
142 	memcpy(b, data, len);
143 	return (0);
144 }
145 
146 int
ibuf_add_ibuf(struct ibuf * buf,const struct ibuf * from)147 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
148 {
149 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
150 }
151 
152 int
ibuf_add_n8(struct ibuf * buf,uint64_t value)153 ibuf_add_n8(struct ibuf *buf, uint64_t value)
154 {
155 	uint8_t v;
156 
157 	if (value > UINT8_MAX) {
158 		errno = EINVAL;
159 		return (-1);
160 	}
161 	v = value;
162 	return ibuf_add(buf, &v, sizeof(v));
163 }
164 
165 int
ibuf_add_n16(struct ibuf * buf,uint64_t value)166 ibuf_add_n16(struct ibuf *buf, uint64_t value)
167 {
168 	uint16_t v;
169 
170 	if (value > UINT16_MAX) {
171 		errno = EINVAL;
172 		return (-1);
173 	}
174 	v = htobe16(value);
175 	return ibuf_add(buf, &v, sizeof(v));
176 }
177 
178 int
ibuf_add_n32(struct ibuf * buf,uint64_t value)179 ibuf_add_n32(struct ibuf *buf, uint64_t value)
180 {
181 	uint32_t v;
182 
183 	if (value > UINT32_MAX) {
184 		errno = EINVAL;
185 		return (-1);
186 	}
187 	v = htobe32(value);
188 	return ibuf_add(buf, &v, sizeof(v));
189 }
190 
191 int
ibuf_add_n64(struct ibuf * buf,uint64_t value)192 ibuf_add_n64(struct ibuf *buf, uint64_t value)
193 {
194 	value = htobe64(value);
195 	return ibuf_add(buf, &value, sizeof(value));
196 }
197 
198 int
ibuf_add_h16(struct ibuf * buf,uint64_t value)199 ibuf_add_h16(struct ibuf *buf, uint64_t value)
200 {
201 	uint16_t v;
202 
203 	if (value > UINT16_MAX) {
204 		errno = EINVAL;
205 		return (-1);
206 	}
207 	v = value;
208 	return ibuf_add(buf, &v, sizeof(v));
209 }
210 
211 int
ibuf_add_h32(struct ibuf * buf,uint64_t value)212 ibuf_add_h32(struct ibuf *buf, uint64_t value)
213 {
214 	uint32_t v;
215 
216 	if (value > UINT32_MAX) {
217 		errno = EINVAL;
218 		return (-1);
219 	}
220 	v = value;
221 	return ibuf_add(buf, &v, sizeof(v));
222 }
223 
224 int
ibuf_add_h64(struct ibuf * buf,uint64_t value)225 ibuf_add_h64(struct ibuf *buf, uint64_t value)
226 {
227 	return ibuf_add(buf, &value, sizeof(value));
228 }
229 
230 int
ibuf_add_zero(struct ibuf * buf,size_t len)231 ibuf_add_zero(struct ibuf *buf, size_t len)
232 {
233 	void *b;
234 
235 	if ((b = ibuf_reserve(buf, len)) == NULL)
236 		return (-1);
237 	memset(b, 0, len);
238 	return (0);
239 }
240 
241 void *
ibuf_seek(struct ibuf * buf,size_t pos,size_t len)242 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
243 {
244 	/* only allow seeking between rpos and wpos */
245 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
246 	    ibuf_size(buf) < pos + len) {
247 		errno = ERANGE;
248 		return (NULL);
249 	}
250 
251 	return (buf->buf + buf->rpos + pos);
252 }
253 
254 int
ibuf_set(struct ibuf * buf,size_t pos,const void * data,size_t len)255 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
256 {
257 	void *b;
258 
259 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
260 		return (-1);
261 
262 	memcpy(b, data, len);
263 	return (0);
264 }
265 
266 int
ibuf_set_n8(struct ibuf * buf,size_t pos,uint64_t value)267 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
268 {
269 	uint8_t v;
270 
271 	if (value > UINT8_MAX) {
272 		errno = EINVAL;
273 		return (-1);
274 	}
275 	v = value;
276 	return (ibuf_set(buf, pos, &v, sizeof(v)));
277 }
278 
279 int
ibuf_set_n16(struct ibuf * buf,size_t pos,uint64_t value)280 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
281 {
282 	uint16_t v;
283 
284 	if (value > UINT16_MAX) {
285 		errno = EINVAL;
286 		return (-1);
287 	}
288 	v = htobe16(value);
289 	return (ibuf_set(buf, pos, &v, sizeof(v)));
290 }
291 
292 int
ibuf_set_n32(struct ibuf * buf,size_t pos,uint64_t value)293 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
294 {
295 	uint32_t v;
296 
297 	if (value > UINT32_MAX) {
298 		errno = EINVAL;
299 		return (-1);
300 	}
301 	v = htobe32(value);
302 	return (ibuf_set(buf, pos, &v, sizeof(v)));
303 }
304 
305 int
ibuf_set_n64(struct ibuf * buf,size_t pos,uint64_t value)306 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
307 {
308 	value = htobe64(value);
309 	return (ibuf_set(buf, pos, &value, sizeof(value)));
310 }
311 
312 int
ibuf_set_h16(struct ibuf * buf,size_t pos,uint64_t value)313 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
314 {
315 	uint16_t v;
316 
317 	if (value > UINT16_MAX) {
318 		errno = EINVAL;
319 		return (-1);
320 	}
321 	v = value;
322 	return (ibuf_set(buf, pos, &v, sizeof(v)));
323 }
324 
325 int
ibuf_set_h32(struct ibuf * buf,size_t pos,uint64_t value)326 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
327 {
328 	uint32_t v;
329 
330 	if (value > UINT32_MAX) {
331 		errno = EINVAL;
332 		return (-1);
333 	}
334 	v = value;
335 	return (ibuf_set(buf, pos, &v, sizeof(v)));
336 }
337 
338 int
ibuf_set_h64(struct ibuf * buf,size_t pos,uint64_t value)339 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
340 {
341 	return (ibuf_set(buf, pos, &value, sizeof(value)));
342 }
343 
344 void *
ibuf_data(const struct ibuf * buf)345 ibuf_data(const struct ibuf *buf)
346 {
347 	return (buf->buf + buf->rpos);
348 }
349 
350 size_t
ibuf_size(const struct ibuf * buf)351 ibuf_size(const struct ibuf *buf)
352 {
353 	return (buf->wpos - buf->rpos);
354 }
355 
356 size_t
ibuf_left(const struct ibuf * buf)357 ibuf_left(const struct ibuf *buf)
358 {
359 	/* on stack buffers have no space left */
360 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
361 		return (0);
362 	return (buf->max - buf->wpos);
363 }
364 
365 int
ibuf_truncate(struct ibuf * buf,size_t len)366 ibuf_truncate(struct ibuf *buf, size_t len)
367 {
368 	if (ibuf_size(buf) >= len) {
369 		buf->wpos = buf->rpos + len;
370 		return (0);
371 	}
372 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
373 		/* only allow to truncate down for stack buffers */
374 		errno = ERANGE;
375 		return (-1);
376 	}
377 	return ibuf_add_zero(buf, len - ibuf_size(buf));
378 }
379 
380 void
ibuf_rewind(struct ibuf * buf)381 ibuf_rewind(struct ibuf *buf)
382 {
383 	buf->rpos = 0;
384 }
385 
386 void
ibuf_close(struct msgbuf * msgbuf,struct ibuf * buf)387 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
388 {
389 	msgbuf_enqueue(msgbuf, buf);
390 }
391 
392 void
ibuf_from_buffer(struct ibuf * buf,void * data,size_t len)393 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
394 {
395 	memset(buf, 0, sizeof(*buf));
396 	buf->buf = data;
397 	buf->size = buf->wpos = len;
398 	buf->fd = IBUF_FD_MARK_ON_STACK;
399 }
400 
401 void
ibuf_from_ibuf(struct ibuf * buf,const struct ibuf * from)402 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
403 {
404 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
405 }
406 
407 int
ibuf_get(struct ibuf * buf,void * data,size_t len)408 ibuf_get(struct ibuf *buf, void *data, size_t len)
409 {
410 	if (ibuf_size(buf) < len) {
411 		errno = EBADMSG;
412 		return (-1);
413 	}
414 
415 	memcpy(data, ibuf_data(buf), len);
416 	buf->rpos += len;
417 	return (0);
418 }
419 
420 int
ibuf_get_ibuf(struct ibuf * buf,size_t len,struct ibuf * new)421 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
422 {
423 	if (ibuf_size(buf) < len) {
424 		errno = EBADMSG;
425 		return (-1);
426 	}
427 
428 	ibuf_from_buffer(new, ibuf_data(buf), len);
429 	buf->rpos += len;
430 	return (0);
431 }
432 
433 int
ibuf_get_h16(struct ibuf * buf,uint16_t * value)434 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
435 {
436 	return ibuf_get(buf, value, sizeof(*value));
437 }
438 
439 int
ibuf_get_h32(struct ibuf * buf,uint32_t * value)440 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
441 {
442 	return ibuf_get(buf, value, sizeof(*value));
443 }
444 
445 int
ibuf_get_h64(struct ibuf * buf,uint64_t * value)446 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
447 {
448 	return ibuf_get(buf, value, sizeof(*value));
449 }
450 
451 int
ibuf_get_n8(struct ibuf * buf,uint8_t * value)452 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
453 {
454 	return ibuf_get(buf, value, sizeof(*value));
455 }
456 
457 int
ibuf_get_n16(struct ibuf * buf,uint16_t * value)458 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
459 {
460 	int rv;
461 
462 	rv = ibuf_get(buf, value, sizeof(*value));
463 	*value = be16toh(*value);
464 	return (rv);
465 }
466 
467 int
ibuf_get_n32(struct ibuf * buf,uint32_t * value)468 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
469 {
470 	int rv;
471 
472 	rv = ibuf_get(buf, value, sizeof(*value));
473 	*value = be32toh(*value);
474 	return (rv);
475 }
476 
477 int
ibuf_get_n64(struct ibuf * buf,uint64_t * value)478 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
479 {
480 	int rv;
481 
482 	rv = ibuf_get(buf, value, sizeof(*value));
483 	*value = be64toh(*value);
484 	return (rv);
485 }
486 
487 char *
ibuf_get_string(struct ibuf * buf,size_t len)488 ibuf_get_string(struct ibuf *buf, size_t len)
489 {
490 	char *str;
491 
492 	if (ibuf_size(buf) < len) {
493 		errno = EBADMSG;
494 		return (NULL);
495 	}
496 
497 	str = strndup(ibuf_data(buf), len);
498 	if (str == NULL)
499 		return (NULL);
500 	buf->rpos += len;
501 	return (str);
502 }
503 
504 int
ibuf_skip(struct ibuf * buf,size_t len)505 ibuf_skip(struct ibuf *buf, size_t len)
506 {
507 	if (ibuf_size(buf) < len) {
508 		errno = EBADMSG;
509 		return (-1);
510 	}
511 
512 	buf->rpos += len;
513 	return (0);
514 }
515 
516 void
ibuf_free(struct ibuf * buf)517 ibuf_free(struct ibuf *buf)
518 {
519 	if (buf == NULL)
520 		return;
521 	/* if buf lives on the stack abort before causing more harm */
522 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
523 		abort();
524 	if (buf->fd >= 0)
525 		close(buf->fd);
526 	freezero(buf->buf, buf->size);
527 	free(buf);
528 }
529 
530 int
ibuf_fd_avail(struct ibuf * buf)531 ibuf_fd_avail(struct ibuf *buf)
532 {
533 	return (buf->fd >= 0);
534 }
535 
536 int
ibuf_fd_get(struct ibuf * buf)537 ibuf_fd_get(struct ibuf *buf)
538 {
539 	int fd;
540 
541 	/* negative fds are internal use and equivalent to -1 */
542 	if (buf->fd < 0)
543 		return (-1);
544 	fd = buf->fd;
545 	buf->fd = -1;
546 	return (fd);
547 }
548 
549 void
ibuf_fd_set(struct ibuf * buf,int fd)550 ibuf_fd_set(struct ibuf *buf, int fd)
551 {
552 	/* if buf lives on the stack abort before causing more harm */
553 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
554 		abort();
555 	if (buf->fd >= 0)
556 		close(buf->fd);
557 	buf->fd = -1;
558 	if (fd >= 0)
559 		buf->fd = fd;
560 }
561 
562 struct msgbuf *
msgbuf_new(void)563 msgbuf_new(void)
564 {
565 	struct msgbuf *msgbuf;
566 
567 	if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
568 		return (NULL);
569 	msgbuf->queued = 0;
570 	TAILQ_INIT(&msgbuf->bufs);
571 	TAILQ_INIT(&msgbuf->rbufs);
572 
573 	return msgbuf;
574 }
575 
576 struct msgbuf *
msgbuf_new_reader(size_t hdrsz,struct ibuf * (* readhdr)(struct ibuf *,void *,int *),void * arg)577 msgbuf_new_reader(size_t hdrsz,
578     struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
579 {
580 	struct msgbuf *msgbuf;
581 	char *buf;
582 
583 	if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
584 		errno = EINVAL;
585 		return (NULL);
586 	}
587 
588 	if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
589 		return (NULL);
590 
591 	msgbuf = msgbuf_new();
592 	if (msgbuf == NULL) {
593 		free(buf);
594 		return (NULL);
595 	}
596 
597 	msgbuf->rbuf = buf;
598 	msgbuf->hdrsize = hdrsz;
599 	msgbuf->readhdr = readhdr;
600 	msgbuf->rarg = arg;
601 
602 	return (msgbuf);
603 }
604 
605 void
msgbuf_free(struct msgbuf * msgbuf)606 msgbuf_free(struct msgbuf *msgbuf)
607 {
608 	if (msgbuf == NULL)
609 		return;
610 	msgbuf_clear(msgbuf);
611 	free(msgbuf->rbuf);
612 	free(msgbuf);
613 }
614 
615 uint32_t
msgbuf_queuelen(struct msgbuf * msgbuf)616 msgbuf_queuelen(struct msgbuf *msgbuf)
617 {
618 	return (msgbuf->queued);
619 }
620 
621 void
msgbuf_clear(struct msgbuf * msgbuf)622 msgbuf_clear(struct msgbuf *msgbuf)
623 {
624 	struct ibuf	*buf;
625 
626 	/* write side */
627 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
628 		msgbuf_dequeue(msgbuf, buf);
629 	msgbuf->queued = 0;
630 
631 	/* read side */
632 	while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) {
633 		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
634 		ibuf_free(buf);
635 	}
636 	msgbuf->roff = 0;
637 	ibuf_free(msgbuf->rpmsg);
638 	msgbuf->rpmsg = NULL;
639 }
640 
641 struct ibuf *
msgbuf_get(struct msgbuf * msgbuf)642 msgbuf_get(struct msgbuf *msgbuf)
643 {
644 	struct ibuf	*buf;
645 
646 	if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL)
647 		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
648 	return buf;
649 }
650 
651 int
ibuf_write(int fd,struct msgbuf * msgbuf)652 ibuf_write(int fd, struct msgbuf *msgbuf)
653 {
654 	struct iovec	 iov[IOV_MAX];
655 	struct ibuf	*buf;
656 	unsigned int	 i = 0;
657 	ssize_t	n;
658 
659 	memset(&iov, 0, sizeof(iov));
660 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
661 		if (i >= IOV_MAX)
662 			break;
663 		iov[i].iov_base = ibuf_data(buf);
664 		iov[i].iov_len = ibuf_size(buf);
665 		i++;
666 	}
667 	if (i == 0)
668 		return (0);	/* nothing queued */
669 
670  again:
671 	if ((n = writev(fd, iov, i)) == -1) {
672 		if (errno == EINTR)
673 			goto again;
674 		if (errno == EAGAIN || errno == ENOBUFS)
675 			/* lets retry later again */
676 			return (0);
677 		return (-1);
678 	}
679 
680 	msgbuf_drain(msgbuf, n);
681 	return (0);
682 }
683 
684 int
msgbuf_write(int fd,struct msgbuf * msgbuf)685 msgbuf_write(int fd, struct msgbuf *msgbuf)
686 {
687 	struct iovec	 iov[IOV_MAX];
688 	struct ibuf	*buf, *buf0 = NULL;
689 	unsigned int	 i = 0;
690 	ssize_t		 n;
691 	struct msghdr	 msg;
692 	struct cmsghdr	*cmsg;
693 	union {
694 		struct cmsghdr	hdr;
695 		char		buf[CMSG_SPACE(sizeof(int))];
696 	} cmsgbuf;
697 
698 	memset(&iov, 0, sizeof(iov));
699 	memset(&msg, 0, sizeof(msg));
700 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
701 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
702 		if (i >= IOV_MAX)
703 			break;
704 		if (i > 0 && buf->fd != -1)
705 			break;
706 		iov[i].iov_base = ibuf_data(buf);
707 		iov[i].iov_len = ibuf_size(buf);
708 		i++;
709 		if (buf->fd != -1)
710 			buf0 = buf;
711 	}
712 
713 	if (i == 0)
714 		return (0);	/* nothing queued */
715 
716 	msg.msg_iov = iov;
717 	msg.msg_iovlen = i;
718 
719 	if (buf0 != NULL) {
720 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
721 		msg.msg_controllen = sizeof(cmsgbuf.buf);
722 		cmsg = CMSG_FIRSTHDR(&msg);
723 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
724 		cmsg->cmsg_level = SOL_SOCKET;
725 		cmsg->cmsg_type = SCM_RIGHTS;
726 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
727 	}
728 
729  again:
730 	if ((n = sendmsg(fd, &msg, 0)) == -1) {
731 		if (errno == EINTR)
732 			goto again;
733 		if (errno == EAGAIN || errno == ENOBUFS)
734 			/* lets retry later again */
735 			return (0);
736 		return (-1);
737 	}
738 
739 	/*
740 	 * assumption: fd got sent if sendmsg sent anything
741 	 * this works because fds are passed one at a time
742 	 */
743 	if (buf0 != NULL) {
744 		close(buf0->fd);
745 		buf0->fd = -1;
746 	}
747 
748 	msgbuf_drain(msgbuf, n);
749 
750 	return (0);
751 }
752 
753 static int
ibuf_read_process(struct msgbuf * msgbuf,int fd)754 ibuf_read_process(struct msgbuf *msgbuf, int fd)
755 {
756 	struct ibuf rbuf, msg;
757 	ssize_t sz;
758 
759 	ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
760 
761 	do {
762 		if (msgbuf->rpmsg == NULL) {
763 			if (ibuf_size(&rbuf) < msgbuf->hdrsize)
764 				break;
765 			/* get size from header */
766 			ibuf_from_buffer(&msg, ibuf_data(&rbuf),
767 			    msgbuf->hdrsize);
768 			if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
769 			    msgbuf->rarg, &fd)) == NULL)
770 				goto fail;
771 		}
772 
773 		if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
774 			sz = ibuf_left(msgbuf->rpmsg);
775 		else
776 			sz = ibuf_size(&rbuf);
777 
778 		/* neither call below can fail */
779 		if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
780 		    ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
781 			goto fail;
782 
783 		if (ibuf_left(msgbuf->rpmsg) == 0) {
784 			msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg);
785 			msgbuf->rpmsg = NULL;
786 		}
787 	} while (ibuf_size(&rbuf) > 0);
788 
789 	if (ibuf_size(&rbuf) > 0)
790 		memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
791 	msgbuf->roff = ibuf_size(&rbuf);
792 
793 	if (fd != -1)
794 		close(fd);
795 	return (1);
796 
797  fail:
798 	/* XXX how to properly clean up is unclear */
799 	if (fd != -1)
800 		close(fd);
801 	return (-1);
802 }
803 
804 int
ibuf_read(int fd,struct msgbuf * msgbuf)805 ibuf_read(int fd, struct msgbuf *msgbuf)
806 {
807 	struct iovec	iov;
808 	ssize_t		n;
809 
810 	if (msgbuf->rbuf == NULL) {
811 		errno = EINVAL;
812 		return (-1);
813 	}
814 
815 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
816 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
817 
818  again:
819 	if ((n = readv(fd, &iov, 1)) == -1) {
820 		if (errno == EINTR)
821 			goto again;
822 		if (errno == EAGAIN)
823 			/* lets retry later again */
824 			return (1);
825 		return (-1);
826 	}
827 	if (n == 0)	/* connection closed */
828 		return (0);
829 
830 	msgbuf->roff += n;
831 	/* new data arrived, try to process it */
832 	return (ibuf_read_process(msgbuf, -1));
833 }
834 
835 int
msgbuf_read(int fd,struct msgbuf * msgbuf)836 msgbuf_read(int fd, struct msgbuf *msgbuf)
837 {
838 	struct msghdr		 msg;
839 	struct cmsghdr		*cmsg;
840 	union {
841 		struct cmsghdr hdr;
842 		char	buf[CMSG_SPACE(sizeof(int) * 1)];
843 	} cmsgbuf;
844 	struct iovec		 iov;
845 	ssize_t			 n;
846 	int			 fdpass = -1;
847 
848 	if (msgbuf->rbuf == NULL) {
849 		errno = EINVAL;
850 		return (-1);
851 	}
852 
853 	memset(&msg, 0, sizeof(msg));
854 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
855 
856 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
857 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
858 	msg.msg_iov = &iov;
859 	msg.msg_iovlen = 1;
860 	msg.msg_control = &cmsgbuf.buf;
861 	msg.msg_controllen = sizeof(cmsgbuf.buf);
862 
863 again:
864 	if ((n = recvmsg(fd, &msg, 0)) == -1) {
865 		if (errno == EINTR)
866 			goto again;
867 		if (errno == EMSGSIZE)
868 			/*
869 			 * Not enough fd slots: fd passing failed, retry
870 			 * to receive the message without fd.
871 			 * imsg_get_fd() will return -1 in that case.
872 			 */
873 			goto again;
874 		if (errno == EAGAIN)
875 			/* lets retry later again */
876 			return (1);
877 		return (-1);
878 	}
879 	if (n == 0)	/* connection closed */
880 		return (0);
881 
882 	msgbuf->roff += n;
883 
884 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
885 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
886 		if (cmsg->cmsg_level == SOL_SOCKET &&
887 		    cmsg->cmsg_type == SCM_RIGHTS) {
888 			int i, j, f;
889 
890 			/*
891 			 * We only accept one file descriptor.  Due to C
892 			 * padding rules, our control buffer might contain
893 			 * more than one fd, and we must close them.
894 			 */
895 			j = ((char *)cmsg + cmsg->cmsg_len -
896 			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
897 			for (i = 0; i < j; i++) {
898 				f = ((int *)CMSG_DATA(cmsg))[i];
899 				if (i == 0)
900 					fdpass = f;
901 				else
902 					close(f);
903 			}
904 		}
905 		/* we do not handle other ctl data level */
906 	}
907 
908 	/* new data arrived, try to process it */
909 	return (ibuf_read_process(msgbuf, fdpass));
910 }
911 
912 static void
msgbuf_read_enqueue(struct msgbuf * msgbuf,struct ibuf * buf)913 msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
914 {
915 	/* if buf lives on the stack abort before causing more harm */
916 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
917 		abort();
918 	TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry);
919 }
920 
921 static void
msgbuf_enqueue(struct msgbuf * msgbuf,struct ibuf * buf)922 msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
923 {
924 	/* if buf lives on the stack abort before causing more harm */
925 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
926 		abort();
927 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
928 	msgbuf->queued++;
929 }
930 
931 static void
msgbuf_dequeue(struct msgbuf * msgbuf,struct ibuf * buf)932 msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
933 {
934 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
935 	msgbuf->queued--;
936 	ibuf_free(buf);
937 }
938 
939 static void
msgbuf_drain(struct msgbuf * msgbuf,size_t n)940 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
941 {
942 	struct ibuf	*buf, *next;
943 
944 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
945 	    buf = next) {
946 		next = TAILQ_NEXT(buf, entry);
947 		if (n >= ibuf_size(buf)) {
948 			n -= ibuf_size(buf);
949 			msgbuf_dequeue(msgbuf, buf);
950 		} else {
951 			buf->rpos += n;
952 			n = 0;
953 		}
954 	}
955 }
956