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