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