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