1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012 The FreeBSD Foundation
5 * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
6 * Copyright (c) 2017 Robert N. M. Watson
7 *
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
10 *
11 * All rights reserved.
12 * This software was developed by SRI International and the University of
13 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
14 * ("CTSRD"), as part of the DARPA CRASH research programme.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD$");
40
41#include <sys/types.h>
42#include <sys/capsicum.h>
43#include <sys/procdesc.h>
44#include <sys/socket.h>
45#include <sys/nv.h>
46
47#include <assert.h>
48#include <err.h>
49#include <errno.h>
50#include <stdbool.h>
51#include <stdlib.h>
52#include <strings.h>
53#include <unistd.h>
54
55#include "zygote.h"
56
57/* Zygote info. */
58static int	zygote_sock = -1;
59
60#define	ZYGOTE_SERVICE_EXECUTE	1
61
62int
63zygote_clone(uint64_t funcidx, int *chanfdp, int *procfdp)
64{
65	nvlist_t *nvl;
66	int error;
67
68	if (zygote_sock == -1) {
69		/* Zygote didn't start. */
70		errno = ENXIO;
71		return (-1);
72	}
73
74	nvl = nvlist_create(0);
75	nvlist_add_number(nvl, "funcidx", funcidx);
76	nvl = nvlist_xfer(zygote_sock, nvl, 0);
77	if (nvl == NULL)
78		return (-1);
79	if (nvlist_exists_number(nvl, "error")) {
80		error = (int)nvlist_get_number(nvl, "error");
81		nvlist_destroy(nvl);
82		errno = error;
83		return (-1);
84	}
85
86	*chanfdp = nvlist_take_descriptor(nvl, "chanfd");
87	*procfdp = nvlist_take_descriptor(nvl, "procfd");
88
89	nvlist_destroy(nvl);
90	return (0);
91}
92
93int
94zygote_clone_service_execute(int *chanfdp, int *procfdp)
95{
96
97	return (zygote_clone(ZYGOTE_SERVICE_EXECUTE, chanfdp, procfdp));
98}
99
100/*
101 * This function creates sandboxes on-demand whoever has access to it via
102 * 'sock' socket. Function sends two descriptors to the caller: process
103 * descriptor of the sandbox and socket pair descriptor for communication
104 * between sandbox and its owner.
105 */
106static void
107zygote_main(int sock)
108{
109	int error, procfd;
110	int chanfd[2];
111	nvlist_t *nvlin, *nvlout;
112	uint64_t funcidx;
113	zygote_func_t *func;
114	pid_t pid;
115
116	assert(sock > STDERR_FILENO);
117
118	setproctitle("zygote");
119
120	for (;;) {
121		nvlin = nvlist_recv(sock, 0);
122		if (nvlin == NULL) {
123			if (errno == ENOTCONN) {
124				/* Casper exited. */
125				_exit(0);
126			}
127			continue;
128		}
129		funcidx = nvlist_get_number(nvlin, "funcidx");
130		nvlist_destroy(nvlin);
131
132		switch (funcidx) {
133		case ZYGOTE_SERVICE_EXECUTE:
134			func = service_execute;
135			break;
136		default:
137			_exit(0);
138		}
139
140		/*
141		 * Someone is requesting a new process, create one.
142		 */
143		procfd = -1;
144		chanfd[0] = -1;
145		chanfd[1] = -1;
146		error = 0;
147		if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
148		    chanfd) == -1) {
149			error = errno;
150			goto send;
151		}
152		pid = pdfork(&procfd, 0);
153		switch (pid) {
154		case -1:
155			/* Failure. */
156			error = errno;
157			break;
158		case 0:
159			/* Child. */
160			close(sock);
161			close(chanfd[0]);
162			func(chanfd[1]);
163			/* NOTREACHED */
164			_exit(1);
165		default:
166			/* Parent. */
167			close(chanfd[1]);
168			break;
169		}
170send:
171		nvlout = nvlist_create(0);
172		if (error != 0) {
173			nvlist_add_number(nvlout, "error", (uint64_t)error);
174			if (chanfd[0] >= 0)
175				close(chanfd[0]);
176			if (procfd >= 0)
177				close(procfd);
178		} else {
179			nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
180			nvlist_move_descriptor(nvlout, "procfd", procfd);
181		}
182		(void)nvlist_send(sock, nvlout);
183		nvlist_destroy(nvlout);
184	}
185	/* NOTREACHED */
186}
187
188int
189zygote_init(void)
190{
191	int serrno, sp[2];
192	pid_t pid;
193
194	if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1)
195		return (-1);
196
197	pid = fork();
198	switch (pid) {
199	case -1:
200		/* Failure. */
201		serrno = errno;
202		close(sp[0]);
203		close(sp[1]);
204		errno = serrno;
205		return (-1);
206	case 0:
207		/* Child. */
208		close(sp[0]);
209		zygote_main(sp[1]);
210		/* NOTREACHED */
211		abort();
212	default:
213		/* Parent. */
214		zygote_sock = sp[0];
215		close(sp[1]);
216		return (0);
217	}
218	/* NOTREACHED */
219}
220