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 "libcasper_impl.h" 56 #include "zygote.h" 57 58 /* Zygote info. */ 59 static int zygote_sock = -1; 60 61 #define ZYGOTE_SERVICE_EXECUTE 1 62 63 int 64 zygote_clone(uint64_t funcidx, int *chanfdp, int *procfdp) 65 { 66 nvlist_t *nvl; 67 int error; 68 69 if (zygote_sock == -1) { 70 /* Zygote didn't start. */ 71 errno = ENXIO; 72 return (-1); 73 } 74 75 nvl = nvlist_create(0); 76 nvlist_add_number(nvl, "funcidx", funcidx); 77 nvl = nvlist_xfer(zygote_sock, nvl, 0); 78 if (nvl == NULL) 79 return (-1); 80 if (nvlist_exists_number(nvl, "error")) { 81 error = (int)nvlist_get_number(nvl, "error"); 82 nvlist_destroy(nvl); 83 errno = error; 84 return (-1); 85 } 86 87 *chanfdp = nvlist_take_descriptor(nvl, "chanfd"); 88 *procfdp = nvlist_take_descriptor(nvl, "procfd"); 89 90 nvlist_destroy(nvl); 91 return (0); 92 } 93 94 int 95 zygote_clone_service_execute(int *chanfdp, int *procfdp) 96 { 97 98 return (zygote_clone(ZYGOTE_SERVICE_EXECUTE, chanfdp, procfdp)); 99 } 100 101 /* 102 * This function creates sandboxes on-demand whoever has access to it via 103 * 'sock' socket. Function sends two descriptors to the caller: process 104 * descriptor of the sandbox and socket pair descriptor for communication 105 * between sandbox and its owner. 106 */ 107 static void 108 zygote_main(int *sockp) 109 { 110 int error, procfd; 111 int chanfd[2]; 112 nvlist_t *nvlin, *nvlout; 113 uint64_t funcidx; 114 zygote_func_t *func; 115 pid_t pid; 116 117 fd_fix_environment(sockp); 118 119 assert(*sockp > STDERR_FILENO); 120 121 setproctitle("zygote"); 122 123 for (;;) { 124 nvlin = nvlist_recv(*sockp, 0); 125 if (nvlin == NULL) { 126 if (errno == ENOTCONN) { 127 /* Casper exited. */ 128 _exit(0); 129 } 130 continue; 131 } 132 funcidx = nvlist_get_number(nvlin, "funcidx"); 133 nvlist_destroy(nvlin); 134 135 switch (funcidx) { 136 case ZYGOTE_SERVICE_EXECUTE: 137 func = service_execute; 138 break; 139 default: 140 _exit(0); 141 } 142 143 /* 144 * Someone is requesting a new process, create one. 145 */ 146 procfd = -1; 147 chanfd[0] = -1; 148 chanfd[1] = -1; 149 error = 0; 150 if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, 151 chanfd) == -1) { 152 error = errno; 153 goto send; 154 } 155 pid = pdfork(&procfd, 0); 156 switch (pid) { 157 case -1: 158 /* Failure. */ 159 error = errno; 160 break; 161 case 0: 162 /* Child. */ 163 close(*sockp); 164 close(chanfd[0]); 165 func(chanfd[1]); 166 /* NOTREACHED */ 167 _exit(1); 168 default: 169 /* Parent. */ 170 close(chanfd[1]); 171 break; 172 } 173 send: 174 nvlout = nvlist_create(0); 175 if (error != 0) { 176 nvlist_add_number(nvlout, "error", (uint64_t)error); 177 if (chanfd[0] >= 0) 178 close(chanfd[0]); 179 if (procfd >= 0) 180 close(procfd); 181 } else { 182 nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]); 183 nvlist_move_descriptor(nvlout, "procfd", procfd); 184 } 185 (void)nvlist_send(*sockp, nvlout); 186 nvlist_destroy(nvlout); 187 } 188 /* NOTREACHED */ 189 } 190 191 int 192 zygote_init(void) 193 { 194 int serrno, sp[2]; 195 pid_t pid; 196 197 if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1) 198 return (-1); 199 200 pid = fork(); 201 switch (pid) { 202 case -1: 203 /* Failure. */ 204 serrno = errno; 205 close(sp[0]); 206 close(sp[1]); 207 errno = serrno; 208 return (-1); 209 case 0: 210 /* Child. */ 211 close(sp[0]); 212 zygote_main(&sp[1]); 213 /* NOTREACHED */ 214 abort(); 215 default: 216 /* Parent. */ 217 zygote_sock = sp[0]; 218 close(sp[1]); 219 return (0); 220 } 221 /* NOTREACHED */ 222 } 223