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