Changeset View
Changeset View
Standalone View
Standalone View
lib/libcasper/services/cap_jail/cap_jail.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2018 Stefan Grundmann | |||||
* All rights reserved. | |||||
* | |||||
* 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 AUTHORS 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 AUTHORS 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 <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
#include <sys/uio.h> | |||||
#include <sys/param.h> | |||||
#include <sys/jail.h> | |||||
#include <sys/cnv.h> | |||||
#include <sys/dnv.h> | |||||
#include <sys/nv.h> | |||||
#include <errno.h> | |||||
#include <stdio.h> | |||||
#include <stdarg.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <libcasper.h> | |||||
#include <libcasper_service.h> | |||||
#include "cap_jail.h" | |||||
static nvlist_t *iovs_to_nvl(struct iovec* iov, size_t niov, size_t *bs); | |||||
static int nvl_to_iovs(struct iovec* iov, size_t niov, const nvlist_t* nvl); | |||||
int | |||||
cap_jail_get(cap_channel_t *chan, struct iovec *iov, u_int niov, int flags) | |||||
{ | |||||
nvlist_t *nvl; | |||||
size_t bs; | |||||
int ret; | |||||
nvl = nvlist_create(NV_FLAG_NO_UNIQUE); | |||||
nvlist_add_string(nvl, "cmd", "jail_get"); | |||||
nvlist_add_number(nvl, "flags", flags); | |||||
nvlist_add_number(nvl, "niov", niov); | |||||
nvlist_move_nvlist(nvl, "iovs", iovs_to_nvl(iov, niov, &bs)); | |||||
nvlist_add_number(nvl, "bs", bs); | |||||
nvl = cap_xfer_nvlist(chan, nvl); | |||||
if (nvl == NULL) | |||||
return (-1); | |||||
if (nvlist_get_number(nvl, "error") != 0) { | |||||
errno = (int)nvlist_get_number(nvl, "error"); | |||||
nvlist_destroy(nvl); | |||||
return (-1); | |||||
} | |||||
ret = (int)nvlist_get_number(nvl, "ret"); | |||||
if (nvl_to_iovs(iov, niov, nvlist_get_nvlist(nvl, "iovs")) != 0) { | |||||
nvlist_destroy(nvl); | |||||
return (-1); | |||||
} | |||||
nvlist_destroy(nvl); | |||||
return (ret); | |||||
} | |||||
static int | |||||
nvl_to_iovs(struct iovec* iov, size_t niov, const nvlist_t* nvl) | |||||
{ | |||||
const char *name; | |||||
const void *val; | |||||
void *cookie; | |||||
size_t i, len; | |||||
int type; | |||||
cookie = NULL; | |||||
for (i=0; i < niov; i++) { | |||||
if ((name = nvlist_next(nvl, &type, &cookie)) == NULL) | |||||
return (-1); | |||||
switch (type) { | |||||
case NV_TYPE_NUMBER: | |||||
iov[i].iov_len = 0; | |||||
break; | |||||
case NV_TYPE_BINARY: | |||||
val = cnvlist_get_binary(cookie, &len); | |||||
if (len > iov[i].iov_len) | |||||
return (-1); | |||||
if (memcmp(iov[i].iov_base, val, len) != 0) | |||||
memcpy(iov[i].iov_base, val, len); | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Service functions. | |||||
*/ | |||||
static nvlist_t* | |||||
iovs_to_nvl(struct iovec* iov, size_t niov, size_t *bs) | |||||
{ | |||||
nvlist_t *nvl = nvlist_create(NV_FLAG_NO_UNIQUE); | |||||
size_t i, size; | |||||
size = 0; | |||||
for (i=0; i < niov; i++) { | |||||
if (iov[i].iov_len == 0) | |||||
nvlist_add_number(nvl, "NULL", 0); | |||||
else { | |||||
nvlist_add_binary(nvl, "iov", | |||||
iov[i].iov_base, iov[i].iov_len); | |||||
size += iov[i].iov_len; | |||||
} | |||||
} | |||||
if (bs != NULL) | |||||
*bs = size; | |||||
return (nvl); | |||||
} | |||||
static int | |||||
nvl_to_iovs_s(struct iovec* iov, size_t niov, const nvlist_t* nvl, | |||||
uint8_t* buf, size_t bs) | |||||
{ | |||||
const char *name; | |||||
const void *val; | |||||
void *cookie; | |||||
size_t i, len, offset; | |||||
int type; | |||||
offset = 0; | |||||
cookie = NULL; | |||||
for (i=0; i < niov; i++) { | |||||
if ((name = nvlist_next(nvl, &type, &cookie)) == NULL) | |||||
return (-1); | |||||
switch (type) { | |||||
case NV_TYPE_NUMBER: | |||||
iov[i].iov_base = 0; | |||||
iov[i].iov_len = 0; | |||||
break; | |||||
case NV_TYPE_BINARY: | |||||
val = cnvlist_get_binary(cookie, &len); | |||||
if (offset + len > bs) | |||||
return (-1); | |||||
memcpy(buf + offset, val, len); | |||||
iov[i].iov_base = buf + offset; | |||||
iov[i].iov_len = len; | |||||
offset += len; | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
jail_command(const char *cmd, const nvlist_t *limits __unused, | |||||
nvlist_t *nvlin, nvlist_t *nvlout) | |||||
oshogbo: We should also support limitng the jail_get command. | |||||
{ | |||||
const nvlist_t *nvliov; | |||||
struct iovec *iov; | |||||
uint8_t *buf; | |||||
size_t bs, niov; | |||||
int flags, ret; | |||||
if (strcmp(cmd, "jail_get") != 0) | |||||
return (EINVAL); | |||||
flags = (int)dnvlist_get_number(nvlin, "flags", 0); | |||||
niov = (size_t)dnvlist_get_number(nvlin, "niov", 0); | |||||
bs = (size_t)dnvlist_get_number(nvlin, "bs", 0); | |||||
nvliov = dnvlist_get_nvlist(nvlin, "iovs", NULL); | |||||
buf = (uint8_t*)alloca(bs); | |||||
iov = alloca(niov * sizeof(struct iovec)); | |||||
if (nvl_to_iovs_s(iov, niov, nvliov, buf, bs) < 0) | |||||
Done Inline Actionsthe alloca(3) calls here should be changed to malloc(3) and checked for failure since sg2342_googlemail.com: the alloca(3) calls here should be changed to malloc(3) and checked for failure since
bs and… | |||||
return (EINVAL); | |||||
if ((ret = jail_get(iov, niov, flags)) < 0) | |||||
return (errno); | |||||
nvlist_add_number(nvlout, "ret", ret); | |||||
nvlist_add_nvlist(nvlout, "iovs", iovs_to_nvl(iov, niov, NULL)); | |||||
return (0); | |||||
} | |||||
CREATE_SERVICE("system.jail", NULL, jail_command, | |||||
CASPER_SERVICE_NO_UNIQ_LIMITS); |
We should also support limitng the jail_get command.