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