Index: lib/libcasper/services/cap_exec/Makefile =================================================================== --- /dev/null +++ lib/libcasper/services/cap_exec/Makefile @@ -0,0 +1,22 @@ +# $FreeBSD$ + +SHLIBDIR?= /lib/casper + +.include + +PACKAGE= runtime + +SHLIB_MAJOR= 1 +INCSDIR?= ${INCLUDEDIR}/casper + +.if ${MK_CASPER} != "no" +SHLIB= cap_exec + +SRCS= cap_exec.c +.endif + +LIBADD= nv + +CFLAGS+=-I${.CURDIR} + +.include Index: lib/libcasper/services/cap_exec/cap_exec.h =================================================================== --- /dev/null +++ lib/libcasper/services/cap_exec/cap_exec.h @@ -0,0 +1,40 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CAP_EXEC_H_ +#define _CAP_EXEC_H_ + +#include + +int cap_exec_init(cap_channel_t *chan, int count, const char **arr); +FILE *cap_exec_open(cap_channel_t *chan, const char *command, const char *mode); +int cap_exec_close(FILE *file); + +#endif Index: lib/libcasper/services/cap_exec/cap_exec.c =================================================================== --- /dev/null +++ lib/libcasper/services/cap_exec/cap_exec.c @@ -0,0 +1,195 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "cap_exec.h" + +struct PROCESS +{ + LIST_ENTRY(PROCESS) files; + int fd, pd; +}; + +static LIST_HEAD(PROCESSES, PROCESS) processes; +static int kq; + +int +cap_exec_init(cap_channel_t *chan, int count, const char **arr) +{ + nvlist_t *allowed_programs; + int i; + + allowed_programs = nvlist_create(0); + for(i = 0; i < count; i++) { + nvlist_add_null(allowed_programs, arr[i]); + } + if (cap_limit_set(chan, allowed_programs) < 0) { + return (-1); + } + + LIST_INIT(&processes); + if ((kq = kqueue()) == -1) { + return (-1); + } + return (0); +} + +FILE * +cap_exec_open(cap_channel_t *chan, const char *command, const char *mode) +{ + nvlist_t *nvl; + int error; + int fd, pd; + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "cmd", "exec"); + nvlist_add_string(nvl, "command", command); + nvl = cap_xfer_nvlist(chan, nvl); + if (nvl == NULL) { + return NULL; + } + error = (int)dnvlist_get_number(nvl, "error", 0); + fd = dnvlist_take_descriptor(nvl, "filedesc", -1); + pd = dnvlist_take_descriptor(nvl, "procdesc", -1); + nvlist_destroy(nvl); + + struct PROCESS *item = malloc(sizeof(struct PROCESS)); + item->fd = fd; + item->pd = pd; + LIST_INSERT_HEAD(&processes, item, files); + + if (error != 0) { + if (fd != -1) { + close(fd); + fd = -1; + } + errno = error; + } + return (fdopen(fd, mode)); +} + +int +cap_exec_close(FILE* file) +{ + int ret; + struct PROCESS *item, *temp; + struct kevent event; + int fd = fileno(file); + + ret = -1; + LIST_FOREACH_SAFE(item, &processes, files, temp) { + if (item && (item->fd == fd)) { + EV_SET(&event, item->pd, EVFILT_PROCDESC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL); + + ret = fclose(file); + LIST_REMOVE(item, files); + free(item); + + kevent(kq, &event, 1, &event, 1, NULL); + break; + } + } + return (ret); +} + +static int +exec_limits(const nvlist_t *oldlimits, const nvlist_t *newlimits) +{ + + /* only allow limit to be set once */ + if (oldlimits != NULL) + return (ENOTCAPABLE); + (void) newlimits; + return (0); +} + +static int +exec_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, + nvlist_t *nvlout) +{ + const char *command; + char *prog; + int fd[2]; + int pd, pid; + bool allowed; + + if (strcmp(cmd, "exec") != 0) + return (EINVAL); + if (limits == NULL) + return (ENOTCAPABLE); + + command = nvlist_get_string(nvlin, "command"); + + /* parse executable */ + char buf[strlen(command) + 1]; + strcpy(buf, command); + prog = strtok(buf, " "); + + /* Check if program in allowed set */ + allowed = nvlist_exists_null(limits, prog); + if (!allowed) + return (ENOTCAPABLE); + + if (pipe(fd) == -1) + return (-1); + + pid = pdfork(&pd, 0); + if (pid == -1) { + return (ENOTCAPABLE); + } else if (pid == 0) { + close(fd[1]); + dup2(fd[0], STDIN_FILENO); + dup2(fd[0], STDOUT_FILENO); + close(fd[0]); + execlp("sh", "sh", "-c", command, NULL); + } else { + close(fd[0]); + nvlist_move_descriptor(nvlout, "filedesc", fd[1]); + nvlist_move_descriptor(nvlout, "procdesc", pd); + } + return (0); +} + +CREATE_SERVICE("system.exec", exec_limits, exec_command, 0);