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