1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Privilege Separation for dhcpcd, privileged proxy 4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name> 5 * All rights reserved 6 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/ioctl.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/time.h> 33 #include <sys/types.h> 34 #include <sys/wait.h> 35 36 #include <assert.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <pwd.h> 40 #include <signal.h> 41 #include <stddef.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "auth.h" 47 #include "common.h" 48 #include "dev.h" 49 #include "dhcpcd.h" 50 #include "dhcp6.h" 51 #include "eloop.h" 52 #include "if.h" 53 #include "ipv6nd.h" 54 #include "logerr.h" 55 #include "privsep.h" 56 #include "sa.h" 57 #include "script.h" 58 59 __CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long)); 60 61 struct psr_error 62 { 63 ssize_t psr_result; 64 int psr_errno; 65 char psr_pad[sizeof(ssize_t) - sizeof(int)]; 66 size_t psr_datalen; 67 }; 68 69 struct psr_ctx { 70 struct dhcpcd_ctx *psr_ctx; 71 struct psr_error psr_error; 72 size_t psr_datalen; 73 void *psr_data; 74 }; 75 76 static void 77 ps_root_readerrorcb(void *arg, unsigned short events) 78 { 79 struct psr_ctx *psr_ctx = arg; 80 struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; 81 struct psr_error *psr_error = &psr_ctx->psr_error; 82 struct iovec iov[] = { 83 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) }, 84 { .iov_base = psr_ctx->psr_data, 85 .iov_len = psr_ctx->psr_datalen }, 86 }; 87 ssize_t len; 88 int exit_code = EXIT_FAILURE; 89 90 if (events != ELE_READ) 91 logerrx("%s: unexpected event 0x%04x", __func__, events); 92 93 #define PSR_ERROR(e) \ 94 do { \ 95 psr_error->psr_result = -1; \ 96 psr_error->psr_errno = (e); \ 97 goto out; \ 98 } while (0 /* CONSTCOND */) 99 100 len = readv(ctx->ps_root->psp_fd, iov, __arraycount(iov)); 101 if (len == -1) 102 PSR_ERROR(errno); 103 else if ((size_t)len < sizeof(*psr_error)) 104 PSR_ERROR(EINVAL); 105 exit_code = EXIT_SUCCESS; 106 107 out: 108 eloop_exit(ctx->ps_eloop, exit_code); 109 } 110 111 ssize_t 112 ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len) 113 { 114 struct psr_ctx psr_ctx = { 115 .psr_ctx = ctx, 116 .psr_data = data, .psr_datalen = len, 117 }; 118 119 if (eloop_event_add(ctx->ps_eloop, ctx->ps_root->psp_fd, ELE_READ, 120 ps_root_readerrorcb, &psr_ctx) == -1) 121 return -1; 122 123 eloop_enter(ctx->ps_eloop); 124 eloop_start(ctx->ps_eloop, &ctx->sigset); 125 eloop_event_delete(ctx->ps_eloop, ctx->ps_root->psp_fd); 126 127 errno = psr_ctx.psr_error.psr_errno; 128 return psr_ctx.psr_error.psr_result; 129 } 130 131 #ifdef PRIVSEP_GETIFADDRS 132 static void 133 ps_root_mreaderrorcb(void *arg, unsigned short events) 134 { 135 struct psr_ctx *psr_ctx = arg; 136 struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; 137 struct psr_error *psr_error = &psr_ctx->psr_error; 138 struct iovec iov[] = { 139 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) }, 140 { .iov_base = NULL, .iov_len = 0 }, 141 }; 142 ssize_t len; 143 int exit_code = EXIT_FAILURE; 144 145 if (events != ELE_READ) 146 logerrx("%s: unexpected event 0x%04x", __func__, events); 147 148 len = recv(ctx->ps_root->psp_fd, 149 psr_error, sizeof(*psr_error), MSG_PEEK); 150 if (len == -1) 151 PSR_ERROR(errno); 152 else if ((size_t)len < sizeof(*psr_error)) 153 PSR_ERROR(EINVAL); 154 155 if (psr_error->psr_datalen > SSIZE_MAX) 156 PSR_ERROR(ENOBUFS); 157 else if (psr_error->psr_datalen != 0) { 158 psr_ctx->psr_data = malloc(psr_error->psr_datalen); 159 if (psr_ctx->psr_data == NULL) 160 PSR_ERROR(errno); 161 psr_ctx->psr_datalen = psr_error->psr_datalen; 162 iov[1].iov_base = psr_ctx->psr_data; 163 iov[1].iov_len = psr_ctx->psr_datalen; 164 } 165 166 len = readv(ctx->ps_root->psp_fd, iov, __arraycount(iov)); 167 if (len == -1) 168 PSR_ERROR(errno); 169 else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen) 170 PSR_ERROR(EINVAL); 171 exit_code = EXIT_SUCCESS; 172 173 out: 174 eloop_exit(ctx->ps_eloop, exit_code); 175 } 176 177 ssize_t 178 ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len) 179 { 180 struct psr_ctx psr_ctx = { 181 .psr_ctx = ctx, 182 }; 183 184 if (eloop_event_add(ctx->ps_eloop, ctx->ps_root->psp_fd, ELE_READ, 185 ps_root_mreaderrorcb, &psr_ctx) == -1) 186 return -1; 187 188 eloop_enter(ctx->ps_eloop); 189 eloop_start(ctx->ps_eloop, &ctx->sigset); 190 eloop_event_delete(ctx->ps_eloop, ctx->ps_root->psp_fd); 191 192 errno = psr_ctx.psr_error.psr_errno; 193 *data = psr_ctx.psr_data; 194 *len = psr_ctx.psr_datalen; 195 return psr_ctx.psr_error.psr_result; 196 } 197 #endif 198 199 static ssize_t 200 ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result, 201 void *data, size_t len) 202 { 203 struct psr_error psr = { 204 .psr_result = result, 205 .psr_errno = errno, 206 .psr_datalen = len, 207 }; 208 struct iovec iov[] = { 209 { .iov_base = &psr, .iov_len = sizeof(psr) }, 210 { .iov_base = data, .iov_len = len }, 211 }; 212 ssize_t err; 213 214 #ifdef PRIVSEP_DEBUG 215 logdebugx("%s: result %zd errno %d", __func__, result, errno); 216 #endif 217 218 err = writev(ctx->ps_root->psp_fd, iov, __arraycount(iov)); 219 220 /* Error sending the message? Try sending the error of sending. */ 221 if (err == -1) { 222 logerr("%s: result=%zd, data=%p, len=%zu", 223 __func__, result, data, len); 224 psr.psr_result = err; 225 psr.psr_errno = errno; 226 iov[1].iov_base = NULL; 227 iov[1].iov_len = 0; 228 err = writev(ctx->ps_root->psp_fd, iov, __arraycount(iov)); 229 } 230 231 return err; 232 } 233 234 static ssize_t 235 ps_root_doioctl(unsigned long req, void *data, size_t len) 236 { 237 int s, err; 238 239 /* Only allow these ioctls */ 240 switch(req) { 241 #ifdef SIOCAIFADDR 242 case SIOCAIFADDR: /* FALLTHROUGH */ 243 case SIOCDIFADDR: /* FALLTHROUGH */ 244 #endif 245 #ifdef SIOCSIFHWADDR 246 case SIOCSIFHWADDR: /* FALLTHROUGH */ 247 #endif 248 #ifdef SIOCGIFPRIORITY 249 case SIOCGIFPRIORITY: /* FALLTHROUGH */ 250 #endif 251 case SIOCSIFFLAGS: /* FALLTHROUGH */ 252 case SIOCGIFMTU: /* FALLTHROUGH */ 253 case SIOCSIFMTU: 254 break; 255 default: 256 errno = EPERM; 257 return -1; 258 } 259 260 s = socket(PF_INET, SOCK_DGRAM, 0); 261 if (s != -1) 262 #ifdef IOCTL_REQUEST_TYPE 263 { 264 ioctl_request_t reqt; 265 266 memcpy(&reqt, &req, sizeof(reqt)); 267 err = ioctl(s, reqt, data, len); 268 } 269 #else 270 err = ioctl(s, req, data, len); 271 #endif 272 else 273 err = -1; 274 if (s != -1) 275 close(s); 276 return err; 277 } 278 279 static ssize_t 280 ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 281 { 282 const char *envbuf = data; 283 char * const argv[] = { ctx->script, NULL }; 284 pid_t pid; 285 int status; 286 287 if (len == 0) 288 return 0; 289 290 if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL) 291 return -1; 292 293 pid = script_exec(argv, ctx->script_env); 294 if (pid == -1) 295 return -1; 296 297 /* Wait for the script to finish */ 298 while (waitpid(pid, &status, 0) == -1) { 299 if (errno != EINTR) { 300 logerr(__func__); 301 status = 0; 302 break; 303 } 304 } 305 return status; 306 } 307 308 static bool 309 ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path) 310 { 311 312 /* Avoid a previous directory attack to avoid /proc/../ 313 * dhcpcd should never use a path with double dots. */ 314 if (strstr(path, "..") != NULL) 315 return false; 316 317 if (cmd == PS_READFILE) { 318 #ifdef EMBEDDED_CONFIG 319 if (strcmp(ctx->cffile, EMBEDDED_CONFIG) == 0) 320 return true; 321 #endif 322 if (strcmp(ctx->cffile, path) == 0) 323 return true; 324 } 325 if (strncmp(DBDIR, path, strlen(DBDIR)) == 0) 326 return true; 327 if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0) 328 return true; 329 330 #ifdef __linux__ 331 if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 || 332 strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 || 333 strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0) 334 return true; 335 #endif 336 337 errno = EPERM; 338 return false; 339 } 340 341 static ssize_t 342 ps_root_dowritefile(const struct dhcpcd_ctx *ctx, 343 mode_t mode, void *data, size_t len) 344 { 345 char *file = data, *nc; 346 347 nc = memchr(file, '\0', len); 348 if (nc == NULL) { 349 errno = EINVAL; 350 return -1; 351 } 352 353 if (!ps_root_validpath(ctx, PS_WRITEFILE, file)) 354 return -1; 355 nc++; 356 return writefile(file, mode, nc, len - (size_t)(nc - file)); 357 } 358 359 #ifdef AUTH 360 static ssize_t 361 ps_root_monordm(uint64_t *rdm, size_t len) 362 { 363 364 if (len != sizeof(*rdm)) { 365 errno = EINVAL; 366 return -1; 367 } 368 return auth_get_rdm_monotonic(rdm); 369 } 370 #endif 371 372 #ifdef PRIVSEP_GETIFADDRS 373 #define IFA_NADDRS 4 374 static ssize_t 375 ps_root_dogetifaddrs(void **rdata, size_t *rlen) 376 { 377 struct ifaddrs *ifaddrs, *ifa; 378 size_t len; 379 uint8_t *buf, *sap; 380 socklen_t salen; 381 382 if (getifaddrs(&ifaddrs) == -1) 383 return -1; 384 if (ifaddrs == NULL) { 385 *rdata = NULL; 386 *rlen = 0; 387 return 0; 388 } 389 390 /* Work out the buffer length required. 391 * Ensure everything is aligned correctly, which does 392 * create a larger buffer than what is needed to send, 393 * but makes creating the same structure in the client 394 * much easier. */ 395 len = 0; 396 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 397 len += ALIGN(sizeof(*ifa)); 398 len += ALIGN(IFNAMSIZ); 399 len += ALIGN(sizeof(salen) * IFA_NADDRS); 400 if (ifa->ifa_addr != NULL) 401 len += ALIGN(sa_len(ifa->ifa_addr)); 402 if (ifa->ifa_netmask != NULL) 403 len += ALIGN(sa_len(ifa->ifa_netmask)); 404 if (ifa->ifa_broadaddr != NULL) 405 len += ALIGN(sa_len(ifa->ifa_broadaddr)); 406 #ifdef BSD 407 /* 408 * On BSD we need to carry ifa_data so we can access 409 * if_data->ifi_link_state 410 */ 411 if (ifa->ifa_addr != NULL && 412 ifa->ifa_addr->sa_family == AF_LINK) 413 len += ALIGN(sizeof(struct if_data)); 414 #endif 415 } 416 417 /* Use calloc to set everything to zero. 418 * This satisfies memory sanitizers because don't write 419 * where we don't need to. */ 420 buf = calloc(1, len); 421 if (buf == NULL) { 422 freeifaddrs(ifaddrs); 423 return -1; 424 } 425 *rdata = buf; 426 *rlen = len; 427 428 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 429 memcpy(buf, ifa, sizeof(*ifa)); 430 buf += ALIGN(sizeof(*ifa)); 431 432 strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ); 433 buf += ALIGN(IFNAMSIZ); 434 sap = buf; 435 buf += ALIGN(sizeof(salen) * IFA_NADDRS); 436 437 #define COPYINSA(addr) \ 438 do { \ 439 if ((addr) != NULL) \ 440 salen = sa_len((addr)); \ 441 else \ 442 salen = 0; \ 443 if (salen != 0) { \ 444 memcpy(sap, &salen, sizeof(salen)); \ 445 memcpy(buf, (addr), salen); \ 446 buf += ALIGN(salen); \ 447 } \ 448 sap += sizeof(salen); \ 449 } while (0 /*CONSTCOND */) 450 451 COPYINSA(ifa->ifa_addr); 452 COPYINSA(ifa->ifa_netmask); 453 COPYINSA(ifa->ifa_broadaddr); 454 455 #ifdef BSD 456 if (ifa->ifa_addr != NULL && 457 ifa->ifa_addr->sa_family == AF_LINK) 458 { 459 salen = (socklen_t)sizeof(struct if_data); 460 memcpy(buf, ifa->ifa_data, salen); 461 buf += ALIGN(salen); 462 } else 463 #endif 464 salen = 0; 465 memcpy(sap, &salen, sizeof(salen)); 466 } 467 468 freeifaddrs(ifaddrs); 469 return 0; 470 } 471 #endif 472 473 static ssize_t 474 ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 475 { 476 struct dhcpcd_ctx *ctx = arg; 477 uint16_t cmd; 478 struct ps_process *psp; 479 struct iovec *iov = msg->msg_iov; 480 void *data = iov->iov_base, *rdata = NULL; 481 size_t len = iov->iov_len, rlen = 0; 482 uint8_t buf[PS_BUFLEN]; 483 time_t mtime; 484 ssize_t err; 485 bool free_rdata = false; 486 487 cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP)); 488 psp = ps_findprocess(ctx, &psm->ps_id); 489 490 #ifdef PRIVSEP_DEBUG 491 logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp); 492 #endif 493 494 if (psp != NULL) { 495 if (psm->ps_cmd & PS_STOP) { 496 return ps_stopprocess(psp); 497 } else if (psm->ps_cmd & PS_START) { 498 /* Process has already started .... */ 499 logdebugx("%s%sprocess %s already started on pid %d", 500 psp->psp_ifname, 501 psp->psp_ifname[0] != '\0' ? ": " : "", 502 psp->psp_name, psp->psp_pid); 503 return 0; 504 } 505 506 err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg); 507 if (err == -1) { 508 logerr("%s: failed to send message to pid %d", 509 __func__, psp->psp_pid); 510 ps_freeprocess(psp); 511 } 512 return 0; 513 } 514 515 if (psm->ps_cmd & PS_STOP && psp == NULL) 516 return 0; 517 518 switch (cmd) { 519 #ifdef INET 520 #ifdef ARP 521 case PS_BPF_ARP: /* FALLTHROUGH */ 522 #endif 523 case PS_BPF_BOOTP: 524 return ps_bpf_cmd(ctx, psm, msg); 525 #endif 526 #ifdef INET 527 case PS_BOOTP: 528 return ps_inet_cmd(ctx, psm, msg); 529 #endif 530 #ifdef INET6 531 #ifdef DHCP6 532 case PS_DHCP6: /* FALLTHROUGH */ 533 #endif 534 case PS_ND: 535 return ps_inet_cmd(ctx, psm, msg); 536 #endif 537 default: 538 break; 539 } 540 541 assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1); 542 543 /* Reset errno */ 544 errno = 0; 545 546 switch (psm->ps_cmd) { 547 case PS_IOCTL: 548 err = ps_root_doioctl(psm->ps_flags, data, len); 549 if (err != -1) { 550 rdata = data; 551 rlen = len; 552 } 553 break; 554 case PS_SCRIPT: 555 err = ps_root_run_script(ctx, data, len); 556 break; 557 case PS_STOPPROCS: 558 ctx->options |= DHCPCD_EXITING; 559 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 560 if (psp != ctx->ps_root) 561 ps_stopprocess(psp); 562 } 563 err = ps_stopwait(ctx); 564 break; 565 case PS_UNLINK: 566 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 567 err = -1; 568 break; 569 } 570 err = unlink(data); 571 break; 572 case PS_READFILE: 573 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 574 err = -1; 575 break; 576 } 577 err = readfile(data, buf, sizeof(buf)); 578 if (err != -1) { 579 rdata = buf; 580 rlen = (size_t)err; 581 } 582 break; 583 case PS_WRITEFILE: 584 err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags, 585 data, len); 586 break; 587 case PS_FILEMTIME: 588 err = filemtime(data, &mtime); 589 if (err != -1) { 590 rdata = &mtime; 591 rlen = sizeof(mtime); 592 } 593 break; 594 case PS_LOGREOPEN: 595 err = logopen(ctx->logfile); 596 break; 597 #ifdef AUTH 598 case PS_AUTH_MONORDM: 599 err = ps_root_monordm(data, len); 600 if (err != -1) { 601 rdata = data; 602 rlen = len; 603 } 604 break; 605 #endif 606 #ifdef PRIVSEP_GETIFADDRS 607 case PS_GETIFADDRS: 608 err = ps_root_dogetifaddrs(&rdata, &rlen); 609 free_rdata = true; 610 break; 611 #endif 612 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE)) 613 case PS_IP6FORWARDING: 614 err = ip6_forwarding(data); 615 break; 616 #endif 617 #ifdef PLUGIN_DEV 618 case PS_DEV_INITTED: 619 err = dev_initialised(ctx, data); 620 break; 621 case PS_DEV_LISTENING: 622 err = dev_listening(ctx); 623 break; 624 #endif 625 default: 626 err = ps_root_os(ctx, psm, msg, &rdata, &rlen, &free_rdata); 627 break; 628 } 629 630 err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen); 631 if (free_rdata) 632 free(rdata); 633 return err; 634 } 635 636 /* Receive from state engine, do an action. */ 637 static void 638 ps_root_recvmsg(void *arg, unsigned short events) 639 { 640 struct ps_process *psp = arg; 641 642 if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, 643 ps_root_recvmsgcb, psp->psp_ctx) == -1) 644 logerr(__func__); 645 } 646 647 #ifdef PLUGIN_DEV 648 static int 649 ps_root_handleinterface(void *arg, int action, const char *ifname) 650 { 651 struct dhcpcd_ctx *ctx = arg; 652 unsigned long flag; 653 654 if (action == 1) 655 flag = PS_DEV_IFADDED; 656 else if (action == -1) 657 flag = PS_DEV_IFREMOVED; 658 else if (action == 0) 659 flag = PS_DEV_IFUPDATED; 660 else { 661 errno = EINVAL; 662 return -1; 663 } 664 665 return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, 666 flag, ifname, strlen(ifname) + 1); 667 } 668 #endif 669 670 static int 671 ps_root_startcb(struct ps_process *psp) 672 { 673 struct dhcpcd_ctx *ctx = psp->psp_ctx; 674 675 if (ctx->options & DHCPCD_MANAGER) 676 setproctitle("[privileged proxy]"); 677 else 678 setproctitle("[privileged proxy] %s%s%s", 679 ctx->ifv[0], 680 ctx->options & DHCPCD_IPV4 ? " [ip4]" : "", 681 ctx->options & DHCPCD_IPV6 ? " [ip6]" : ""); 682 ctx->options |= DHCPCD_PRIVSEPROOT; 683 684 if (if_opensockets(ctx) == -1) 685 logerr("%s: if_opensockets", __func__); 686 #ifdef BSD 687 else { 688 /* We only want to write to this socket, so set 689 * a small as possible buffer size. */ 690 socklen_t smallbuf = 1; 691 692 if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF, 693 &smallbuf, (socklen_t)sizeof(smallbuf)) == -1) 694 logerr("%s: setsockopt(SO_RCVBUF)", __func__); 695 } 696 #endif 697 698 /* Open network sockets for sending. 699 * This is a small bit wasteful for non sandboxed OS's 700 * but makes life very easy for unicasting DHCPv6 in non manager 701 * mode as we no longer care about address selection. 702 * We can't call shutdown SHUT_RD on the socket because it's 703 * not connected. All we can do is try and set a zero sized 704 * receive buffer and just let it overflow. 705 * Reading from it just to drain it is a waste of CPU time. */ 706 #ifdef INET 707 if (ctx->options & DHCPCD_IPV4) { 708 int buflen = 1; 709 710 ctx->udp_wfd = xsocket(PF_INET, 711 SOCK_RAW | SOCK_CXNB, IPPROTO_UDP); 712 if (ctx->udp_wfd == -1) 713 logerr("%s: dhcp_openraw", __func__); 714 else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF, 715 &buflen, sizeof(buflen)) == -1) 716 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__); 717 } 718 #endif 719 #ifdef INET6 720 if (ctx->options & DHCPCD_IPV6) { 721 int buflen = 1; 722 723 ctx->nd_fd = ipv6nd_open(false); 724 if (ctx->nd_fd == -1) 725 logerr("%s: ipv6nd_open", __func__); 726 else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF, 727 &buflen, sizeof(buflen)) == -1) 728 logerr("%s: setsockopt SO_RCVBUF ND", __func__); 729 } 730 #endif 731 #ifdef DHCP6 732 if (ctx->options & DHCPCD_IPV6) { 733 int buflen = 1; 734 735 ctx->dhcp6_wfd = dhcp6_openraw(); 736 if (ctx->dhcp6_wfd == -1) 737 logerr("%s: dhcp6_openraw", __func__); 738 else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF, 739 &buflen, sizeof(buflen)) == -1) 740 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__); 741 } 742 #endif 743 744 #ifdef PLUGIN_DEV 745 /* Start any dev listening plugin which may want to 746 * change the interface name provided by the kernel */ 747 if ((ctx->options & (DHCPCD_MANAGER | DHCPCD_DEV)) == 748 (DHCPCD_MANAGER | DHCPCD_DEV)) 749 dev_start(ctx, ps_root_handleinterface); 750 #endif 751 752 return 0; 753 } 754 755 void 756 ps_root_signalcb(int sig, void *arg) 757 { 758 struct dhcpcd_ctx *ctx = arg; 759 int status; 760 pid_t pid; 761 const char *ifname, *name; 762 struct ps_process *psp; 763 764 if (sig != SIGCHLD) 765 return; 766 767 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 768 psp = ps_findprocesspid(ctx, pid); 769 if (psp != NULL) { 770 ifname = psp->psp_ifname; 771 name = psp->psp_name; 772 } else { 773 /* Ignore logging the double fork */ 774 if (ctx->options & DHCPCD_LAUNCHER) 775 continue; 776 ifname = ""; 777 name = "unknown process"; 778 } 779 780 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 781 logerrx("%s%s%s exited unexpectedly from PID %d," 782 " code=%d", 783 ifname, ifname[0] != '\0' ? ": " : "", 784 name, pid, WEXITSTATUS(status)); 785 else if (WIFSIGNALED(status)) 786 logerrx("%s%s%s exited unexpectedly from PID %d," 787 " signal=%s", 788 ifname, ifname[0] != '\0' ? ": " : "", 789 name, pid, strsignal(WTERMSIG(status))); 790 else 791 logdebugx("%s%s%s exited from PID %d", 792 ifname, ifname[0] != '\0' ? ": " : "", 793 name, pid); 794 795 if (psp != NULL) 796 ps_freeprocess(psp); 797 } 798 799 if (!(ctx->options & DHCPCD_EXITING)) 800 return; 801 if (!(ps_waitforprocs(ctx))) 802 eloop_exit(ctx->ps_eloop, EXIT_SUCCESS); 803 } 804 805 int (*handle_interface)(void *, int, const char *); 806 807 #ifdef PLUGIN_DEV 808 static ssize_t 809 ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 810 { 811 int action; 812 struct iovec *iov = msg->msg_iov; 813 814 if (msg->msg_iovlen != 1) { 815 errno = EINVAL; 816 return -1; 817 } 818 819 switch(psm->ps_flags) { 820 case PS_DEV_IFADDED: 821 action = 1; 822 break; 823 case PS_DEV_IFREMOVED: 824 action = -1; 825 break; 826 case PS_DEV_IFUPDATED: 827 action = 0; 828 break; 829 default: 830 errno = EINVAL; 831 return -1; 832 } 833 834 return dhcpcd_handleinterface(ctx, action, iov->iov_base); 835 } 836 #endif 837 838 static ssize_t 839 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 840 { 841 struct dhcpcd_ctx *ctx = arg; 842 ssize_t err; 843 844 switch(psm->ps_cmd) { 845 #ifdef PLUGIN_DEV 846 case PS_DEV_IFCMD: 847 err = ps_root_devcb(ctx, psm, msg); 848 break; 849 #endif 850 default: 851 #ifdef INET 852 err = ps_bpf_dispatch(ctx, psm, msg); 853 if (err == -1 && errno == ENOTSUP) 854 #endif 855 err = ps_inet_dispatch(ctx, psm, msg); 856 } 857 return err; 858 } 859 860 static void 861 ps_root_dispatch(void *arg, unsigned short events) 862 { 863 struct dhcpcd_ctx *ctx = arg; 864 865 if (ps_recvpsmsg(ctx, ctx->ps_data_fd, events, 866 ps_root_dispatchcb, ctx) == -1) 867 logerr(__func__); 868 } 869 870 static void 871 ps_root_log(void *arg, unsigned short events) 872 { 873 struct dhcpcd_ctx *ctx = arg; 874 875 if (events != ELE_READ) 876 logerrx("%s: unexpected event 0x%04x", __func__, events); 877 878 if (logreadfd(ctx->ps_log_root_fd) == -1) 879 logerr(__func__); 880 } 881 882 pid_t 883 ps_root_start(struct dhcpcd_ctx *ctx) 884 { 885 struct ps_id id = { 886 .psi_ifindex = 0, 887 .psi_cmd = PS_ROOT, 888 }; 889 struct ps_process *psp; 890 int logfd[2], datafd[2]; 891 pid_t pid; 892 893 if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, logfd) == -1) 894 return -1; 895 #ifdef PRIVSEP_RIGHTS 896 if (ps_rights_limit_fdpair(logfd) == -1) 897 return -1; 898 #endif 899 900 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1) 901 return -1; 902 if (ps_setbuf_fdpair(datafd) == -1) 903 return -1; 904 #ifdef PRIVSEP_RIGHTS 905 if (ps_rights_limit_fdpair(datafd) == -1) 906 return -1; 907 #endif 908 909 psp = ctx->ps_root = ps_newprocess(ctx, &id); 910 strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name)); 911 pid = ps_startprocess(psp, ps_root_recvmsg, NULL, 912 ps_root_startcb, ps_root_signalcb, PSF_ELOOP); 913 914 if (pid == 0) { 915 ctx->ps_log_fd = logfd[0]; /* Keep open to pass to processes */ 916 ctx->ps_log_root_fd = logfd[1]; 917 if (eloop_event_add(ctx->eloop, ctx->ps_log_root_fd, ELE_READ, 918 ps_root_log, ctx) == -1) 919 return -1; 920 ctx->ps_data_fd = datafd[1]; 921 close(datafd[0]); 922 return 0; 923 } else if (pid == -1) 924 return -1; 925 926 logsetfd(logfd[0]); 927 close(logfd[1]); 928 929 ctx->ps_data_fd = datafd[0]; 930 close(datafd[1]); 931 if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, ELE_READ, 932 ps_root_dispatch, ctx) == -1) 933 return 1; 934 935 return pid; 936 } 937 938 int 939 ps_root_stop(struct dhcpcd_ctx *ctx) 940 { 941 struct ps_process *psp = ctx->ps_root; 942 943 if (!(ctx->options & DHCPCD_PRIVSEP) || 944 ctx->eloop == NULL) 945 return 0; 946 947 /* If we are the root process then remove the pidfile */ 948 if (ctx->options & DHCPCD_PRIVSEPROOT && 949 !(ctx->options & DHCPCD_TEST)) 950 { 951 if (unlink(ctx->pidfile) == -1) 952 logerr("%s: unlink: %s", __func__, ctx->pidfile); 953 } 954 955 /* Only the manager process gets past this point. */ 956 if (ctx->options & DHCPCD_FORKED) 957 return 0; 958 959 /* We cannot log the root process exited before we 960 * log dhcpcd exits because the latter requires the former. 961 * So we just log the intent to exit. 962 * Even sending this will be a race to exit. */ 963 logdebugx("%s%s%s will exit from PID %d", 964 psp->psp_ifname, 965 psp->psp_ifname[0] != '\0' ? ": " : "", 966 psp->psp_name, psp->psp_pid); 967 968 if (ps_stopprocess(psp) == -1) 969 return -1; 970 971 return ps_stopwait(ctx); 972 } 973 974 ssize_t 975 ps_root_stopprocesses(struct dhcpcd_ctx *ctx) 976 { 977 978 if (!(IN_PRIVSEP_SE(ctx))) 979 return 0; 980 981 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_STOPPROCS, 0, 982 NULL, 0) == -1) 983 return -1; 984 return ps_root_readerror(ctx, NULL, 0); 985 } 986 987 ssize_t 988 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 989 { 990 991 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_SCRIPT, 992 0, data, len) == -1) 993 return -1; 994 return ps_root_readerror(ctx, NULL, 0); 995 } 996 997 ssize_t 998 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, 999 size_t len) 1000 { 1001 int fd = ctx->ps_root->psp_fd; 1002 #ifdef IOCTL_REQUEST_TYPE 1003 unsigned long ulreq = 0; 1004 1005 memcpy(&ulreq, &req, sizeof(req)); 1006 if (ps_sendcmd(ctx, fd, PS_IOCTL, ulreq, data, len) == -1) 1007 return -1; 1008 #else 1009 if (ps_sendcmd(ctx, fd, PS_IOCTL, req, data, len) == -1) 1010 return -1; 1011 #endif 1012 return ps_root_readerror(ctx, data, len); 1013 } 1014 1015 ssize_t 1016 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file) 1017 { 1018 1019 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_UNLINK, 0, 1020 file, strlen(file) + 1) == -1) 1021 return -1; 1022 return ps_root_readerror(ctx, NULL, 0); 1023 } 1024 1025 ssize_t 1026 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, 1027 void *data, size_t len) 1028 { 1029 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_READFILE, 0, 1030 file, strlen(file) + 1) == -1) 1031 return -1; 1032 return ps_root_readerror(ctx, data, len); 1033 } 1034 1035 ssize_t 1036 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 1037 const void *data, size_t len) 1038 { 1039 char buf[PS_BUFLEN]; 1040 size_t flen; 1041 1042 flen = strlcpy(buf, file, sizeof(buf)); 1043 flen += 1; 1044 if (flen > sizeof(buf) || flen + len > sizeof(buf)) { 1045 errno = ENOBUFS; 1046 return -1; 1047 } 1048 memcpy(buf + flen, data, len); 1049 1050 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_WRITEFILE, mode, 1051 buf, flen + len) == -1) 1052 return -1; 1053 return ps_root_readerror(ctx, NULL, 0); 1054 } 1055 1056 ssize_t 1057 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 1058 { 1059 1060 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_FILEMTIME, 0, 1061 file, strlen(file) + 1) == -1) 1062 return -1; 1063 return ps_root_readerror(ctx, time, sizeof(*time)); 1064 } 1065 1066 ssize_t 1067 ps_root_logreopen(struct dhcpcd_ctx *ctx) 1068 { 1069 1070 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_LOGREOPEN, 0, 1071 NULL, 0) == -1) 1072 return -1; 1073 return ps_root_readerror(ctx, NULL, 0); 1074 } 1075 1076 #ifdef PRIVSEP_GETIFADDRS 1077 int 1078 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead) 1079 { 1080 struct ifaddrs *ifa; 1081 void *buf = NULL; 1082 char *bp, *sap; 1083 socklen_t salen; 1084 size_t len; 1085 ssize_t err; 1086 1087 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, 1088 PS_GETIFADDRS, 0, NULL, 0) == -1) 1089 return -1; 1090 err = ps_root_mreaderror(ctx, &buf, &len); 1091 1092 if (err == -1) 1093 return -1; 1094 1095 /* Should be impossible - lo0 will always exist. */ 1096 if (len == 0) { 1097 *ifahead = NULL; 1098 return 0; 1099 } 1100 1101 bp = buf; 1102 *ifahead = (struct ifaddrs *)(void *)bp; 1103 for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) { 1104 if (len < ALIGN(sizeof(*ifa)) + 1105 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS)) 1106 goto err; 1107 bp += ALIGN(sizeof(*ifa)); 1108 ifa->ifa_name = bp; 1109 bp += ALIGN(IFNAMSIZ); 1110 sap = bp; 1111 bp += ALIGN(sizeof(salen) * IFA_NADDRS); 1112 len -= ALIGN(sizeof(*ifa)) + 1113 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS); 1114 1115 #define COPYOUTSA(addr) \ 1116 do { \ 1117 memcpy(&salen, sap, sizeof(salen)); \ 1118 if (len < salen) \ 1119 goto err; \ 1120 if (salen != 0) { \ 1121 (addr) = (struct sockaddr *)(void *)bp; \ 1122 bp += ALIGN(salen); \ 1123 len -= ALIGN(salen); \ 1124 } \ 1125 sap += sizeof(salen); \ 1126 } while (0 /* CONSTCOND */) 1127 1128 COPYOUTSA(ifa->ifa_addr); 1129 COPYOUTSA(ifa->ifa_netmask); 1130 COPYOUTSA(ifa->ifa_broadaddr); 1131 1132 memcpy(&salen, sap, sizeof(salen)); 1133 if (len < salen) 1134 goto err; 1135 if (salen != 0) { 1136 ifa->ifa_data = bp; 1137 bp += ALIGN(salen); 1138 len -= ALIGN(salen); 1139 } else 1140 ifa->ifa_data = NULL; 1141 1142 if (len != 0) 1143 ifa->ifa_next = (struct ifaddrs *)(void *)bp; 1144 else 1145 ifa->ifa_next = NULL; 1146 } 1147 return 0; 1148 1149 err: 1150 free(buf); 1151 *ifahead = NULL; 1152 errno = EINVAL; 1153 return -1; 1154 } 1155 #endif 1156 1157 #if defined(__linux__) || defined(HAVE_PLEDGE) 1158 ssize_t 1159 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname) 1160 { 1161 1162 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_IP6FORWARDING, 0, 1163 ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1) 1164 return -1; 1165 return ps_root_readerror(ctx, NULL, 0); 1166 } 1167 #endif 1168 1169 #ifdef AUTH 1170 int 1171 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm) 1172 { 1173 1174 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_AUTH_MONORDM, 0, 1175 rdm, sizeof(*rdm))== -1) 1176 return -1; 1177 return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm)); 1178 } 1179 #endif 1180 1181 #ifdef PLUGIN_DEV 1182 int 1183 ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname) 1184 { 1185 1186 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_DEV_INITTED, 0, 1187 ifname, strlen(ifname) + 1)== -1) 1188 return -1; 1189 return (int)ps_root_readerror(ctx, NULL, 0); 1190 } 1191 1192 int 1193 ps_root_dev_listening(struct dhcpcd_ctx * ctx) 1194 { 1195 1196 if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_DEV_LISTENING, 1197 0, NULL, 0) == -1) 1198 return -1; 1199 return (int)ps_root_readerror(ctx, NULL, 0); 1200 } 1201 #endif 1202