2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012 The FreeBSD Foundation
5 * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
6 * Copyright (c) 2017 Robert N. M. Watson
9 * This software was developed by Pawel Jakub Dawidek under sponsorship from
10 * the FreeBSD Foundation.
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.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
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
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
41 #include <sys/types.h>
42 #include <sys/queue.h>
43 #include <sys/socket.h>
54 #include "libcasper_impl.h"
57 struct casper_service {
58 struct service *cs_service;
59 TAILQ_ENTRY(casper_service) cs_next;
62 static TAILQ_HEAD(, casper_service) casper_services =
63 TAILQ_HEAD_INITIALIZER(casper_services);
65 #define CORE_CASPER_NAME "core.casper"
66 #define CSERVICE_IS_CORE(service) \
67 (strcmp(service_name(service->cs_service), CORE_CASPER_NAME) == 0)
69 static struct casper_service *
70 service_find(const char *name)
72 struct casper_service *casserv;
74 TAILQ_FOREACH(casserv, &casper_services, cs_next) {
75 if (strcmp(service_name(casserv->cs_service), name) == 0)
81 struct casper_service *
82 service_register(const char *name, service_limit_func_t *limitfunc,
83 service_command_func_t *commandfunc, uint64_t flags)
85 struct casper_service *casserv;
87 if (commandfunc == NULL)
89 if (name == NULL || name[0] == '\0')
91 if (service_find(name) != NULL)
94 casserv = malloc(sizeof(*casserv));
98 casserv->cs_service = service_alloc(name, limitfunc, commandfunc,
100 if (casserv->cs_service == NULL) {
104 TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
110 casper_allowed_service(const nvlist_t *limits, const char *service)
116 if (nvlist_exists_null(limits, service))
123 casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
130 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
131 if (type != NV_TYPE_NULL)
133 if (!casper_allowed_service(oldlimits, name))
134 return (ENOTCAPABLE);
141 service_execute(int chanfd)
143 struct casper_service *casserv;
144 struct service *service;
145 const char *servname;
149 nvl = nvlist_recv(chanfd, 0);
152 if (!nvlist_exists_string(nvl, "service"))
154 servname = nvlist_get_string(nvl, "service");
155 casserv = service_find(servname);
158 service = casserv->cs_service;
159 procfd = nvlist_take_descriptor(nvl, "procfd");
162 service_start(service, chanfd, procfd);
168 casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
171 struct casper_service *casserv;
172 const char *servname;
174 int chanfd, procfd, error;
176 if (strcmp(cmd, "open") != 0)
178 if (!nvlist_exists_string(nvlin, "service"))
181 servname = nvlist_get_string(nvlin, "service");
182 casserv = service_find(servname);
186 if (!casper_allowed_service(limits, servname))
187 return (ENOTCAPABLE);
189 if (zygote_clone_service_execute(&chanfd, &procfd) == -1)
192 nvl = nvlist_create(0);
193 nvlist_add_string(nvl, "service", servname);
194 nvlist_move_descriptor(nvl, "procfd", procfd);
195 if (nvlist_send(chanfd, nvl) == -1) {
203 nvlist_move_descriptor(nvlout, "chanfd", chanfd);
204 nvlist_add_number(nvlout, "chanflags",
205 service_get_channel_flags(casserv->cs_service));
211 service_register_core(int fd)
213 struct casper_service *casserv;
214 struct service_connection *sconn;
216 casserv = service_register(CORE_CASPER_NAME, casper_limit,
218 sconn = service_connection_add(casserv->cs_service, fd, NULL);
226 casper_main_loop(int fd)
229 struct casper_service *casserv;
230 struct service_connection *sconn, *sconntmp;
231 int sock, maxfd, ret;
233 if (zygote_init() < 0)
237 * Register core services.
239 service_register_core(fd);
245 TAILQ_FOREACH(casserv, &casper_services, cs_next) {
246 /* We handle only core services. */
247 if (!CSERVICE_IS_CORE(casserv))
249 for (sconn = service_connection_first(casserv->cs_service);
251 sconn = service_connection_next(sconn)) {
252 sock = service_connection_get_sock(sconn);
254 maxfd = sock > maxfd ? sock : maxfd;
264 assert(maxfd <= (int)FD_SETSIZE);
265 ret = select(maxfd, &fds, NULL, NULL, NULL);
266 assert(ret == -1 || ret > 0); /* select() cannot timeout */
273 TAILQ_FOREACH(casserv, &casper_services, cs_next) {
274 /* We handle only core services. */
275 if (!CSERVICE_IS_CORE(casserv))
277 for (sconn = service_connection_first(casserv->cs_service);
278 sconn != NULL; sconn = sconntmp) {
280 * Prepare for connection to be removed from
281 * the list on failure.
283 sconntmp = service_connection_next(sconn);
284 sock = service_connection_get_sock(sconn);
285 if (FD_ISSET(sock, &fds)) {
286 service_message(casserv->cs_service,