Index: lib/libcasper/services/Makefile =================================================================== --- lib/libcasper/services/Makefile +++ lib/libcasper/services/Makefile @@ -4,6 +4,7 @@ SUBDIR= cap_dns SUBDIR+= cap_grp +SUBDIR+= cap_jail SUBDIR+= cap_pwd SUBDIR+= cap_random SUBDIR+= cap_sysctl Index: lib/libcasper/services/cap_jail/Makefile =================================================================== --- /dev/null +++ lib/libcasper/services/cap_jail/Makefile @@ -0,0 +1,28 @@ +# $FreeBSD$ + +SHLIBDIR?= /lib/casper + +.include + +PACKAGE=libcasper + +SHLIB_MAJOR= 1 +INCSDIR?= ${INCLUDEDIR}/casper + +.if ${MK_CASPER} != "no" +SHLIB= cap_jail + +SRCS= cap_jail.c +.endif + +INCS= cap_jail.h + +LIBADD= nv + +CFLAGS+=-I${.CURDIR} + +MAN+= cap_jail.3 + +MLINKS+=cap_jail.3 cap_jail_get.3 +MLINKS+=cap_jail.3 libcap_jail.3 +.include Index: lib/libcasper/services/cap_jail/cap_jail.h =================================================================== --- /dev/null +++ lib/libcasper/services/cap_jail/cap_jail.h @@ -0,0 +1,44 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _CAP_JAIL_H_ +#define _CAP_JAIL_H_ + +#ifdef HAVE_CASPER +#define WITH_CASPER +#endif + +#ifdef WITH_CASPER +int cap_jail_get(cap_channel_t *chan, struct iovec *iov, u_int niov, + int flags); +#else +#define cap_jail_get(chan, iov, niov, flags) \ + jail_get(iov, niov, flags); +#endif + +#endif /* !_CAP_JAIL_H_ */ Index: lib/libcasper/services/cap_jail/cap_jail.3 =================================================================== --- /dev/null +++ lib/libcasper/services/cap_jail/cap_jail.3 @@ -0,0 +1,111 @@ +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd May 11, 2018 +.Dt CAP_JAIL 3 +.Os +.Sh NAME +.Nm cap_jail +.Nd "library for getting jail information in capability mode" +.Sh LIBRARY +.Lb libcap_jail +.Sh SYNOPSIS +.In sys/uio.h +.In libcasper.h +.In casper/cap_jail.h +.Ft int +.Fn cap_jail_get "cap_channel_t *chan" " struct iovec *iov" " u_int niov" " int flags" +.Sh DESCRIPTION +The function +.Fn cap_jail_get +is equivalent to +.Xr jail_get 2 +except that the connection to the +.Nm system.jail +service needs to be provided. +.Sh EXAMPLES +The following example first opens a capability to casper and then uses this +capability to create the +.Nm system.jail +casper service and uses it to get the +.Dv jid +and +.Dv name +of the first jail +.Bd -literal +cap_channel_t *capcas, *capjail; +struct iovec iov[4]; +char name[256]; +int jid; + +capcas = cap_init(); +if (capcas == NULL) + err(1, "Unable to contact Casper"); + +/* Enter capability mode sandbox. */ +if (cap_enter() < 0 && errno != ENOSYS) + err(1, "Unable to enter capability mode"); + +/* Use Casper capability to create capability to the system.jail service. */ +capjail = cap_service_open(capcas, "system.jail"); +if (capjail == NULL) + err(1, "Unable to open system.jail service"); + +/* Close Casper capability, we don't need it anymore. */ +cap_close(capcas); + +/* prepare iovs */ +jid = 0; +iov[0].iov_base = __DECONST(char *, "lastjid"); +iov[0].iov_len = strlen(iov[0].iov_base) + 1; +iov[1].iov_base = &jid; +iov[1].iov_len = sizeof(jid); +iov[2].iov_base = __DECONST(char *, "name"); +iov[2].iov_len = strlen(iov[2].iov_base) + 1; +iov[3].iov_base = name; +iov[3].iov_len = sizeof(name); + +/* Fetch values */ +jid = cap_jail_get(capjail, iov, 4, 0); + +if (jid < 0 && errno != ENOENT) + err(1, "Unable to get jail information"); +if (jid > 0) + printf("jid = %d name = %s\\n", jid, name); +else + printf("no jails\\n"); + +cap_close(capjail); +.Ed +.Sh SEE ALSO +.Xr cap_enter 2 , +.Xr jail_get 2 , +.Xr capsicum 4 , +.Sh AUTHORS +The +.Nm cap_jail +service and this manual page were written by +.An Stefan Grundmann Index: lib/libcasper/services/cap_jail/cap_jail.c =================================================================== --- /dev/null +++ lib/libcasper/services/cap_jail/cap_jail.c @@ -0,0 +1,227 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#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) +{ + const nvlist_t *nvliov; + struct iovec *iov; + uint8_t *buf; + size_t bs, niov; + int flags, r, 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); + + r = 0; + buf = NULL; + if ((iov = malloc(niov * sizeof(struct iovec))) == NULL || + (buf = malloc(bs)) == NULL) { + r = errno; + goto error; + } + if (nvl_to_iovs_s(iov, niov, nvliov, buf, bs) < 0) { + r = EINVAL; + goto error; + } + if ((ret = jail_get(iov, niov, flags)) < 0) { + r = errno; + goto error; + } + nvlist_add_number(nvlout, "ret", ret); + nvlist_add_nvlist(nvlout, "iovs", iovs_to_nvl(iov, niov, NULL)); + error: + free(buf); + free(iov); + return (r); +} + +CREATE_SERVICE("system.jail", NULL, jail_command, + CASPER_SERVICE_NO_UNIQ_LIMITS); Index: lib/libcasper/services/cap_sysctl/cap_sysctl.h =================================================================== --- lib/libcasper/services/cap_sysctl/cap_sysctl.h +++ lib/libcasper/services/cap_sysctl/cap_sysctl.h @@ -44,9 +44,13 @@ #ifdef WITH_CASPER int cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); +int cap_sysctl(cap_channel_t *chan, const int *name, u_int namelen, + void *oldp, size_t *oldlenp, const void *newp, size_t newlen); #else #define cap_sysctlbyname(chan, name, oldp, oldlenp, newp, newlen) \ sysctlbyname(name, oldp, oldlenp, newp, newlen) +#define cap_sysctl(chan, name, namelen, oldp, oldlenp, newp, newlen) \ + sysctl(name, namelen, oldp, oldlenp, newp, newlen) #endif #endif /* !_CAP_SYSCTL_H_ */ Index: lib/libcasper/services/cap_sysctl/cap_sysctl.3 =================================================================== --- lib/libcasper/services/cap_sysctl/cap_sysctl.3 +++ lib/libcasper/services/cap_sysctl/cap_sysctl.3 @@ -38,11 +38,17 @@ .In casper/cap_sysctl.h .Ft int .Fn cap_sysctlbyname "cap_channel_t *chan" " const char *name" " void *oldp" " size_t *oldlenp" " const void *newp" " size_t newlen" +.Ft int +.Fn cap_sysctl "cap_channel_t *chan" " int *name" " u_int namelen" " void *oldp" " size_t *oldlenp" " const void *newp" " size_t newlen" .Sh DESCRIPTION -The function +The functions .Fn cap_sysctlbyname -is equivalent to +and +.Fn cap_sysctl +are equivalent to .Xr sysctlbyname 3 +and +.Xr sysctl 3 except that the connection to the .Nm system.sysctl service needs to be provided. @@ -129,6 +135,7 @@ .Sh SEE ALSO .Xr cap_enter 2 , .Xr err 3 , +.Xr sysctl 3 , .Xr sysctlbyname 3 , .Xr capsicum 4 , .Xr nv 9 Index: lib/libcasper/services/cap_sysctl/cap_sysctl.c =================================================================== --- lib/libcasper/services/cap_sysctl/cap_sysctl.c +++ lib/libcasper/services/cap_sysctl/cap_sysctl.c @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -46,6 +47,8 @@ #include "cap_sysctl.h" +static nvlist_t *sysctl_mibs = NULL; + int cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) @@ -93,6 +96,53 @@ return (0); } +int +cap_sysctl(cap_channel_t *chan, const int *name, u_int namelen, + void *oldp, size_t *oldlenp, const void *newp, size_t newlen) +{ + nvlist_t *nvl; + const uint8_t *retoldp; + size_t oldlen; + uint8_t operation; + + operation = 0; + if (oldp != NULL) + operation |= CAP_SYSCTL_READ; + if (newp != NULL) + operation |= CAP_SYSCTL_WRITE; + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "cmd", "sysctl"); + nvlist_add_binary(nvl, "name", (const void*)name, namelen * sizeof(int)); + nvlist_add_number(nvl, "operation", (uint64_t)operation); + if (oldp == NULL && oldlenp != NULL) + nvlist_add_null(nvl, "justsize"); + else if (oldlenp != NULL) + nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp); + if (newp != NULL) + nvlist_add_binary(nvl, "newp", newp, newlen); + 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); + } + + if (oldp == NULL && oldlenp != NULL) { + *oldlenp = (size_t)nvlist_get_number(nvl, "oldlen"); + } else if (oldp != NULL) { + retoldp = nvlist_get_binary(nvl, "oldp", &oldlen); + memcpy(oldp, retoldp, oldlen); + if (oldlenp != NULL) + *oldlenp = oldlen; + } + nvlist_destroy(nvl); + + return (0); +} + /* * Service functions. */ @@ -110,7 +160,7 @@ if (nvlist_error(nvl) != 0) return (nvlist_error(nvl)); -#define HAS_NAME 0x01 +#define HAS_NAME_OR_MIB 0x01 #define HAS_OPERATION 0x02 fields = 0; @@ -118,12 +168,12 @@ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) { /* We accept only one 'name' and one 'operation' in nvl. */ if (strcmp(name, "name") == 0) { - if (type != NV_TYPE_STRING) + if (type != NV_TYPE_STRING && type != NV_TYPE_BINARY) return (EINVAL); /* Only one 'name' can be present. */ - if ((fields & HAS_NAME) != 0) + if ((fields & HAS_NAME_OR_MIB) != 0) return (EINVAL); - fields |= HAS_NAME; + fields |= HAS_NAME_OR_MIB; } else if (strcmp(name, "operation") == 0) { uint64_t operation; @@ -150,15 +200,55 @@ } /* Both fields has to be there. */ - if (fields != (HAS_NAME | HAS_OPERATION)) + if (fields != (HAS_NAME_OR_MIB | HAS_OPERATION)) return (EINVAL); #undef HAS_OPERATION -#undef HAS_NAME +#undef HAS_NAME_OR_MIB return (0); } +static bool +sysctl_allowed_mib(const nvlist_t *limits, const int *chmib, size_t chmiblen, + uint64_t choperation) +{ + uint64_t operation; + const char *name; + const int *mib; + size_t len; + size_t miblen; + void *cookie; + int type; + + if (limits == NULL) + return (true); + + cookie = NULL; + while ((name = nvlist_next(limits, &type, &cookie)) != NULL) { + assert(type == NV_TYPE_NUMBER); + + operation = nvlist_get_number(limits, name); + if ((operation & choperation) != choperation) + continue; + mib = (const int*)dnvlist_get_binary(sysctl_mibs, name, &len, + NULL, 0); + miblen = len / sizeof(int); + if ((operation & CAP_SYSCTL_RECURSIVE) == 0) { + if (miblen != chmiblen || + memcmp(mib, chmib, miblen) != 0) + continue; + } else + if (miblen > chmiblen || + memcmp(mib, chmib, miblen) != 0) + continue; + + return (true); + } + + return (false); +} + static bool sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation) { @@ -197,6 +287,26 @@ return (false); } +static void +sysctl_lookup_mibs(const nvlist_t *limits) +{ + nvlist_t *mibs; + int mib[CTL_MAXNAME]; + const char *name; + void *cookie; + size_t miblen; + int type; + + mibs = nvlist_create(0); + cookie = NULL; + while ((name = nvlist_next(limits, &type, &cookie)) != NULL) + if (sysctlnametomib(name, mib, &miblen) == 0) + nvlist_add_binary(mibs, name, mib, miblen * sizeof(int)); + + nvlist_destroy(sysctl_mibs); + sysctl_mibs = mibs; +} + static int sysctl_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) { @@ -218,6 +328,7 @@ return (ENOTCAPABLE); } + sysctl_lookup_mibs(newlimits); return (0); } @@ -227,8 +338,10 @@ { const char *name; const void *newp; + const int *mib; void *oldp; uint64_t operation; + size_t miblen; size_t oldlen, newlen; size_t *oldlenp; int error; @@ -239,11 +352,18 @@ if (error != 0) return (error); - name = nvlist_get_string(nvlin, "name"); + mib = NULL; operation = nvlist_get_number(nvlin, "operation"); - if (!sysctl_allowed(limits, name, operation)) - return (ENOTCAPABLE); - + if (nvlist_exists_binary(nvlin, "name")) { + mib = (const int*)nvlist_get_binary(nvlin, "name", &miblen); + miblen = miblen / sizeof(int); + if (!sysctl_allowed_mib(limits, mib, miblen, operation)) + return (ENOTCAPABLE); + } else { + name = nvlist_get_string(nvlin, "name"); + if (!sysctl_allowed(limits, name, operation)) + return (ENOTCAPABLE); + } if ((operation & CAP_SYSCTL_WRITE) != 0) { if (!nvlist_exists_binary(nvlin, "newp")) return (EINVAL); @@ -276,10 +396,18 @@ oldlenp = NULL; } - if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) { - error = errno; - free(oldp); - return (error); + if (mib != NULL) { + if (sysctl(mib, miblen, oldp, oldlenp, newp, newlen) == -1) { + error = errno; + free(oldp); + return(error); + } + } else { + if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) { + error = errno; + free(oldp); + return (error); + } } if ((operation & CAP_SYSCTL_READ) != 0) { Index: lib/libcasper/services/cap_sysctl/tests/sysctl_test.c =================================================================== --- lib/libcasper/services/cap_sysctl/tests/sysctl_test.c +++ lib/libcasper/services/cap_sysctl/tests/sysctl_test.c @@ -97,9 +97,13 @@ unsigned int result; int oldvalue, newvalue; size_t oldsize; - + int mib0[CTL_MAXNAME], mib1[CTL_MAXNAME]; + size_t miblen0, miblen1; result = 0; + sysctlnametomib(SYSCTL0_NAME, mib0, &miblen0); + sysctlnametomib(SYSCTL1_NAME, mib1, &miblen1); + oldsize = sizeof(oldvalue); if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, &oldvalue, &oldsize, NULL, 0) == 0) { @@ -108,7 +112,7 @@ } newvalue = 123; - if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, NULL, NULL, &newvalue, + if (cap_sysctl(capsysctl, mib0, miblen0, NULL, NULL, &newvalue, sizeof(newvalue)) == 0) { result |= SYSCTL0_WRITE; } @@ -140,7 +144,7 @@ } oldsize = sizeof(oldvalue); - if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, &oldvalue, &oldsize, + if (cap_sysctl(capsysctl, mib1, miblen1, &oldvalue, &oldsize, NULL, 0) == 0) { if (oldsize == sizeof(oldvalue)) result |= SYSCTL1_READ0; Index: lib/libjail/Makefile =================================================================== --- lib/libjail/Makefile +++ lib/libjail/Makefile @@ -1,5 +1,7 @@ # $FreeBSD$ +.include + PACKAGE=lib${LIB} LIB= jail SHLIBDIR?= /lib @@ -27,4 +29,9 @@ CFLAGS+=-I${.CURDIR} +.if ${MK_CASPER} != "no" && !defined(RESCUE) +LIBADD= casper cap_sysctl cap_jail +CFLAGS+=-DWITH_CASPER +.endif + .include Index: lib/libjail/jail.h =================================================================== --- lib/libjail/jail.h +++ lib/libjail/jail.h @@ -64,6 +64,7 @@ extern int jailparam_get(struct jailparam *jp, unsigned njp, int flags); extern char *jailparam_export(struct jailparam *jp); extern void jailparam_free(struct jailparam *jp, unsigned njp); +extern int jail_cap_init(void); __END_DECLS #endif /* _JAIL_H */ Index: lib/libjail/jail.c =================================================================== --- lib/libjail/jail.c +++ lib/libjail/jail.c @@ -39,6 +39,13 @@ #include #include +#ifdef WITH_CASPER +# include +# include +# include +# include +#endif + #include #include #include @@ -69,6 +76,90 @@ static const char *bool_values[] = { "false", "true" }; static const char *jailsys_values[] = { "disable", "new", "inherit" }; +#ifdef WITH_CASPER +static cap_channel_t *cap_h_sysctl = NULL; +static cap_channel_t *cap_h_jail_get = NULL; + +static int +jail_cap_init_sysclt(const cap_channel_t *capcas) +{ + nvlist_t *limits; + + cap_h_sysctl = cap_service_open(capcas, "system.sysctl"); + if (cap_h_sysctl == NULL) + return (-1); + + limits = nvlist_create(0); + nvlist_add_number(limits, __DECONST(char *, SJPARAM), + CAP_SYSCTL_READ|CAP_SYSCTL_RECURSIVE); + + return (cap_limit_set(cap_h_sysctl, limits)); +} + +static int +jail_cap_init_jail(const cap_channel_t *capcas) +{ + + cap_h_jail_get = cap_service_open(capcas, "system.jail"); + if (cap_h_jail_get == NULL) + return (-1); + return (0); +} + +int +jail_cap_init() +{ + cap_channel_t *capcas; + int r; + + capcas = cap_init(); + if (capcas == NULL) + return (-1); + + r = jail_cap_init_sysclt(capcas); + if (r == 0) + r = jail_cap_init_jail(capcas); + + cap_close(capcas); + return (r); +} + +static int +hot_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldplenp, + const void *newp, size_t newlen) +{ + int r; + + r = sysctl(name, namelen, oldp, oldplenp, newp, newlen); + if (r < 0 && errno == EPERM && cap_h_sysctl != NULL) + r = cap_sysctl(cap_h_sysctl, name, namelen, oldp, oldplenp, + newp, newlen); + return (r); +} + +static int +hot_jail_get(struct iovec *iov, u_int niov, int flags) +{ + int r; + + r = jail_get(iov, niov, flags); + if (r < 0 && errno == ECAPMODE && cap_h_jail_get != NULL) + r = cap_jail_get(cap_h_jail_get, iov, niov, flags); + + return (r); +} + +#define sysctl(name, namelen, oldp, oldlenp, newp, newlen) \ + hot_sysctl(name, namelen, oldp, oldlenp, newp, newlen) +#define jail_get(iovec, iov, niov) \ + hot_jail_get(iovec, iov, niov) +#else /* WITH_CASPER */ +int +jail_cap_init() { + return (0); +} +#endif /* !WITH_CASPER */ + /* * Import a null-terminated parameter list and set a jail with the flags Index: rescue/librescue/Makefile =================================================================== --- rescue/librescue/Makefile +++ rescue/librescue/Makefile @@ -16,13 +16,20 @@ .PATH: ${SRCTOP}/lib/libc/gen \ ${SRCTOP}/lib/libc/net \ ${SRCTOP}/lib/libc/stdlib \ - ${SRCTOP}/lib/libutil + ${SRCTOP}/lib/libutil \ + ${SRCTOP}/lib/libjail LIB= rescue INTERNALLIB= # Don't install this library SRCS= exec.c getusershell.c login_class.c popen.c rcmdsh.c \ sysctl.c system.c +# If libjail is configured to use libcasper, jail.c must be +# recompiled. +.if ${MK_CASPER} != "no" +SRCS+= jail.c +.endif + CFLAGS+= -DRESCUE # Flags copied from src/lib/libc and src/lib/libutil # libc/db/Makefile.inc Index: share/mk/src.libnames.mk =================================================================== --- share/mk/src.libnames.mk +++ share/mk/src.libnames.mk @@ -75,6 +75,7 @@ casper \ cap_dns \ cap_grp \ + cap_jail \ cap_pwd \ cap_random \ cap_sysctl \ @@ -237,6 +238,7 @@ _DP_casper= nv _DP_cap_dns= nv _DP_cap_grp= nv +_DP_cap_jail= nv _DP_cap_pwd= nv _DP_cap_random= nv _DP_cap_sysctl= nv @@ -269,6 +271,9 @@ _DP_magic= z _DP_mt= sbuf bsdxml _DP_ldns= crypto +.if ${MK_CASPER} != "no" +_DP_jail+= casper cap_sysctl cap_jail +.endif .if ${MK_OPENSSL} != "no" _DP_fetch= ssl crypto .else @@ -535,6 +540,7 @@ LIBCASPERDIR= ${OBJTOP}/lib/libcasper/libcasper LIBCAP_DNSDIR= ${OBJTOP}/lib/libcasper/services/cap_dns LIBCAP_GRPDIR= ${OBJTOP}/lib/libcasper/services/cap_grp +LIBCAP_JAILDIR= ${OBJTOP}/lib/libcasper/servicec/cap_jail LIBCAP_PWDDIR= ${OBJTOP}/lib/libcasper/services/cap_pwd LIBCAP_RANDOMDIR= ${OBJTOP}/lib/libcasper/services/cap_random LIBCAP_SYSCTLDIR= ${OBJTOP}/lib/libcasper/services/cap_sysctl Index: usr.sbin/jls/jls.c =================================================================== --- usr.sbin/jls/jls.c +++ usr.sbin/jls/jls.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,11 @@ char *dot, *ep, *jname, *pname; int c, i, jflags, jid, lastjid, pflags, spc; + caph_cache_catpages(); + if (jail_cap_init() < 0 || caph_limit_stdio() < 0 || + caph_enter_casper() < 0) + err(1, "capsicum"); + argc = xo_parse_args(argc, argv); if (argc < 0) exit(1);