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