1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Privilege Separation for dhcpcd 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 /* 30 * The current design is this: 31 * Spawn a priv process to carry out privileged actions and 32 * spawning unpriv process to initate network connections such as BPF 33 * or address specific listener. 34 * Spawn an unpriv process to send/receive common network data. 35 * Then drop all privs and start running. 36 * Every process aside from the privileged proxy is chrooted. 37 * All privsep processes ignore signals - only the manager process accepts them. 38 * 39 * dhcpcd will maintain the config file in the chroot, no need to handle 40 * this in a script or something. 41 */ 42 43 #include <sys/resource.h> 44 #include <sys/socket.h> 45 #include <sys/stat.h> 46 #include <sys/types.h> 47 #include <sys/wait.h> 48 49 #ifdef AF_LINK 50 #include <net/if_dl.h> 51 #endif 52 53 #include <assert.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <grp.h> 57 #include <paths.h> 58 #include <pwd.h> 59 #include <stddef.h> /* For offsetof, struct padding debug */ 60 #include <signal.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 65 #include "arp.h" 66 #include "common.h" 67 #include "control.h" 68 #include "dev.h" 69 #include "dhcp.h" 70 #include "dhcp6.h" 71 #include "eloop.h" 72 #include "ipv6nd.h" 73 #include "logerr.h" 74 #include "privsep.h" 75 76 #ifdef HAVE_CAPSICUM 77 #include <sys/capsicum.h> 78 #include <sys/procdesc.h> 79 #include <capsicum_helpers.h> 80 #endif 81 #ifdef HAVE_UTIL_H 82 #include <util.h> 83 #endif 84 85 /* CMSG_ALIGN is a Linux extension */ 86 #ifndef CMSG_ALIGN 87 #define CMSG_ALIGN(n) (CMSG_SPACE((n)) - CMSG_SPACE(0)) 88 #endif 89 90 /* Calculate number of padding bytes to achieve 'struct cmsghdr' alignment */ 91 #define CALC_CMSG_PADLEN(has_cmsg, pos) \ 92 ((has_cmsg) ? (socklen_t)(CMSG_ALIGN((pos)) - (pos)) : 0) 93 94 int 95 ps_init(struct dhcpcd_ctx *ctx) 96 { 97 struct passwd *pw; 98 struct stat st; 99 100 errno = 0; 101 if ((ctx->ps_user = pw = getpwnam(PRIVSEP_USER)) == NULL) { 102 ctx->options &= ~DHCPCD_PRIVSEP; 103 if (errno == 0) { 104 logerrx("no such user %s", PRIVSEP_USER); 105 /* Just incase logerrx caused an error... */ 106 errno = 0; 107 } else 108 logerr("getpwnam"); 109 return -1; 110 } 111 112 if (stat(pw->pw_dir, &st) == -1 || !S_ISDIR(st.st_mode)) { 113 ctx->options &= ~DHCPCD_PRIVSEP; 114 logerrx("refusing chroot: %s: %s", 115 PRIVSEP_USER, pw->pw_dir); 116 errno = 0; 117 return -1; 118 } 119 120 ctx->options |= DHCPCD_PRIVSEP; 121 return 0; 122 } 123 124 static int 125 ps_dropprivs(struct dhcpcd_ctx *ctx) 126 { 127 struct passwd *pw = ctx->ps_user; 128 129 if (ctx->options & DHCPCD_LAUNCHER) 130 logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir); 131 if (chroot(pw->pw_dir) == -1 && 132 (errno != EPERM || ctx->options & DHCPCD_FORKED)) 133 logerr("%s: chroot: %s", __func__, pw->pw_dir); 134 if (chdir("/") == -1) 135 logerr("%s: chdir: /", __func__); 136 137 if ((setgroups(1, &pw->pw_gid) == -1 || 138 setgid(pw->pw_gid) == -1 || 139 setuid(pw->pw_uid) == -1) && 140 (errno != EPERM || ctx->options & DHCPCD_FORKED)) 141 { 142 logerr("failed to drop privileges"); 143 return -1; 144 } 145 146 struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 }; 147 148 /* Prohibit new files, sockets, etc */ 149 /* 150 * If poll(2) is called with nfds>RLIMIT_NOFILE then it returns EINVAL. 151 * We don't know the final value of nfds at this point *easily*. 152 * Sadly, this is a POSIX limitation and most platforms adhere to it. 153 * However, some are not that strict and are whitelisted below. 154 * Also, if we're not using poll then we can be restrictive. 155 * 156 * For the non whitelisted platforms there should be a sandbox to 157 * fallback to where we don't allow new files, etc: 158 * Linux:seccomp, FreeBSD:capsicum, OpenBSD:pledge 159 * Solaris users are sadly out of luck on both counts. 160 */ 161 #if defined(__NetBSD__) || defined(__DragonFly__) || \ 162 defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) 163 /* The control proxy *does* need to create new fd's via accept(2). */ 164 if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) { 165 if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) 166 logerr("setrlimit RLIMIT_NOFILE"); 167 } 168 #endif 169 170 #define DHC_NOCHKIO (DHCPCD_STARTED | DHCPCD_DAEMONISE) 171 /* Prohibit writing to files. 172 * Obviously this won't work if we are using a logfile 173 * or redirecting stderr to a file. */ 174 if ((ctx->options & DHC_NOCHKIO) == DHC_NOCHKIO || 175 (ctx->logfile == NULL && isatty(STDERR_FILENO) == 1)) 176 { 177 if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) 178 logerr("setrlimit RLIMIT_FSIZE"); 179 } 180 181 #ifdef RLIMIT_NPROC 182 /* Prohibit forks */ 183 if (setrlimit(RLIMIT_NPROC, &rzero) == -1) 184 logerr("setrlimit RLIMIT_NPROC"); 185 #endif 186 187 return 0; 188 } 189 190 static int 191 ps_setbuf0(int fd, int ctl, int minlen) 192 { 193 int len; 194 socklen_t slen; 195 196 slen = sizeof(len); 197 if (getsockopt(fd, SOL_SOCKET, ctl, &len, &slen) == -1) 198 return -1; 199 200 #ifdef __linux__ 201 len /= 2; 202 #endif 203 if (len >= minlen) 204 return 0; 205 206 return setsockopt(fd, SOL_SOCKET, ctl, &minlen, sizeof(minlen)); 207 } 208 209 static int 210 ps_setbuf(int fd) 211 { 212 /* Ensure we can receive a fully sized privsep message. 213 * Double the send buffer. */ 214 int minlen = (int)sizeof(struct ps_msg); 215 216 if (ps_setbuf0(fd, SO_RCVBUF, minlen) == -1 || 217 ps_setbuf0(fd, SO_SNDBUF, minlen * 2) == -1) 218 { 219 logerr(__func__); 220 return -1; 221 } 222 return 0; 223 } 224 225 int 226 ps_setbuf_fdpair(int fd[]) 227 { 228 229 if (ps_setbuf(fd[0]) == -1 || ps_setbuf(fd[1]) == -1) 230 return -1; 231 return 0; 232 } 233 234 #ifdef PRIVSEP_RIGHTS 235 int 236 ps_rights_limit_ioctl(int fd) 237 { 238 cap_rights_t rights; 239 240 cap_rights_init(&rights, CAP_IOCTL); 241 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) 242 return -1; 243 return 0; 244 } 245 246 int 247 ps_rights_limit_fd_fctnl(int fd) 248 { 249 cap_rights_t rights; 250 251 cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, 252 CAP_ACCEPT, CAP_FCNTL); 253 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) 254 return -1; 255 return 0; 256 } 257 258 int 259 ps_rights_limit_fd(int fd) 260 { 261 cap_rights_t rights; 262 263 cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN); 264 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) 265 return -1; 266 return 0; 267 } 268 269 int 270 ps_rights_limit_fd_sockopt(int fd) 271 { 272 cap_rights_t rights; 273 274 cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, 275 CAP_GETSOCKOPT, CAP_SETSOCKOPT); 276 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) 277 return -1; 278 return 0; 279 } 280 281 int 282 ps_rights_limit_fd_rdonly(int fd) 283 { 284 cap_rights_t rights; 285 286 cap_rights_init(&rights, CAP_READ, CAP_EVENT); 287 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) 288 return -1; 289 return 0; 290 } 291 292 int 293 ps_rights_limit_fdpair(int fd[]) 294 { 295 296 if (ps_rights_limit_fd(fd[0]) == -1 || ps_rights_limit_fd(fd[1]) == -1) 297 return -1; 298 return 0; 299 } 300 301 static int 302 ps_rights_limit_stdio() 303 { 304 const int iebadf = CAPH_IGNORE_EBADF; 305 int error = 0; 306 307 if (caph_limit_stream(STDIN_FILENO, CAPH_READ | iebadf) == -1) 308 error = -1; 309 if (caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | iebadf) == -1) 310 error = -1; 311 if (caph_limit_stream(STDERR_FILENO, CAPH_WRITE | iebadf) == -1) 312 error = -1; 313 314 return error; 315 } 316 #endif 317 318 #ifdef HAVE_CAPSICUM 319 static void 320 ps_processhangup(void *arg, unsigned short events) 321 { 322 struct ps_process *psp = arg; 323 struct dhcpcd_ctx *ctx = psp->psp_ctx; 324 325 if (!(events & ELE_HANGUP)) 326 logerrx("%s: unexpected event 0x%04x", __func__, events); 327 328 logdebugx("%s%s%s exited from PID %d", 329 psp->psp_ifname, psp->psp_ifname[0] != '\0' ? ": " : "", 330 psp->psp_name, psp->psp_pid); 331 332 ps_freeprocess(psp); 333 334 if (!(ctx->options & DHCPCD_EXITING)) 335 return; 336 if (!(ps_waitforprocs(ctx))) 337 eloop_exit(ctx->ps_eloop, EXIT_SUCCESS); 338 } 339 #endif 340 341 pid_t 342 ps_startprocess(struct ps_process *psp, 343 void (*recv_msg)(void *, unsigned short), 344 void (*recv_unpriv_msg)(void *, unsigned short), 345 int (*callback)(struct ps_process *), void (*signal_cb)(int, void *), 346 unsigned int flags) 347 { 348 struct dhcpcd_ctx *ctx = psp->psp_ctx; 349 int fd[2]; 350 pid_t pid; 351 352 if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, fd) == -1) { 353 logerr("%s: socketpair", __func__); 354 return -1; 355 } 356 if (ps_setbuf_fdpair(fd) == -1) { 357 logerr("%s: ps_setbuf_fdpair", __func__); 358 return -1; 359 } 360 #ifdef PRIVSEP_RIGHTS 361 if (ps_rights_limit_fdpair(fd) == -1) { 362 logerr("%s: ps_rights_limit_fdpair", __func__); 363 return -1; 364 } 365 #endif 366 367 #ifdef HAVE_CAPSICUM 368 pid = pdfork(&psp->psp_pfd, PD_CLOEXEC); 369 #else 370 pid = fork(); 371 #endif 372 switch (pid) { 373 case -1: 374 #ifdef HAVE_CAPSICUM 375 logerr("pdfork"); 376 #else 377 logerr("fork"); 378 #endif 379 return -1; 380 case 0: 381 psp->psp_pid = getpid(); 382 psp->psp_fd = fd[1]; 383 close(fd[0]); 384 break; 385 default: 386 psp->psp_pid = pid; 387 psp->psp_fd = fd[0]; 388 close(fd[1]); 389 if (recv_unpriv_msg == NULL) 390 ; 391 else if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ, 392 recv_unpriv_msg, psp) == -1) 393 { 394 logerr("%s: eloop_event_add fd %d", 395 __func__, psp->psp_fd); 396 return -1; 397 } 398 #ifdef HAVE_CAPSICUM 399 if (eloop_event_add(ctx->eloop, psp->psp_pfd, ELE_HANGUP, 400 ps_processhangup, psp) == -1) 401 { 402 logerr("%s: eloop_event_add pfd %d", 403 __func__, psp->psp_pfd); 404 return -1; 405 } 406 #endif 407 psp->psp_started = true; 408 return pid; 409 } 410 411 /* If we are not the root process, close un-needed stuff. */ 412 if (ctx->ps_root != psp) { 413 ps_root_close(ctx); 414 #ifdef PLUGIN_DEV 415 dev_stop(ctx); 416 #endif 417 } 418 419 ctx->options |= DHCPCD_FORKED; 420 if (ctx->ps_log_fd != -1) 421 logsetfd(ctx->ps_log_fd); 422 423 #ifdef DEBUG_FD 424 logerrx("pid %d log_fd=%d data_fd=%d psp_fd=%d", 425 getpid(), ctx->ps_log_fd, ctx->ps_data_fd, psp->psp_fd); 426 #endif 427 428 eloop_clear(ctx->eloop, -1); 429 eloop_forked(ctx->eloop); 430 eloop_signal_set_cb(ctx->eloop, 431 dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx); 432 /* ctx->sigset aready has the initial sigmask set in main() */ 433 if (eloop_signal_mask(ctx->eloop, NULL) == -1) { 434 logerr("%s: eloop_signal_mask", __func__); 435 goto errexit; 436 } 437 438 if (ctx->fork_fd != -1) { 439 /* Already removed from eloop thanks to above clear. */ 440 close(ctx->fork_fd); 441 ctx->fork_fd = -1; 442 } 443 444 /* This process has no need of the blocking inner eloop. */ 445 if (!(flags & PSF_ELOOP)) { 446 eloop_free(ctx->ps_eloop); 447 ctx->ps_eloop = NULL; 448 } else 449 eloop_forked(ctx->ps_eloop); 450 451 pidfile_clean(); 452 ps_freeprocesses(ctx, psp); 453 454 if (ctx->ps_root != psp) { 455 ctx->options &= ~DHCPCD_PRIVSEPROOT; 456 ctx->ps_root = NULL; 457 if (ctx->ps_log_root_fd != -1) { 458 /* Already removed from eloop thanks to above clear. */ 459 close(ctx->ps_log_root_fd); 460 ctx->ps_log_root_fd = -1; 461 } 462 #ifdef PRIVSEP_RIGHTS 463 if (ps_rights_limit_stdio() == -1) { 464 logerr("ps_rights_limit_stdio"); 465 goto errexit; 466 } 467 #endif 468 } 469 470 if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ, 471 recv_msg, psp) == -1) 472 { 473 logerr("%d %s: eloop_event_add XX fd %d", getpid(), __func__, psp->psp_fd); 474 goto errexit; 475 } 476 477 if (callback(psp) == -1) 478 goto errexit; 479 480 if (flags & PSF_DROPPRIVS) 481 ps_dropprivs(ctx); 482 483 psp->psp_started = true; 484 return 0; 485 486 errexit: 487 if (psp->psp_fd != -1) { 488 close(psp->psp_fd); 489 psp->psp_fd = -1; 490 } 491 eloop_exit(ctx->eloop, EXIT_FAILURE); 492 return -1; 493 } 494 495 void 496 ps_process_timeout(void *arg) 497 { 498 struct dhcpcd_ctx *ctx = arg; 499 500 logerrx("%s: timed out", __func__); 501 eloop_exit(ctx->eloop, EXIT_FAILURE); 502 } 503 504 int 505 ps_stopprocess(struct ps_process *psp) 506 { 507 int err = 0; 508 509 if (psp == NULL) 510 return 0; 511 512 psp->psp_started = false; 513 514 #ifdef PRIVSEP_DEBUG 515 logdebugx("%s: me=%d pid=%d fd=%d %s", __func__, 516 getpid(), psp->psp_pid, psp->psp_fd, psp->psp_name); 517 #endif 518 519 if (psp->psp_fd != -1) { 520 eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); 521 #if 0 522 if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_STOP, 0, 523 NULL, 0) == -1) 524 { 525 logerr("%d %d %s %s", getpid(), psp->psp_pid, psp->psp_name, __func__); 526 err = -1; 527 } 528 shutdown(psp->psp_fd, SHUT_WR); 529 #else 530 if (shutdown(psp->psp_fd, SHUT_WR) == -1) { 531 logerr(__func__); 532 err = -1; 533 } 534 #endif 535 } 536 537 /* Don't wait for the process as it may not respond to the shutdown 538 * request. We'll reap the process on receipt of SIGCHLD where we 539 * also close the fd. */ 540 return err; 541 } 542 543 int 544 ps_start(struct dhcpcd_ctx *ctx) 545 { 546 pid_t pid; 547 548 TAILQ_INIT(&ctx->ps_processes); 549 550 /* We need an inner eloop to block with. */ 551 if ((ctx->ps_eloop = eloop_new()) == NULL) 552 return -1; 553 eloop_signal_set_cb(ctx->ps_eloop, 554 dhcpcd_signals, dhcpcd_signals_len, 555 dhcpcd_signal_cb, ctx); 556 557 switch (pid = ps_root_start(ctx)) { 558 case -1: 559 logerr("ps_root_start"); 560 return -1; 561 case 0: 562 return 0; 563 default: 564 logdebugx("spawned privileged proxy on PID %d", pid); 565 } 566 567 /* No point in spawning the generic network listener if we're 568 * not going to use it. */ 569 if (!ps_inet_canstart(ctx)) 570 goto started_net; 571 572 switch (pid = ps_inet_start(ctx)) { 573 case -1: 574 return -1; 575 case 0: 576 return 0; 577 default: 578 logdebugx("spawned network proxy on PID %d", pid); 579 } 580 581 started_net: 582 if (!(ctx->options & DHCPCD_TEST)) { 583 switch (pid = ps_ctl_start(ctx)) { 584 case -1: 585 return -1; 586 case 0: 587 return 0; 588 default: 589 logdebugx("spawned controller proxy on PID %d", pid); 590 } 591 } 592 593 #ifdef ARC4RANDOM_H 594 /* Seed the random number generator early incase it needs /dev/urandom 595 * which won't be available in the chroot. */ 596 arc4random(); 597 #endif 598 599 return 1; 600 } 601 602 int 603 ps_entersandbox(const char *_pledge, const char **sandbox) 604 { 605 606 #if !defined(HAVE_PLEDGE) 607 UNUSED(_pledge); 608 #endif 609 610 #if defined(HAVE_CAPSICUM) 611 if (sandbox != NULL) 612 *sandbox = "capsicum"; 613 return cap_enter(); 614 #elif defined(HAVE_PLEDGE) 615 if (sandbox != NULL) 616 *sandbox = "pledge"; 617 // There is no need to use unveil(2) because we are in an empty chroot 618 // This is encouraged by Theo de Raadt himself: 619 // https://www.mail-archive.com/misc@openbsd.org/msg171655.html 620 return pledge(_pledge, NULL); 621 #elif defined(HAVE_SECCOMP) 622 if (sandbox != NULL) 623 *sandbox = "seccomp"; 624 return ps_seccomp_enter(); 625 #else 626 if (sandbox != NULL) 627 *sandbox = "posix resource limited"; 628 return 0; 629 #endif 630 } 631 632 int 633 ps_managersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) 634 { 635 const char *sandbox = NULL; 636 bool forked; 637 int dropped; 638 639 forked = ctx->options & DHCPCD_FORKED; 640 ctx->options &= ~DHCPCD_FORKED; 641 dropped = ps_dropprivs(ctx); 642 if (forked) 643 ctx->options |= DHCPCD_FORKED; 644 645 /* 646 * If we don't have a root process, we cannot use syslog. 647 * If it cannot be opened before chrooting then syslog(3) will fail. 648 * openlog(3) does not return an error which doubly sucks. 649 */ 650 if (ctx->ps_root == NULL) { 651 unsigned int logopts = loggetopts(); 652 653 logopts &= ~LOGERR_LOG; 654 logsetopts(logopts); 655 } 656 657 if (dropped == -1) { 658 logerr("%s: ps_dropprivs", __func__); 659 return -1; 660 } 661 662 #ifdef PRIVSEP_RIGHTS 663 if ((ctx->pf_inet_fd != -1 && 664 ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) || 665 ps_rights_limit_stdio() == -1) 666 { 667 logerr("%s: cap_rights_limit", __func__); 668 return -1; 669 } 670 #endif 671 672 if (_pledge == NULL) 673 _pledge = "stdio"; 674 if (ps_entersandbox(_pledge, &sandbox) == -1) { 675 if (errno == ENOSYS) { 676 if (sandbox != NULL) 677 logwarnx("sandbox unavailable: %s", sandbox); 678 return 0; 679 } 680 logerr("%s: %s", __func__, sandbox); 681 return -1; 682 } else if (ctx->options & DHCPCD_LAUNCHER || 683 ((!(ctx->options & DHCPCD_DAEMONISE)) && 684 ctx->options & DHCPCD_MANAGER)) 685 logdebugx("sandbox: %s", sandbox); 686 return 0; 687 } 688 689 int 690 ps_stop(struct dhcpcd_ctx *ctx) 691 { 692 int r, ret = 0; 693 694 if (!(ctx->options & DHCPCD_PRIVSEP) || 695 ctx->options & DHCPCD_FORKED || 696 ctx->eloop == NULL) 697 return 0; 698 699 if (ctx->ps_ctl != NULL) { 700 r = ps_ctl_stop(ctx); 701 if (r != 0) 702 ret = r; 703 } 704 705 if (ctx->ps_inet != NULL) { 706 r = ps_inet_stop(ctx); 707 if (r != 0) 708 ret = r; 709 } 710 711 if (ctx->ps_root != NULL) { 712 if (ps_root_stopprocesses(ctx) == -1) 713 ret = -1; 714 } 715 716 return ret; 717 } 718 719 bool 720 ps_waitforprocs(struct dhcpcd_ctx *ctx) 721 { 722 struct ps_process *psp = TAILQ_FIRST(&ctx->ps_processes); 723 724 if (psp == NULL) 725 return false; 726 727 /* Different processes */ 728 if (psp != TAILQ_LAST(&ctx->ps_processes, ps_process_head)) 729 return true; 730 731 return !psp->psp_started; 732 } 733 734 int 735 ps_stopwait(struct dhcpcd_ctx *ctx) 736 { 737 int error = EXIT_SUCCESS; 738 739 if (ctx->ps_eloop == NULL || !ps_waitforprocs(ctx)) 740 return 0; 741 742 ctx->options |= DHCPCD_EXITING; 743 if (eloop_timeout_add_sec(ctx->ps_eloop, PS_PROCESS_TIMEOUT, 744 ps_process_timeout, ctx) == -1) 745 logerr("%s: eloop_timeout_add_sec", __func__); 746 eloop_enter(ctx->ps_eloop); 747 748 #ifdef HAVE_CAPSICUM 749 struct ps_process *psp; 750 751 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 752 if (psp->psp_pfd == -1) 753 continue; 754 if (eloop_event_add(ctx->ps_eloop, psp->psp_pfd, 755 ELE_HANGUP, ps_processhangup, psp) == -1) 756 logerr("%s: eloop_event_add pfd %d", 757 __func__, psp->psp_pfd); 758 } 759 #endif 760 761 error = eloop_start(ctx->ps_eloop, &ctx->sigset); 762 if (error != EXIT_SUCCESS) 763 logerr("%s: eloop_start", __func__); 764 765 eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx); 766 767 return error; 768 } 769 770 void 771 ps_freeprocess(struct ps_process *psp) 772 { 773 struct dhcpcd_ctx *ctx = psp->psp_ctx; 774 775 TAILQ_REMOVE(&ctx->ps_processes, psp, next); 776 777 if (psp->psp_fd != -1) { 778 eloop_event_delete(ctx->eloop, psp->psp_fd); 779 close(psp->psp_fd); 780 } 781 if (psp->psp_work_fd != -1) { 782 eloop_event_delete(ctx->eloop, psp->psp_work_fd); 783 close(psp->psp_work_fd); 784 } 785 #ifdef HAVE_CAPSICUM 786 if (psp->psp_pfd != -1) { 787 eloop_event_delete(ctx->eloop, psp->psp_pfd); 788 if (ctx->ps_eloop != NULL) 789 eloop_event_delete(ctx->ps_eloop, psp->psp_pfd); 790 close(psp->psp_pfd); 791 } 792 #endif 793 if (ctx->ps_root == psp) 794 ctx->ps_root = NULL; 795 if (ctx->ps_inet == psp) 796 ctx->ps_inet = NULL; 797 if (ctx->ps_ctl == psp) 798 ctx->ps_ctl = NULL; 799 #ifdef INET 800 if (psp->psp_bpf != NULL) 801 bpf_close(psp->psp_bpf); 802 #endif 803 free(psp); 804 } 805 806 static void 807 ps_free(struct dhcpcd_ctx *ctx) 808 { 809 struct ps_process *ppsp, *psp; 810 bool stop; 811 812 if (ctx->ps_root != NULL) 813 ppsp = ctx->ps_root; 814 else if (ctx->ps_ctl != NULL) 815 ppsp = ctx->ps_ctl; 816 else 817 ppsp = NULL; 818 if (ppsp != NULL) 819 stop = ppsp->psp_pid == getpid(); 820 else 821 stop = false; 822 823 while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) { 824 if (stop && psp != ppsp) 825 ps_stopprocess(psp); 826 ps_freeprocess(psp); 827 } 828 } 829 830 int 831 ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, 832 const void *data, size_t len) 833 { 834 uint8_t *datap, *namep, *controlp; 835 socklen_t cmsg_padlen = 836 CALC_CMSG_PADLEN(psm->ps_controllen, psm->ps_namelen); 837 838 namep = UNCONST(data); 839 controlp = namep + psm->ps_namelen + cmsg_padlen; 840 datap = controlp + psm->ps_controllen; 841 842 if (psm->ps_namelen != 0) { 843 if (psm->ps_namelen > len) { 844 errno = EINVAL; 845 return -1; 846 } 847 msg->msg_name = namep; 848 len -= psm->ps_namelen; 849 } else 850 msg->msg_name = NULL; 851 msg->msg_namelen = psm->ps_namelen; 852 853 if (psm->ps_controllen != 0) { 854 if (psm->ps_controllen > len) { 855 errno = EINVAL; 856 return -1; 857 } 858 msg->msg_control = controlp; 859 len -= psm->ps_controllen + cmsg_padlen; 860 } else 861 msg->msg_control = NULL; 862 msg->msg_controllen = psm->ps_controllen; 863 864 if (len != 0) { 865 msg->msg_iovlen = 1; 866 msg->msg_iov[0].iov_base = datap; 867 msg->msg_iov[0].iov_len = len; 868 } else { 869 msg->msg_iovlen = 0; 870 msg->msg_iov[0].iov_base = NULL; 871 msg->msg_iov[0].iov_len = 0; 872 } 873 return 0; 874 } 875 876 ssize_t 877 ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, 878 struct ps_msghdr *psm, const struct msghdr *msg) 879 { 880 long padding[1] = { 0 }; 881 struct iovec iov[] = { 882 { .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) }, 883 { .iov_base = NULL, }, /* name */ 884 { .iov_base = NULL, }, /* control padding */ 885 { .iov_base = NULL, }, /* control */ 886 { .iov_base = NULL, }, /* payload 1 */ 887 { .iov_base = NULL, }, /* payload 2 */ 888 { .iov_base = NULL, }, /* payload 3 */ 889 }; 890 int iovlen; 891 ssize_t len; 892 893 if (msg != NULL) { 894 struct iovec *iovp = &iov[1]; 895 int i; 896 socklen_t cmsg_padlen; 897 898 psm->ps_namelen = msg->msg_namelen; 899 psm->ps_controllen = (socklen_t)msg->msg_controllen; 900 901 iovp->iov_base = msg->msg_name; 902 iovp->iov_len = msg->msg_namelen; 903 iovp++; 904 905 cmsg_padlen = 906 CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); 907 assert(cmsg_padlen <= sizeof(padding)); 908 iovp->iov_len = cmsg_padlen; 909 iovp->iov_base = cmsg_padlen != 0 ? padding : NULL; 910 iovp++; 911 912 iovp->iov_base = msg->msg_control; 913 iovp->iov_len = msg->msg_controllen; 914 iovlen = 4; 915 916 for (i = 0; i < (int)msg->msg_iovlen; i++) { 917 if ((size_t)(iovlen + i) > __arraycount(iov)) { 918 errno = ENOBUFS; 919 return -1; 920 } 921 iovp++; 922 iovp->iov_base = msg->msg_iov[i].iov_base; 923 iovp->iov_len = msg->msg_iov[i].iov_len; 924 } 925 iovlen += i; 926 } else 927 iovlen = 1; 928 929 len = writev(fd, iov, iovlen); 930 if (len == -1) { 931 if (ctx->options & DHCPCD_FORKED && 932 !(ctx->options & DHCPCD_PRIVSEPROOT)) 933 eloop_exit(ctx->eloop, EXIT_FAILURE); 934 } 935 return len; 936 } 937 938 ssize_t 939 ps_sendpsmdata(struct dhcpcd_ctx *ctx, int fd, 940 struct ps_msghdr *psm, const void *data, size_t len) 941 { 942 struct iovec iov[] = { 943 { .iov_base = UNCONST(data), .iov_len = len }, 944 }; 945 struct msghdr msg = { 946 .msg_iov = iov, .msg_iovlen = 1, 947 }; 948 949 return ps_sendpsmmsg(ctx, fd, psm, &msg); 950 } 951 952 953 ssize_t 954 ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, 955 const struct msghdr *msg) 956 { 957 struct ps_msghdr psm = { 958 .ps_cmd = cmd, 959 .ps_flags = flags, 960 .ps_namelen = msg->msg_namelen, 961 .ps_controllen = (socklen_t)msg->msg_controllen, 962 }; 963 size_t i; 964 965 for (i = 0; i < (size_t)msg->msg_iovlen; i++) 966 psm.ps_datalen += msg->msg_iov[i].iov_len; 967 968 #if 0 /* For debugging structure padding. */ 969 logerrx("psa.family %lu %zu", offsetof(struct ps_addr, psa_family), sizeof(psm.ps_id.psi_addr.psa_family)); 970 logerrx("psa.pad %lu %zu", offsetof(struct ps_addr, psa_pad), sizeof(psm.ps_id.psi_addr.psa_pad)); 971 logerrx("psa.psa_u %lu %zu", offsetof(struct ps_addr, psa_u), sizeof(psm.ps_id.psi_addr.psa_u)); 972 logerrx("psa %zu", sizeof(psm.ps_id.psi_addr)); 973 974 logerrx("psi.addr %lu %zu", offsetof(struct ps_id, psi_addr), sizeof(psm.ps_id.psi_addr)); 975 logerrx("psi.index %lu %zu", offsetof(struct ps_id, psi_ifindex), sizeof(psm.ps_id.psi_ifindex)); 976 logerrx("psi.cmd %lu %zu", offsetof(struct ps_id, psi_cmd), sizeof(psm.ps_id.psi_cmd)); 977 logerrx("psi.pad %lu %zu", offsetof(struct ps_id, psi_pad), sizeof(psm.ps_id.psi_pad)); 978 logerrx("psi %zu", sizeof(struct ps_id)); 979 980 logerrx("ps_cmd %lu", offsetof(struct ps_msghdr, ps_cmd)); 981 logerrx("ps_pad %lu %zu", offsetof(struct ps_msghdr, ps_pad), sizeof(psm.ps_pad)); 982 logerrx("ps_flags %lu %zu", offsetof(struct ps_msghdr, ps_flags), sizeof(psm.ps_flags)); 983 984 logerrx("ps_id %lu %zu", offsetof(struct ps_msghdr, ps_id), sizeof(psm.ps_id)); 985 986 logerrx("ps_namelen %lu %zu", offsetof(struct ps_msghdr, ps_namelen), sizeof(psm.ps_namelen)); 987 logerrx("ps_controllen %lu %zu", offsetof(struct ps_msghdr, ps_controllen), sizeof(psm.ps_controllen)); 988 logerrx("ps_pad2 %lu %zu", offsetof(struct ps_msghdr, ps_pad2), sizeof(psm.ps_pad2)); 989 logerrx("ps_datalen %lu %zu", offsetof(struct ps_msghdr, ps_datalen), sizeof(psm.ps_datalen)); 990 logerrx("psm %zu", sizeof(psm)); 991 #endif 992 993 return ps_sendpsmmsg(ctx, fd, &psm, msg); 994 } 995 996 ssize_t 997 ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, 998 const void *data, size_t len) 999 { 1000 struct ps_msghdr psm = { 1001 .ps_cmd = cmd, 1002 .ps_flags = flags, 1003 }; 1004 struct iovec iov[] = { 1005 { .iov_base = UNCONST(data), .iov_len = len } 1006 }; 1007 struct msghdr msg = { 1008 .msg_iov = iov, .msg_iovlen = 1, 1009 }; 1010 1011 return ps_sendpsmmsg(ctx, fd, &psm, &msg); 1012 } 1013 1014 static ssize_t 1015 ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) 1016 { 1017 struct ps_msghdr psm = { .ps_cmd = cmd }; 1018 uint8_t data[PS_BUFLEN], *p = data; 1019 struct iovec iov[] = { 1020 { .iov_base = &psm, .iov_len = sizeof(psm) }, 1021 { .iov_base = data, .iov_len = 0 }, 1022 }; 1023 size_t dl = sizeof(data); 1024 socklen_t cmsg_padlen = 1025 CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); 1026 1027 if (msg->msg_namelen != 0) { 1028 if (msg->msg_namelen > dl) 1029 goto nobufs; 1030 psm.ps_namelen = msg->msg_namelen; 1031 memcpy(p, msg->msg_name, msg->msg_namelen); 1032 p += msg->msg_namelen; 1033 dl -= msg->msg_namelen; 1034 } 1035 1036 if (msg->msg_controllen != 0) { 1037 if (msg->msg_controllen + cmsg_padlen > dl) 1038 goto nobufs; 1039 if (cmsg_padlen != 0) { 1040 memset(p, 0, cmsg_padlen); 1041 p += cmsg_padlen; 1042 dl -= cmsg_padlen; 1043 } 1044 psm.ps_controllen = (socklen_t)msg->msg_controllen; 1045 memcpy(p, msg->msg_control, msg->msg_controllen); 1046 p += msg->msg_controllen; 1047 dl -= msg->msg_controllen; 1048 } 1049 1050 psm.ps_datalen = msg->msg_iov[0].iov_len; 1051 if (psm.ps_datalen > dl) 1052 goto nobufs; 1053 1054 iov[1].iov_len = 1055 psm.ps_namelen + psm.ps_controllen + psm.ps_datalen + cmsg_padlen; 1056 if (psm.ps_datalen != 0) 1057 memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); 1058 return writev(fd, iov, __arraycount(iov)); 1059 1060 nobufs: 1061 errno = ENOBUFS; 1062 return -1; 1063 } 1064 1065 ssize_t 1066 ps_recvmsg(int rfd, unsigned short events, uint16_t cmd, int wfd) 1067 { 1068 struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; 1069 uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; 1070 uint8_t databuf[64 * 1024]; 1071 struct iovec iov[] = { 1072 { .iov_base = databuf, .iov_len = sizeof(databuf) } 1073 }; 1074 struct msghdr msg = { 1075 .msg_name = &ss, .msg_namelen = sizeof(ss), 1076 .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), 1077 .msg_iov = iov, .msg_iovlen = 1, 1078 }; 1079 ssize_t len; 1080 1081 if (!(events & ELE_READ)) 1082 logerrx("%s: unexpected event 0x%04x", __func__, events); 1083 1084 len = recvmsg(rfd, &msg, 0); 1085 if (len == -1) { 1086 logerr("%s: recvmsg", __func__); 1087 return len; 1088 } 1089 1090 iov[0].iov_len = (size_t)len; 1091 len = ps_sendcmdmsg(wfd, cmd, &msg); 1092 if (len == -1) 1093 logerr("%s: ps_sendcmdmsg", __func__); 1094 return len; 1095 } 1096 1097 ssize_t 1098 ps_daemonised(struct dhcpcd_ctx *ctx) 1099 { 1100 struct ps_process *psp; 1101 ssize_t err = 0; 1102 1103 dhcpcd_daemonised(ctx); 1104 1105 /* Echo the message to all processes */ 1106 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1107 if (psp->psp_pid == getpid()) 1108 continue; 1109 if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_DAEMONISED, 1110 0, NULL, 0) == -1) 1111 err = -1; 1112 } 1113 1114 return err; 1115 } 1116 1117 ssize_t 1118 ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events, 1119 ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), 1120 void *cbctx) 1121 { 1122 struct ps_msg psm; 1123 ssize_t len; 1124 size_t dlen; 1125 struct iovec iov[1]; 1126 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; 1127 bool stop = false; 1128 1129 if (!(events & ELE_READ)) 1130 logerrx("%s: unexpected event 0x%04x", __func__, events); 1131 1132 len = read(fd, &psm, sizeof(psm)); 1133 #ifdef PRIVSEP_DEBUG 1134 logdebugx("%s: %zd", __func__, len); 1135 #endif 1136 1137 if (len == -1 || len == 0) 1138 stop = true; 1139 else { 1140 dlen = (size_t)len; 1141 if (dlen < sizeof(psm.psm_hdr)) { 1142 errno = EINVAL; 1143 return -1; 1144 } 1145 1146 if (psm.psm_hdr.ps_cmd == PS_STOP) { 1147 stop = true; 1148 len = 0; 1149 } else if (psm.psm_hdr.ps_cmd == PS_DAEMONISED) { 1150 ps_daemonised(ctx); 1151 return 0; 1152 } 1153 } 1154 1155 if (stop) { 1156 ctx->options |= DHCPCD_EXITING; 1157 #ifdef PRIVSEP_DEBUG 1158 logdebugx("process %d stopping", getpid()); 1159 #endif 1160 ps_free(ctx); 1161 eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); 1162 return len; 1163 } 1164 dlen -= sizeof(psm.psm_hdr); 1165 1166 if (ps_unrollmsg(&msg, &psm.psm_hdr, psm.psm_data, dlen) == -1) 1167 return -1; 1168 1169 if (callback == NULL) 1170 return 0; 1171 1172 errno = 0; 1173 return callback(cbctx, &psm.psm_hdr, &msg); 1174 } 1175 1176 struct ps_process * 1177 ps_findprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) 1178 { 1179 struct ps_process *psp; 1180 1181 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1182 if (!(psp->psp_started)) 1183 continue; 1184 if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0) 1185 return psp; 1186 } 1187 errno = ESRCH; 1188 return NULL; 1189 } 1190 1191 struct ps_process * 1192 ps_findprocesspid(struct dhcpcd_ctx *ctx, pid_t pid) 1193 { 1194 struct ps_process *psp; 1195 1196 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1197 if (psp->psp_pid == pid) 1198 return psp; 1199 } 1200 errno = ESRCH; 1201 return NULL; 1202 } 1203 1204 struct ps_process * 1205 ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) 1206 { 1207 struct ps_process *psp; 1208 1209 psp = calloc(1, sizeof(*psp)); 1210 if (psp == NULL) 1211 return NULL; 1212 psp->psp_ctx = ctx; 1213 memcpy(&psp->psp_id, psid, sizeof(psp->psp_id)); 1214 psp->psp_fd = -1; 1215 psp->psp_work_fd = -1; 1216 #ifdef HAVE_CAPSICUM 1217 psp->psp_pfd = -1; 1218 #endif 1219 1220 if (!(ctx->options & DHCPCD_MANAGER)) 1221 strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_ifname)); 1222 TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); 1223 return psp; 1224 } 1225 1226 void 1227 ps_freeprocesses(struct dhcpcd_ctx *ctx, struct ps_process *notthis) 1228 { 1229 struct ps_process *psp, *psn; 1230 1231 TAILQ_FOREACH_SAFE(psp, &ctx->ps_processes, next, psn) { 1232 if (psp == notthis) 1233 continue; 1234 ps_freeprocess(psp); 1235 } 1236 } 1237