zygote.c revision 302408
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: stable/11/lib/libcasper/libcasper/zygote.c 301572 2016-06-08 02:03:53Z oshogbo $");
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. */
51static int	zygote_sock = -1;
52
53int
54zygote_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 */
90static void
91zygote_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		}
146send:
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
164int
165zygote_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