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