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