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