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 #ifdef PLUGIN_DEV 412 /* If we are not the root process, stop listening to devices. */ 413 if (ctx->ps_root != psp) 414 dev_stop(ctx); 415 #endif 416 417 ctx->options |= DHCPCD_FORKED; 418 if (ctx->ps_log_fd != -1) 419 logsetfd(ctx->ps_log_fd); 420 eloop_clear(ctx->eloop, -1); 421 eloop_forked(ctx->eloop); 422 eloop_signal_set_cb(ctx->eloop, 423 dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx); 424 /* ctx->sigset aready has the initial sigmask set in main() */ 425 if (eloop_signal_mask(ctx->eloop, NULL) == -1) { 426 logerr("%s: eloop_signal_mask", __func__); 427 goto errexit; 428 } 429 430 if (ctx->fork_fd != -1) { 431 /* Already removed from eloop thanks to above clear. */ 432 close(ctx->fork_fd); 433 ctx->fork_fd = -1; 434 } 435 436 /* This process has no need of the blocking inner eloop. */ 437 if (!(flags & PSF_ELOOP)) { 438 eloop_free(ctx->ps_eloop); 439 ctx->ps_eloop = NULL; 440 } else 441 eloop_forked(ctx->ps_eloop); 442 443 pidfile_clean(); 444 ps_freeprocesses(ctx, psp); 445 446 if (ctx->ps_root != psp) { 447 ctx->options &= ~DHCPCD_PRIVSEPROOT; 448 ctx->ps_root = NULL; 449 if (ctx->ps_log_root_fd != -1) { 450 /* Already removed from eloop thanks to above clear. */ 451 close(ctx->ps_log_root_fd); 452 ctx->ps_log_root_fd = -1; 453 } 454 #ifdef PRIVSEP_RIGHTS 455 if (ps_rights_limit_stdio() == -1) { 456 logerr("ps_rights_limit_stdio"); 457 goto errexit; 458 } 459 #endif 460 } 461 462 if (ctx->ps_inet != psp) 463 ctx->ps_inet = NULL; 464 if (ctx->ps_ctl != psp) 465 ctx->ps_ctl = NULL; 466 467 #if 0 468 char buf[1024]; 469 errno = 0; 470 ssize_t xx = recv(psp->psp_fd, buf, sizeof(buf), MSG_PEEK); 471 logerr("pid %d test fd %d recv peek %zd", getpid(), psp->psp_fd, xx); 472 #endif 473 474 if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ, 475 recv_msg, psp) == -1) 476 { 477 logerr("%d %s: eloop_event_add XX fd %d", getpid(), __func__, psp->psp_fd); 478 goto errexit; 479 } 480 481 if (callback(psp) == -1) 482 goto errexit; 483 484 if (flags & PSF_DROPPRIVS) 485 ps_dropprivs(ctx); 486 487 psp->psp_started = true; 488 return 0; 489 490 errexit: 491 if (psp->psp_fd != -1) { 492 close(psp->psp_fd); 493 psp->psp_fd = -1; 494 } 495 eloop_exit(ctx->eloop, EXIT_FAILURE); 496 return -1; 497 } 498 499 void 500 ps_process_timeout(void *arg) 501 { 502 struct dhcpcd_ctx *ctx = arg; 503 504 logerrx("%s: timed out", __func__); 505 eloop_exit(ctx->eloop, EXIT_FAILURE); 506 } 507 508 int 509 ps_stopprocess(struct ps_process *psp) 510 { 511 int err = 0; 512 513 if (psp == NULL) 514 return 0; 515 516 psp->psp_started = false; 517 518 #ifdef PRIVSEP_DEBUG 519 logdebugx("%s: me=%d pid=%d fd=%d %s", __func__, 520 getpid(), psp->psp_pid, psp->psp_fd, psp->psp_name); 521 #endif 522 523 if (psp->psp_fd != -1) { 524 eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); 525 #if 0 526 if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_STOP, 0, 527 NULL, 0) == -1) 528 { 529 logerr("%d %d %s %s", getpid(), psp->psp_pid, psp->psp_name, __func__); 530 err = -1; 531 } 532 shutdown(psp->psp_fd, SHUT_WR); 533 #else 534 if (shutdown(psp->psp_fd, SHUT_WR) == -1) { 535 logerr(__func__); 536 err = -1; 537 } 538 #endif 539 } 540 541 /* Don't wait for the process as it may not respond to the shutdown 542 * request. We'll reap the process on receipt of SIGCHLD where we 543 * also close the fd. */ 544 return err; 545 } 546 547 int 548 ps_start(struct dhcpcd_ctx *ctx) 549 { 550 pid_t pid; 551 552 TAILQ_INIT(&ctx->ps_processes); 553 554 /* We need an inner eloop to block with. */ 555 if ((ctx->ps_eloop = eloop_new()) == NULL) 556 return -1; 557 eloop_signal_set_cb(ctx->ps_eloop, 558 dhcpcd_signals, dhcpcd_signals_len, 559 dhcpcd_signal_cb, ctx); 560 561 switch (pid = ps_root_start(ctx)) { 562 case -1: 563 logerr("ps_root_start"); 564 return -1; 565 case 0: 566 return 0; 567 default: 568 logdebugx("spawned privileged proxy on PID %d", pid); 569 } 570 571 /* No point in spawning the generic network listener if we're 572 * not going to use it. */ 573 if (!ps_inet_canstart(ctx)) 574 goto started_net; 575 576 switch (pid = ps_inet_start(ctx)) { 577 case -1: 578 return -1; 579 case 0: 580 return 0; 581 default: 582 logdebugx("spawned network proxy on PID %d", pid); 583 } 584 585 started_net: 586 if (!(ctx->options & DHCPCD_TEST)) { 587 switch (pid = ps_ctl_start(ctx)) { 588 case -1: 589 return -1; 590 case 0: 591 return 0; 592 default: 593 logdebugx("spawned controller proxy on PID %d", pid); 594 } 595 } 596 597 #ifdef ARC4RANDOM_H 598 /* Seed the random number generator early incase it needs /dev/urandom 599 * which won't be available in the chroot. */ 600 arc4random(); 601 #endif 602 603 return 1; 604 } 605 606 int 607 ps_entersandbox(const char *_pledge, const char **sandbox) 608 { 609 610 #if !defined(HAVE_PLEDGE) 611 UNUSED(_pledge); 612 #endif 613 614 #if defined(HAVE_CAPSICUM) 615 if (sandbox != NULL) 616 *sandbox = "capsicum"; 617 return cap_enter(); 618 #elif defined(HAVE_PLEDGE) 619 if (sandbox != NULL) 620 *sandbox = "pledge"; 621 // There is no need to use unveil(2) because we are in an empty chroot 622 // This is encouraged by Theo de Raadt himself: 623 // https://www.mail-archive.com/misc@openbsd.org/msg171655.html 624 return pledge(_pledge, NULL); 625 #elif defined(HAVE_SECCOMP) 626 if (sandbox != NULL) 627 *sandbox = "seccomp"; 628 return ps_seccomp_enter(); 629 #else 630 if (sandbox != NULL) 631 *sandbox = "posix resource limited"; 632 return 0; 633 #endif 634 } 635 636 int 637 ps_managersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) 638 { 639 const char *sandbox = NULL; 640 bool forked; 641 int dropped; 642 643 forked = ctx->options & DHCPCD_FORKED; 644 ctx->options &= ~DHCPCD_FORKED; 645 dropped = ps_dropprivs(ctx); 646 if (forked) 647 ctx->options |= DHCPCD_FORKED; 648 649 /* 650 * If we don't have a root process, we cannot use syslog. 651 * If it cannot be opened before chrooting then syslog(3) will fail. 652 * openlog(3) does not return an error which doubly sucks. 653 */ 654 if (ctx->ps_root == NULL) { 655 unsigned int logopts = loggetopts(); 656 657 logopts &= ~LOGERR_LOG; 658 logsetopts(logopts); 659 } 660 661 if (dropped == -1) { 662 logerr("%s: ps_dropprivs", __func__); 663 return -1; 664 } 665 666 #ifdef PRIVSEP_RIGHTS 667 if ((ctx->pf_inet_fd != -1 && 668 ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) || 669 ps_rights_limit_stdio() == -1) 670 { 671 logerr("%s: cap_rights_limit", __func__); 672 return -1; 673 } 674 #endif 675 676 if (_pledge == NULL) 677 _pledge = "stdio"; 678 if (ps_entersandbox(_pledge, &sandbox) == -1) { 679 if (errno == ENOSYS) { 680 if (sandbox != NULL) 681 logwarnx("sandbox unavailable: %s", sandbox); 682 return 0; 683 } 684 logerr("%s: %s", __func__, sandbox); 685 return -1; 686 } else if (ctx->options & DHCPCD_LAUNCHER || 687 ((!(ctx->options & DHCPCD_DAEMONISE)) && 688 ctx->options & DHCPCD_MANAGER)) 689 logdebugx("sandbox: %s", sandbox); 690 return 0; 691 } 692 693 int 694 ps_stop(struct dhcpcd_ctx *ctx) 695 { 696 int r, ret = 0; 697 698 if (!(ctx->options & DHCPCD_PRIVSEP) || 699 ctx->options & DHCPCD_FORKED || 700 ctx->eloop == NULL) 701 return 0; 702 703 if (ctx->ps_ctl != NULL) { 704 r = ps_ctl_stop(ctx); 705 if (r != 0) 706 ret = r; 707 } 708 709 if (ctx->ps_inet != NULL) { 710 r = ps_inet_stop(ctx); 711 if (r != 0) 712 ret = r; 713 } 714 715 if (ctx->ps_root != NULL) { 716 if (ps_root_stopprocesses(ctx) == -1) 717 ret = -1; 718 } 719 720 return ret; 721 } 722 723 bool 724 ps_waitforprocs(struct dhcpcd_ctx *ctx) 725 { 726 struct ps_process *psp = TAILQ_FIRST(&ctx->ps_processes); 727 728 if (psp == NULL) 729 return false; 730 731 /* Different processes */ 732 if (psp != TAILQ_LAST(&ctx->ps_processes, ps_process_head)) 733 return true; 734 735 return !psp->psp_started; 736 } 737 738 int 739 ps_stopwait(struct dhcpcd_ctx *ctx) 740 { 741 int error = EXIT_SUCCESS; 742 743 if (ctx->ps_eloop == NULL || !ps_waitforprocs(ctx)) 744 return 0; 745 746 ctx->options |= DHCPCD_EXITING; 747 if (eloop_timeout_add_sec(ctx->ps_eloop, PS_PROCESS_TIMEOUT, 748 ps_process_timeout, ctx) == -1) 749 logerr("%s: eloop_timeout_add_sec", __func__); 750 eloop_enter(ctx->ps_eloop); 751 752 #ifdef HAVE_CAPSICUM 753 struct ps_process *psp; 754 755 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 756 if (psp->psp_pfd == -1) 757 continue; 758 if (eloop_event_add(ctx->ps_eloop, psp->psp_pfd, 759 ELE_HANGUP, ps_processhangup, psp) == -1) 760 logerr("%s: eloop_event_add pfd %d", 761 __func__, psp->psp_pfd); 762 } 763 #endif 764 765 error = eloop_start(ctx->ps_eloop, &ctx->sigset); 766 if (error != EXIT_SUCCESS) 767 logerr("%s: eloop_start", __func__); 768 769 eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx); 770 771 return error; 772 } 773 774 void 775 ps_freeprocess(struct ps_process *psp) 776 { 777 struct dhcpcd_ctx *ctx = psp->psp_ctx; 778 779 TAILQ_REMOVE(&ctx->ps_processes, psp, next); 780 781 if (psp->psp_fd != -1) { 782 eloop_event_delete(ctx->eloop, psp->psp_fd); 783 close(psp->psp_fd); 784 } 785 if (psp->psp_work_fd != -1) { 786 eloop_event_delete(ctx->eloop, psp->psp_work_fd); 787 close(psp->psp_work_fd); 788 } 789 #ifdef HAVE_CAPSICUM 790 if (psp->psp_pfd != -1) { 791 eloop_event_delete(ctx->eloop, psp->psp_pfd); 792 if (ctx->ps_eloop != NULL) 793 eloop_event_delete(ctx->ps_eloop, psp->psp_pfd); 794 close(psp->psp_pfd); 795 } 796 #endif 797 if (ctx->ps_root == psp) 798 ctx->ps_root = NULL; 799 if (ctx->ps_inet == psp) 800 ctx->ps_inet = NULL; 801 if (ctx->ps_ctl == psp) 802 ctx->ps_ctl = NULL; 803 #ifdef INET 804 if (psp->psp_bpf != NULL) 805 bpf_close(psp->psp_bpf); 806 #endif 807 free(psp); 808 } 809 810 static void 811 ps_free(struct dhcpcd_ctx *ctx) 812 { 813 struct ps_process *ppsp, *psp; 814 bool stop; 815 816 if (ctx->ps_root != NULL) 817 ppsp = ctx->ps_root; 818 else if (ctx->ps_ctl != NULL) 819 ppsp = ctx->ps_ctl; 820 else 821 ppsp = NULL; 822 if (ppsp != NULL) 823 stop = ppsp->psp_pid == getpid(); 824 else 825 stop = false; 826 827 while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) { 828 if (stop && psp != ppsp) 829 ps_stopprocess(psp); 830 ps_freeprocess(psp); 831 } 832 } 833 834 int 835 ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, 836 const void *data, size_t len) 837 { 838 uint8_t *datap, *namep, *controlp; 839 socklen_t cmsg_padlen = 840 CALC_CMSG_PADLEN(psm->ps_controllen, psm->ps_namelen); 841 842 namep = UNCONST(data); 843 controlp = namep + psm->ps_namelen + cmsg_padlen; 844 datap = controlp + psm->ps_controllen; 845 846 if (psm->ps_namelen != 0) { 847 if (psm->ps_namelen > len) { 848 errno = EINVAL; 849 return -1; 850 } 851 msg->msg_name = namep; 852 len -= psm->ps_namelen; 853 } else 854 msg->msg_name = NULL; 855 msg->msg_namelen = psm->ps_namelen; 856 857 if (psm->ps_controllen != 0) { 858 if (psm->ps_controllen > len) { 859 errno = EINVAL; 860 return -1; 861 } 862 msg->msg_control = controlp; 863 len -= psm->ps_controllen + cmsg_padlen; 864 } else 865 msg->msg_control = NULL; 866 msg->msg_controllen = psm->ps_controllen; 867 868 if (len != 0) { 869 msg->msg_iovlen = 1; 870 msg->msg_iov[0].iov_base = datap; 871 msg->msg_iov[0].iov_len = len; 872 } else { 873 msg->msg_iovlen = 0; 874 msg->msg_iov[0].iov_base = NULL; 875 msg->msg_iov[0].iov_len = 0; 876 } 877 return 0; 878 } 879 880 ssize_t 881 ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, 882 struct ps_msghdr *psm, const struct msghdr *msg) 883 { 884 long padding[1] = { 0 }; 885 struct iovec iov[] = { 886 { .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) }, 887 { .iov_base = NULL, }, /* name */ 888 { .iov_base = NULL, }, /* control padding */ 889 { .iov_base = NULL, }, /* control */ 890 { .iov_base = NULL, }, /* payload 1 */ 891 { .iov_base = NULL, }, /* payload 2 */ 892 { .iov_base = NULL, }, /* payload 3 */ 893 }; 894 int iovlen; 895 ssize_t len; 896 897 if (msg != NULL) { 898 struct iovec *iovp = &iov[1]; 899 int i; 900 socklen_t cmsg_padlen; 901 902 psm->ps_namelen = msg->msg_namelen; 903 psm->ps_controllen = (socklen_t)msg->msg_controllen; 904 905 iovp->iov_base = msg->msg_name; 906 iovp->iov_len = msg->msg_namelen; 907 iovp++; 908 909 cmsg_padlen = 910 CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); 911 assert(cmsg_padlen <= sizeof(padding)); 912 iovp->iov_len = cmsg_padlen; 913 iovp->iov_base = cmsg_padlen != 0 ? padding : NULL; 914 iovp++; 915 916 iovp->iov_base = msg->msg_control; 917 iovp->iov_len = msg->msg_controllen; 918 iovlen = 4; 919 920 for (i = 0; i < (int)msg->msg_iovlen; i++) { 921 if ((size_t)(iovlen + i) > __arraycount(iov)) { 922 errno = ENOBUFS; 923 return -1; 924 } 925 iovp++; 926 iovp->iov_base = msg->msg_iov[i].iov_base; 927 iovp->iov_len = msg->msg_iov[i].iov_len; 928 } 929 iovlen += i; 930 } else 931 iovlen = 1; 932 933 len = writev(fd, iov, iovlen); 934 if (len == -1) { 935 if (ctx->options & DHCPCD_FORKED && 936 !(ctx->options & DHCPCD_PRIVSEPROOT)) 937 eloop_exit(ctx->eloop, EXIT_FAILURE); 938 } 939 return len; 940 } 941 942 ssize_t 943 ps_sendpsmdata(struct dhcpcd_ctx *ctx, int fd, 944 struct ps_msghdr *psm, const void *data, size_t len) 945 { 946 struct iovec iov[] = { 947 { .iov_base = UNCONST(data), .iov_len = len }, 948 }; 949 struct msghdr msg = { 950 .msg_iov = iov, .msg_iovlen = 1, 951 }; 952 953 return ps_sendpsmmsg(ctx, fd, psm, &msg); 954 } 955 956 957 ssize_t 958 ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, 959 const struct msghdr *msg) 960 { 961 struct ps_msghdr psm = { 962 .ps_cmd = cmd, 963 .ps_flags = flags, 964 .ps_namelen = msg->msg_namelen, 965 .ps_controllen = (socklen_t)msg->msg_controllen, 966 }; 967 size_t i; 968 969 for (i = 0; i < (size_t)msg->msg_iovlen; i++) 970 psm.ps_datalen += msg->msg_iov[i].iov_len; 971 972 #if 0 /* For debugging structure padding. */ 973 logerrx("psa.family %lu %zu", offsetof(struct ps_addr, psa_family), sizeof(psm.ps_id.psi_addr.psa_family)); 974 logerrx("psa.pad %lu %zu", offsetof(struct ps_addr, psa_pad), sizeof(psm.ps_id.psi_addr.psa_pad)); 975 logerrx("psa.psa_u %lu %zu", offsetof(struct ps_addr, psa_u), sizeof(psm.ps_id.psi_addr.psa_u)); 976 logerrx("psa %zu", sizeof(psm.ps_id.psi_addr)); 977 978 logerrx("psi.addr %lu %zu", offsetof(struct ps_id, psi_addr), sizeof(psm.ps_id.psi_addr)); 979 logerrx("psi.index %lu %zu", offsetof(struct ps_id, psi_ifindex), sizeof(psm.ps_id.psi_ifindex)); 980 logerrx("psi.cmd %lu %zu", offsetof(struct ps_id, psi_cmd), sizeof(psm.ps_id.psi_cmd)); 981 logerrx("psi.pad %lu %zu", offsetof(struct ps_id, psi_pad), sizeof(psm.ps_id.psi_pad)); 982 logerrx("psi %zu", sizeof(struct ps_id)); 983 984 logerrx("ps_cmd %lu", offsetof(struct ps_msghdr, ps_cmd)); 985 logerrx("ps_pad %lu %zu", offsetof(struct ps_msghdr, ps_pad), sizeof(psm.ps_pad)); 986 logerrx("ps_flags %lu %zu", offsetof(struct ps_msghdr, ps_flags), sizeof(psm.ps_flags)); 987 988 logerrx("ps_id %lu %zu", offsetof(struct ps_msghdr, ps_id), sizeof(psm.ps_id)); 989 990 logerrx("ps_namelen %lu %zu", offsetof(struct ps_msghdr, ps_namelen), sizeof(psm.ps_namelen)); 991 logerrx("ps_controllen %lu %zu", offsetof(struct ps_msghdr, ps_controllen), sizeof(psm.ps_controllen)); 992 logerrx("ps_pad2 %lu %zu", offsetof(struct ps_msghdr, ps_pad2), sizeof(psm.ps_pad2)); 993 logerrx("ps_datalen %lu %zu", offsetof(struct ps_msghdr, ps_datalen), sizeof(psm.ps_datalen)); 994 logerrx("psm %zu", sizeof(psm)); 995 #endif 996 997 return ps_sendpsmmsg(ctx, fd, &psm, msg); 998 } 999 1000 ssize_t 1001 ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, 1002 const void *data, size_t len) 1003 { 1004 struct ps_msghdr psm = { 1005 .ps_cmd = cmd, 1006 .ps_flags = flags, 1007 }; 1008 struct iovec iov[] = { 1009 { .iov_base = UNCONST(data), .iov_len = len } 1010 }; 1011 struct msghdr msg = { 1012 .msg_iov = iov, .msg_iovlen = 1, 1013 }; 1014 1015 return ps_sendpsmmsg(ctx, fd, &psm, &msg); 1016 } 1017 1018 static ssize_t 1019 ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) 1020 { 1021 struct ps_msghdr psm = { .ps_cmd = cmd }; 1022 uint8_t data[PS_BUFLEN], *p = data; 1023 struct iovec iov[] = { 1024 { .iov_base = &psm, .iov_len = sizeof(psm) }, 1025 { .iov_base = data, .iov_len = 0 }, 1026 }; 1027 size_t dl = sizeof(data); 1028 socklen_t cmsg_padlen = 1029 CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); 1030 1031 if (msg->msg_namelen != 0) { 1032 if (msg->msg_namelen > dl) 1033 goto nobufs; 1034 psm.ps_namelen = msg->msg_namelen; 1035 memcpy(p, msg->msg_name, msg->msg_namelen); 1036 p += msg->msg_namelen; 1037 dl -= msg->msg_namelen; 1038 } 1039 1040 if (msg->msg_controllen != 0) { 1041 if (msg->msg_controllen + cmsg_padlen > dl) 1042 goto nobufs; 1043 if (cmsg_padlen != 0) { 1044 memset(p, 0, cmsg_padlen); 1045 p += cmsg_padlen; 1046 dl -= cmsg_padlen; 1047 } 1048 psm.ps_controllen = (socklen_t)msg->msg_controllen; 1049 memcpy(p, msg->msg_control, msg->msg_controllen); 1050 p += msg->msg_controllen; 1051 dl -= msg->msg_controllen; 1052 } 1053 1054 psm.ps_datalen = msg->msg_iov[0].iov_len; 1055 if (psm.ps_datalen > dl) 1056 goto nobufs; 1057 1058 iov[1].iov_len = 1059 psm.ps_namelen + psm.ps_controllen + psm.ps_datalen + cmsg_padlen; 1060 if (psm.ps_datalen != 0) 1061 memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); 1062 return writev(fd, iov, __arraycount(iov)); 1063 1064 nobufs: 1065 errno = ENOBUFS; 1066 return -1; 1067 } 1068 1069 ssize_t 1070 ps_recvmsg(int rfd, unsigned short events, uint16_t cmd, int wfd) 1071 { 1072 struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; 1073 uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; 1074 uint8_t databuf[64 * 1024]; 1075 struct iovec iov[] = { 1076 { .iov_base = databuf, .iov_len = sizeof(databuf) } 1077 }; 1078 struct msghdr msg = { 1079 .msg_name = &ss, .msg_namelen = sizeof(ss), 1080 .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), 1081 .msg_iov = iov, .msg_iovlen = 1, 1082 }; 1083 ssize_t len; 1084 1085 if (!(events & ELE_READ)) 1086 logerrx("%s: unexpected event 0x%04x", __func__, events); 1087 1088 len = recvmsg(rfd, &msg, 0); 1089 if (len == -1) { 1090 logerr("%s: recvmsg", __func__); 1091 return len; 1092 } 1093 1094 iov[0].iov_len = (size_t)len; 1095 len = ps_sendcmdmsg(wfd, cmd, &msg); 1096 if (len == -1) 1097 logerr("%s: ps_sendcmdmsg", __func__); 1098 return len; 1099 } 1100 1101 ssize_t 1102 ps_daemonised(struct dhcpcd_ctx *ctx) 1103 { 1104 struct ps_process *psp; 1105 ssize_t err = 0; 1106 1107 dhcpcd_daemonised(ctx); 1108 1109 /* Echo the message to all processes */ 1110 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1111 if (psp->psp_pid == getpid()) 1112 continue; 1113 if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_DAEMONISED, 1114 0, NULL, 0) == -1) 1115 err = -1; 1116 } 1117 1118 return err; 1119 } 1120 1121 ssize_t 1122 ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events, 1123 ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), 1124 void *cbctx) 1125 { 1126 struct ps_msg psm; 1127 ssize_t len; 1128 size_t dlen; 1129 struct iovec iov[1]; 1130 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; 1131 bool stop = false; 1132 1133 if (!(events & ELE_READ)) 1134 logerrx("%s: unexpected event 0x%04x", __func__, events); 1135 1136 len = read(fd, &psm, sizeof(psm)); 1137 #ifdef PRIVSEP_DEBUG 1138 logdebugx("%s: %zd", __func__, len); 1139 #endif 1140 1141 if (len == -1 || len == 0) 1142 stop = true; 1143 else { 1144 dlen = (size_t)len; 1145 if (dlen < sizeof(psm.psm_hdr)) { 1146 errno = EINVAL; 1147 return -1; 1148 } 1149 1150 if (psm.psm_hdr.ps_cmd == PS_STOP) { 1151 stop = true; 1152 len = 0; 1153 } else if (psm.psm_hdr.ps_cmd == PS_DAEMONISED) { 1154 ps_daemonised(ctx); 1155 return 0; 1156 } 1157 } 1158 1159 if (stop) { 1160 ctx->options |= DHCPCD_EXITING; 1161 #ifdef PRIVSEP_DEBUG 1162 logdebugx("process %d stopping", getpid()); 1163 #endif 1164 ps_free(ctx); 1165 eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); 1166 return len; 1167 } 1168 dlen -= sizeof(psm.psm_hdr); 1169 1170 if (ps_unrollmsg(&msg, &psm.psm_hdr, psm.psm_data, dlen) == -1) 1171 return -1; 1172 1173 if (callback == NULL) 1174 return 0; 1175 1176 errno = 0; 1177 return callback(cbctx, &psm.psm_hdr, &msg); 1178 } 1179 1180 struct ps_process * 1181 ps_findprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) 1182 { 1183 struct ps_process *psp; 1184 1185 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1186 if (!(psp->psp_started)) 1187 continue; 1188 if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0) 1189 return psp; 1190 } 1191 errno = ESRCH; 1192 return NULL; 1193 } 1194 1195 struct ps_process * 1196 ps_findprocesspid(struct dhcpcd_ctx *ctx, pid_t pid) 1197 { 1198 struct ps_process *psp; 1199 1200 TAILQ_FOREACH(psp, &ctx->ps_processes, next) { 1201 if (psp->psp_pid == pid) 1202 return psp; 1203 } 1204 errno = ESRCH; 1205 return NULL; 1206 } 1207 1208 struct ps_process * 1209 ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) 1210 { 1211 struct ps_process *psp; 1212 1213 psp = calloc(1, sizeof(*psp)); 1214 if (psp == NULL) 1215 return NULL; 1216 psp->psp_ctx = ctx; 1217 memcpy(&psp->psp_id, psid, sizeof(psp->psp_id)); 1218 psp->psp_work_fd = -1; 1219 #ifdef HAVE_CAPSICUM 1220 psp->psp_pfd = -1; 1221 #endif 1222 1223 if (!(ctx->options & DHCPCD_MANAGER)) 1224 strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_ifname)); 1225 TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); 1226 return psp; 1227 } 1228 1229 void 1230 ps_freeprocesses(struct dhcpcd_ctx *ctx, struct ps_process *notthis) 1231 { 1232 struct ps_process *psp, *psn; 1233 1234 TAILQ_FOREACH_SAFE(psp, &ctx->ps_processes, next, psn) { 1235 if (psp == notthis) 1236 continue; 1237 ps_freeprocess(psp); 1238 } 1239 } 1240