1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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/types.h>
39 #include <sys/capsicum.h>
40 #include <sys/procdesc.h>
41 #include <sys/socket.h>
42 #include <sys/nv.h>
43
44 #include <assert.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <stdbool.h>
48 #include <stdlib.h>
49 #include <strings.h>
50 #include <unistd.h>
51
52 #include "libcasper_impl.h"
53 #include "zygote.h"
54
55 /* Zygote info. */
56 static int zygote_sock = -1;
57
58 #define ZYGOTE_SERVICE_EXECUTE 1
59
60 int
zygote_clone(uint64_t funcidx,int * chanfdp,int * procfdp)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
zygote_clone_service_execute(int * chanfdp,int * procfdp)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
zygote_main(int * sockp)105 zygote_main(int *sockp)
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 fd_fix_environment(sockp);
115
116 assert(*sockp > STDERR_FILENO);
117
118 setproctitle("zygote");
119
120 for (;;) {
121 nvlin = nvlist_recv(*sockp, 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(*sockp);
161 close(chanfd[0]);
162 func(chanfd[1]);
163 /* NOTREACHED */
164 _exit(1);
165 default:
166 /* Parent. */
167 close(chanfd[1]);
168 break;
169 }
170 send:
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(*sockp, nvlout);
183 nvlist_destroy(nvlout);
184 }
185 /* NOTREACHED */
186 }
187
188 int
zygote_init(void)189 zygote_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