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 * 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 * 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 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 * 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 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 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 158 ibuf_add_buf(struct ibuf *buf, const struct ibuf *from) 159 { 160 return ibuf_add_ibuf(buf, from); 161 } 162 163 int 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 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 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 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 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 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 236 ibuf_add_h64(struct ibuf *buf, uint64_t value) 237 { 238 return ibuf_add(buf, &value, sizeof(value)); 239 } 240 241 int 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 * 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 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 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 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 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 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 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 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 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 * 356 ibuf_data(const struct ibuf *buf) 357 { 358 return (buf->buf + buf->rpos); 359 } 360 361 size_t 362 ibuf_size(const struct ibuf *buf) 363 { 364 return (buf->wpos - buf->rpos); 365 } 366 367 size_t 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 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 391 ibuf_rewind(struct ibuf *buf) 392 { 393 buf->rpos = 0; 394 } 395 396 void 397 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) 398 { 399 ibuf_enqueue(msgbuf, buf); 400 } 401 402 void 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 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 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 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 444 ibuf_get_n8(struct ibuf *buf, uint8_t *value) 445 { 446 return ibuf_get(buf, value, sizeof(*value)); 447 } 448 449 int 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 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 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 480 ibuf_get_h16(struct ibuf *buf, uint16_t *value) 481 { 482 return ibuf_get(buf, value, sizeof(*value)); 483 } 484 485 int 486 ibuf_get_h32(struct ibuf *buf, uint32_t *value) 487 { 488 return ibuf_get(buf, value, sizeof(*value)); 489 } 490 491 int 492 ibuf_get_h64(struct ibuf *buf, uint64_t *value) 493 { 494 return ibuf_get(buf, value, sizeof(*value)); 495 } 496 497 int 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 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 523 ibuf_fd_avail(struct ibuf *buf) 524 { 525 return (buf->fd != -1); 526 } 527 528 int 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 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 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 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 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 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 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 690 msgbuf_queuelen(struct msgbuf *msgbuf) 691 { 692 return (msgbuf->queued); 693 } 694 695 static void 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 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