]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcasper/libcasper/zygote.c
Import riscv DTS files
[FreeBSD/FreeBSD.git] / lib / libcasper / libcasper / zygote.c
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. */
58 static int      zygote_sock = -1;
59
60 #define ZYGOTE_SERVICE_EXECUTE  1
61
62 int
63 zygote_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
93 int
94 zygote_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  */
106 static void
107 zygote_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                 }
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(sock, nvlout);
183                 nvlist_destroy(nvlout);
184         }
185         /* NOTREACHED */
186 }
187
188 int
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 }