Date: Mon, 13 May 2019 17:49:55 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r347534 - in head: . lib/libcasper/services/cap_sysctl lib/libcasper/services/cap_sysctl/tests Message-ID: <201905131749.x4DHnt1M020569@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Mon May 13 17:49:54 2019 New Revision: 347534 URL: https://svnweb.freebsd.org/changeset/base/347534 Log: Add cap_sysctl(3) and cap_sysctlnametomib(3). These complement cap_sysctlbyname(3) to provide a drop-in replacement for the corresponding libc functions. Also revise the libcap_sysctl limit interface to provide access to sysctls by MIB, and to avoid direct manipulation of nvlists by the caller. Reviewed by: oshogbo Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D17854 Modified: head/ObsoleteFiles.inc head/lib/libcasper/services/cap_sysctl/Makefile head/lib/libcasper/services/cap_sysctl/cap_sysctl.3 head/lib/libcasper/services/cap_sysctl/cap_sysctl.c head/lib/libcasper/services/cap_sysctl/cap_sysctl.h head/lib/libcasper/services/cap_sysctl/tests/sysctl_test.c Modified: head/ObsoleteFiles.inc ============================================================================== --- head/ObsoleteFiles.inc Mon May 13 17:48:16 2019 (r347533) +++ head/ObsoleteFiles.inc Mon May 13 17:49:54 2019 (r347534) @@ -38,6 +38,8 @@ # xargs -n1 | sort | uniq -d; # done +# 20190513: libcap_sysctl interface change +OLD_FILES+=lib/casper/libcap_sysctl.1 # 20190509: tests/sys/opencrypto requires the net/py-dpkt package. OLD_FILES+=usr/tests/sys/opencrypto/dpkt.py OLD_FILES+=usr/tests/sys/opencrypto/dpkt.pyc Modified: head/lib/libcasper/services/cap_sysctl/Makefile ============================================================================== --- head/lib/libcasper/services/cap_sysctl/Makefile Mon May 13 17:48:16 2019 (r347533) +++ head/lib/libcasper/services/cap_sysctl/Makefile Mon May 13 17:49:54 2019 (r347534) @@ -6,7 +6,7 @@ SHLIBDIR?= /lib/casper PACKAGE=libcasper -SHLIB_MAJOR= 1 +SHLIB_MAJOR= 2 INCSDIR?= ${INCLUDEDIR}/casper .if ${MK_CASPER} != "no" @@ -25,8 +25,12 @@ HAS_TESTS= SUBDIR.${MK_TESTS}+= tests MAN+= cap_sysctl.3 - -MLINKS+=cap_sysctl.3 libcap_sysctl.3 -MLINKS+=cap_sysctl.3 cap_sysctlbyname.3 +MLINKS+=cap_sysctl.3 libcap_sysctl.3 \ + cap_sysctl.3 cap_sysctlbyname.3 \ + cap_sysctl.3 cap_nametomib.3 \ + cap_sysctl.3 cap_sysctl_limit_init.3 \ + cap_sysctl.3 cap_sysctl_limit_mib.3 \ + cap_sysctl.3 cap_sysctl_limit_name.3 \ + cap_sysctl.3 cap_sysctl_limit.3 .include <bsd.lib.mk> Modified: head/lib/libcasper/services/cap_sysctl/cap_sysctl.3 ============================================================================== --- head/lib/libcasper/services/cap_sysctl/cap_sysctl.3 Mon May 13 17:48:16 2019 (r347533) +++ head/lib/libcasper/services/cap_sysctl/cap_sysctl.3 Mon May 13 17:49:54 2019 (r347534) @@ -24,72 +24,113 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2018 +.Dd May 13, 2019 .Dt CAP_SYSCTL 3 .Os .Sh NAME -.Nm cap_sysctlbyname +.Nm cap_sysctl .Nd "library for getting or setting system information in capability mode" .Sh LIBRARY .Lb libcap_sysctl .Sh SYNOPSIS -.In sys/nv.h .In libcasper.h .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" +.Fn cap_sysctl "cap_channel_t *chan" "const int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen" +.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_sysctlnametomib "cap_channel_t *chan" "const char *name" "int *mibp" "size_t *sizep" +.Ft void * +.Fn cap_sysctl_limit_init "cap_channel_t *chan" +.Ft void * +.Fn cap_sysctl_limit_name "void *limit" "const char *name" "int flags" +.Ft void * +.Fn cap_sysctl_limit_mib "void *limit" "int *mibp" "u_int miblen" "int flags" +.Ft int +.Fn cap_sysctl_limit "void *limit" .Sh DESCRIPTION -The function +The +.Fn cap_sysctl , .Fn cap_sysctlbyname -is equivalent to +and +.Fn cap_sysctlnametomib +functions are equivalent to +.Xr sysctl 3 , .Xr sysctlbyname 3 -except that the connection to the -.Nm system.sysctl -service needs to be provided. +and +.Xr sysctlnametomib 3 , +except that they are implemented by the +.Ql system.sysctl +.Xr libcasper 3 +service and require a corresponding +.Xr libcasper 3 +capability. .Sh LIMITS -The service can be limited using -.Xr cap_limit_set 3 -function. +By default, the +.Nm +capability provides unrestricted access to the sysctl namespace. +Applications typically only require access to a small number of sysctl +variables; the +.Fn cap_sysctl_limit +interface can be used to restrict the sysctls that can be accessed using +the +.Nm +capability. +.Fn cap_sysctl_limit_init +returns an opaque limit handle used to store a list of permitted sysctls +and access rights. +Rights are encoded using the following flags: +.Pp +.Bd -literal -offset indent -compact +CAP_SYSCTL_READ allow reads of the sysctl variable +CAP_SYSCTL_WRITE allow writes of the sysctl variable +CAP_SYSCTL_RDWR allow reads and writes of the sysctl variable +CAP_RECURSIVE permit access to any child of the sysctl variable +.Ed +.Pp The -.Xr nvlist 9 -for that function can contain the following values and types: -.Bl -ohang -offset indent -.It ( NV_TYPE_NUMBER ) -The name of the element with type number will be treated as the limited sysctl. -The value of the element will describe the access rights for given sysctl. -There are four different rights +.Fn cap_sysctl_limit_name +function adds the sysctl identified by +.Ar name +to the limit list, and +.Fn cap_sysctl_limit_mib +function adds the sysctl identified by +.Ar mibp +to the limit list. +The access rights for the sysctl are specified in the +.Ar flags +parameter; at least one of .Dv CAP_SYSCTL_READ , -.Dv CAP_SYSCTL_WRITE , -.Dv CAP_SYSCTL_RDWR , +.Dv CAP_SYSCTL_WRITE and -.Dv CAP_SYSCTL_RECURSIVE . -The -.Dv CAP_SYSCTL_READ -flag allows to fetch the value of a given sysctl. -The -.Dv CAP_SYSCTL_WIRTE -flag allows to override the value of a given sysctl. -The .Dv CAP_SYSCTL_RDWR -is combination of the -.Dv CAP_SYSCTL_WIRTE -and -.Dv CAP_SYSCTL_READ -and allows to read and write the value of a given sysctl. -The -.Dv CAP_SYSCTL_RECURSIVE -allows access to all children of a given sysctl. -This right must be combined with at least one other right. +must be specified. +.Fn cap_sysctl_limit +applies a set of sysctl limits to the capability, denying access to sysctl +variables not belonging to the set. +.Pp +Once a set of limits is applied, subsequent calls to +.Fn cap_sysctl_limit +will fail unless the new set is a subset of the current set. +.Pp +.Fn cap_sysctlnametomib +will succeed so long as the named sysctl variable is present in the limit set, +regardless of its access rights. +When a sysctl variable name is added to a limit set, its MIB identifier is +automatically added to the set. .Sh EXAMPLES -The following example first opens a capability to casper and then uses this +The following example first opens a capability to casper, uses this capability to create the .Nm system.sysctl -casper service and uses it to get the value of +casper service, and then uses the +.Nm +capability to get the value of .Dv kern.trap_enotcap . .Bd -literal cap_channel_t *capcas, *capsysctl; const char *name = "kern.trap_enotcap"; -nvlist_t *limits; +void *limit; int value; size_t size; @@ -111,11 +152,11 @@ if (capsysctl == NULL) cap_close(capcas); /* Create limit for one MIB with read access only. */ -limits = nvlist_create(0); -nvlist_add_number(limits, name, CAP_SYSCTL_READ); +limit = cap_sysctl_limit_init(capsysctl); +(void)cap_sysctl_limit_name(limit, name, CAP_SYSCTL_READ); /* Limit system.sysctl. */ -if (cap_limit_set(capsysctl, limits) < 0) +if (cap_sysctl_limit(limit) < 0) err(1, "Unable to set limits"); /* Fetch value. */ @@ -129,7 +170,9 @@ cap_close(capsysctl); .Sh SEE ALSO .Xr cap_enter 2 , .Xr err 3 , +.Xr sysctl 3 , .Xr sysctlbyname 3 , +.Xr sysctlnametomib 3 , .Xr capsicum 4 , .Xr nv 9 .Sh AUTHORS Modified: head/lib/libcasper/services/cap_sysctl/cap_sysctl.c ============================================================================== --- head/lib/libcasper/services/cap_sysctl/cap_sysctl.c Mon May 13 17:48:16 2019 (r347533) +++ head/lib/libcasper/services/cap_sysctl/cap_sysctl.c Mon May 13 17:49:54 2019 (r347534) @@ -1,12 +1,15 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2013, 2018 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * + * Portions of this software were developed by Mark Johnston + * 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: @@ -32,9 +35,11 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/types.h> -#include <sys/sysctl.h> +#include <sys/param.h> +#include <sys/cnv.h> +#include <sys/dnv.h> #include <sys/nv.h> +#include <sys/sysctl.h> #include <assert.h> #include <errno.h> @@ -46,24 +51,117 @@ __FBSDID("$FreeBSD$"); #include "cap_sysctl.h" +/* + * Limit interface. + */ + +struct cap_sysctl_limit { + cap_channel_t *chan; + nvlist_t *nv; +}; + +cap_sysctl_limit_t * +cap_sysctl_limit_init(cap_channel_t *chan) +{ + cap_sysctl_limit_t *limit; + int error; + + limit = malloc(sizeof(*limit)); + if (limit != NULL) { + limit->chan = chan; + limit->nv = nvlist_create(NV_FLAG_NO_UNIQUE); + if (limit->nv == NULL) { + error = errno; + free(limit); + limit = NULL; + errno = error; + } + } + return (limit); +} + +cap_sysctl_limit_t * +cap_sysctl_limit_name(cap_sysctl_limit_t *limit, const char *name, int flags) +{ + nvlist_t *lnv; + size_t mibsz; + int error, mib[CTL_MAXNAME]; + + lnv = nvlist_create(0); + if (lnv == NULL) { + error = errno; + if (limit->nv != NULL) + nvlist_destroy(limit->nv); + free(limit); + errno = error; + return (NULL); + } + nvlist_add_string(lnv, "name", name); + nvlist_add_number(lnv, "operation", flags); + + mibsz = nitems(mib); + error = cap_sysctlnametomib(limit->chan, name, mib, &mibsz); + if (error == 0) + nvlist_add_binary(lnv, "mib", mib, mibsz * sizeof(int)); + + nvlist_move_nvlist(limit->nv, "limit", lnv); + return (limit); +} + +cap_sysctl_limit_t * +cap_sysctl_limit_mib(cap_sysctl_limit_t *limit, int *mibp, u_int miblen, + int flags) +{ + nvlist_t *lnv; + int error; + + lnv = nvlist_create(0); + if (lnv == NULL) { + error = errno; + if (limit->nv != NULL) + nvlist_destroy(limit->nv); + free(limit); + errno = error; + return (NULL); + } + nvlist_add_binary(lnv, "mib", mibp, miblen * sizeof(int)); + nvlist_add_number(lnv, "operation", flags); + nvlist_add_nvlist(limit->nv, "limit", lnv); + return (limit); +} + int -cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp, - size_t *oldlenp, const void *newp, size_t newlen) +cap_sysctl_limit(cap_sysctl_limit_t *limit) { - nvlist_t *nvl; + cap_channel_t *chan; + nvlist_t *lnv; + + chan = limit->chan; + lnv = limit->nv; + free(limit); + + /* cap_limit_set(3) will always free the nvlist. */ + return (cap_limit_set(chan, lnv)); +} + +/* + * Service interface. + */ + +static int +do_sysctl(cap_channel_t *chan, nvlist_t *nvl, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) +{ const uint8_t *retoldp; - uint8_t operation; size_t oldlen; + int error; + uint8_t operation; operation = 0; - if (oldp != NULL) + if (oldlenp != NULL) operation |= CAP_SYSCTL_READ; if (newp != NULL) operation |= CAP_SYSCTL_WRITE; - - nvl = nvlist_create(0); - nvlist_add_string(nvl, "cmd", "sysctl"); - nvlist_add_string(nvl, "name", name); nvlist_add_number(nvl, "operation", (uint64_t)operation); if (oldp == NULL && oldlenp != NULL) nvlist_add_null(nvl, "justsize"); @@ -71,12 +169,14 @@ cap_sysctlbyname(cap_channel_t *chan, const char *name 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"); + error = (int)dnvlist_get_number(nvl, "error", 0); + if (error != 0) { nvlist_destroy(nvl); + errno = error; return (-1); } @@ -88,21 +188,87 @@ cap_sysctlbyname(cap_channel_t *chan, const char *name if (oldlenp != NULL) *oldlenp = oldlen; } + nvlist_destroy(nvl); 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 *req; + + req = nvlist_create(0); + nvlist_add_string(req, "cmd", "sysctl"); + nvlist_add_binary(req, "mib", name, (size_t)namelen * sizeof(int)); + return (do_sysctl(chan, req, oldp, oldlenp, newp, newlen)); +} + +int +cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen) +{ + nvlist_t *req; + + req = nvlist_create(0); + nvlist_add_string(req, "cmd", "sysctlbyname"); + nvlist_add_string(req, "name", name); + return (do_sysctl(chan, req, oldp, oldlenp, newp, newlen)); +} + +int +cap_sysctlnametomib(cap_channel_t *chan, const char *name, int *mibp, + size_t *sizep) +{ + nvlist_t *req; + const void *mib; + size_t mibsz; + int error; + + req = nvlist_create(0); + nvlist_add_string(req, "cmd", "sysctlnametomib"); + nvlist_add_string(req, "name", name); + nvlist_add_number(req, "operation", 0); + nvlist_add_number(req, "size", (uint64_t)*sizep); + + req = cap_xfer_nvlist(chan, req); + if (req == NULL) + return (-1); + error = (int)dnvlist_get_number(req, "error", 0); + if (error != 0) { + nvlist_destroy(req); + errno = error; + return (-1); + } + + mib = nvlist_get_binary(req, "mib", &mibsz); + *sizep = mibsz / sizeof(int); + + memcpy(mibp, mib, mibsz); + + nvlist_destroy(req); + + return (0); +} + /* - * Service functions. + * Service implementation. */ + +/* + * Validate a sysctl description. This must consist of an nvlist with either a + * binary "mib" field or a string "name", and an operation. + */ static int -sysctl_check_one(const nvlist_t *nvl, bool islimit) +sysctl_valid(const nvlist_t *nvl, bool limit) { const char *name; void *cookie; int type; - unsigned int fields; + size_t size; + unsigned int field, fields; /* NULL nvl is of course invalid. */ if (nvl == NULL) @@ -111,84 +277,120 @@ sysctl_check_one(const nvlist_t *nvl, bool islimit) return (nvlist_error(nvl)); #define HAS_NAME 0x01 -#define HAS_OPERATION 0x02 +#define HAS_MIB 0x02 +#define HAS_ID (HAS_NAME | HAS_MIB) +#define HAS_OPERATION 0x04 fields = 0; cookie = NULL; 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 ((strcmp(name, "name") == 0 && type == NV_TYPE_STRING) || + (strcmp(name, "mib") == 0 && type == NV_TYPE_BINARY)) { + if (strcmp(name, "mib") == 0) { + /* A MIB must be an array of integers. */ + (void)cnvlist_get_binary(cookie, &size); + if (size % sizeof(int) != 0) + return (EINVAL); + field = HAS_MIB; + } else + field = HAS_NAME; + + /* + * A limit may contain both a name and a MIB identifier. + */ + if ((fields & field) != 0 || + (!limit && (fields & HAS_ID) != 0)) return (EINVAL); - /* Only one 'name' can be present. */ - if ((fields & HAS_NAME) != 0) - return (EINVAL); - fields |= HAS_NAME; + fields |= field; } else if (strcmp(name, "operation") == 0) { - uint64_t operation; + uint64_t mask, operation; if (type != NV_TYPE_NUMBER) return (EINVAL); + + operation = cnvlist_get_number(cookie); + /* - * We accept only CAP_SYSCTL_READ and - * CAP_SYSCTL_WRITE flags. + * Requests can only include the RDWR flags; limits may + * also include the RECURSIVE flag. */ - operation = nvlist_get_number(nvl, name); - if ((operation & ~(CAP_SYSCTL_RDWR)) != 0) + mask = limit ? (CAP_SYSCTL_RDWR | + CAP_SYSCTL_RECURSIVE) : CAP_SYSCTL_RDWR; + if ((operation & ~limit) != 0 || + (operation & CAP_SYSCTL_RDWR) == 0) return (EINVAL); - /* ...but there has to be at least one of them. */ - if ((operation & (CAP_SYSCTL_RDWR)) == 0) - return (EINVAL); /* Only one 'operation' can be present. */ if ((fields & HAS_OPERATION) != 0) return (EINVAL); fields |= HAS_OPERATION; - } else if (islimit) { - /* If this is limit, there can be no other fields. */ + } else if (limit) return (EINVAL); - } } - /* Both fields has to be there. */ - if (fields != (HAS_NAME | HAS_OPERATION)) + if ((fields & HAS_OPERATION) == 0 || (fields & HAS_ID) == 0) return (EINVAL); -#undef HAS_OPERATION -#undef HAS_NAME +#undef HAS_OPERATION +#undef HAS_ID +#undef HAS_MIB +#undef HAS_NAME return (0); } static bool -sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation) +sysctl_allowed(const nvlist_t *limits, const nvlist_t *req) { - uint64_t operation; - const char *name; + const nvlist_t *limit; + uint64_t op, reqop; + const char *lname, *name, *reqname; void *cookie; + size_t lsize, reqsize; + const int *lmib, *reqmib; int type; if (limits == NULL) return (true); + reqmib = dnvlist_get_binary(req, "mib", &reqsize, NULL, 0); + reqname = dnvlist_get_string(req, "name", NULL); + reqop = nvlist_get_number(req, "operation"); + cookie = NULL; while ((name = nvlist_next(limits, &type, &cookie)) != NULL) { - assert(type == NV_TYPE_NUMBER); + assert(type == NV_TYPE_NVLIST); - operation = nvlist_get_number(limits, name); - if ((operation & choperation) != choperation) + limit = cnvlist_get_nvlist(cookie); + op = nvlist_get_number(limit, "operation"); + if ((reqop & op) != reqop) continue; - if ((operation & CAP_SYSCTL_RECURSIVE) == 0) { - if (strcmp(name, chname) != 0) + if (reqname != NULL) { + lname = dnvlist_get_string(limit, "name", NULL); + if (lname == NULL) continue; - } else { - size_t namelen; + if ((op & CAP_SYSCTL_RECURSIVE) == 0) { + if (strcmp(lname, reqname) != 0) + continue; + } else { + size_t namelen; - namelen = strlen(name); - if (strncmp(name, chname, namelen) != 0) + namelen = strlen(lname); + if (strncmp(lname, reqname, namelen) != 0) + continue; + if (reqname[namelen] != '.' && + reqname[namelen] != '\0') + continue; + } + } else { + lmib = dnvlist_get_binary(limit, "mib", &lsize, NULL, 0); + if (lmib == NULL) continue; - if (chname[namelen] != '.' && chname[namelen] != '\0') + if (lsize > reqsize || ((op & CAP_SYSCTL_RECURSIVE) == 0 && + lsize < reqsize)) continue; + if (memcmp(lmib, reqmib, lsize) != 0) + continue; } return (true); @@ -200,21 +402,20 @@ sysctl_allowed(const nvlist_t *limits, const char *chn static int sysctl_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) { + const nvlist_t *nvl; const char *name; void *cookie; - uint64_t operation; - int type; + int error, type; cookie = NULL; while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { - if (type != NV_TYPE_NUMBER) + if (strcmp(name, "limit") != 0 || type != NV_TYPE_NVLIST) return (EINVAL); - operation = nvlist_get_number(newlimits, name); - if ((operation & ~(CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) != 0) - return (EINVAL); - if ((operation & (CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) == 0) - return (EINVAL); - if (!sysctl_allowed(oldlimits, name, operation)) + nvl = cnvlist_get_nvlist(cookie); + error = sysctl_valid(nvl, true); + if (error != 0) + return (error); + if (!sysctl_allowed(oldlimits, nvl)) return (ENOTCAPABLE); } @@ -222,28 +423,59 @@ sysctl_limit(const nvlist_t *oldlimits, const nvlist_t } static int +nametomib(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) +{ + const char *name; + size_t size; + int error, *mibp; + + if (!sysctl_allowed(limits, nvlin)) + return (ENOTCAPABLE); + + name = nvlist_get_string(nvlin, "name"); + size = (size_t)nvlist_get_number(nvlin, "size"); + + mibp = malloc(size * sizeof(*mibp)); + if (mibp == NULL) + return (ENOMEM); + + error = sysctlnametomib(name, mibp, &size); + if (error != 0) { + error = errno; + free(mibp); + return (error); + } + + nvlist_add_binary(nvlout, "mib", mibp, size * sizeof(*mibp)); + + return (0); +} + +static int sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) { const char *name; const void *newp; + const int *mibp; void *oldp; uint64_t operation; - size_t oldlen, newlen; + size_t oldlen, newlen, size; size_t *oldlenp; int error; - if (strcmp(cmd, "sysctl") != 0) + if (strcmp(cmd, "sysctlnametomib") == 0) + return (nametomib(limits, nvlin, nvlout)); + + if (strcmp(cmd, "sysctlbyname") != 0 && strcmp(cmd, "sysctl") != 0) return (EINVAL); - error = sysctl_check_one(nvlin, false); + error = sysctl_valid(nvlin, false); if (error != 0) return (error); - - name = nvlist_get_string(nvlin, "name"); - operation = nvlist_get_number(nvlin, "operation"); - if (!sysctl_allowed(limits, name, operation)) + if (!sysctl_allowed(limits, nvlin)) return (ENOTCAPABLE); + operation = nvlist_get_number(nvlin, "operation"); if ((operation & CAP_SYSCTL_WRITE) != 0) { if (!nvlist_exists_binary(nvlin, "newp")) return (EINVAL); @@ -276,7 +508,15 @@ sysctl_command(const char *cmd, const nvlist_t *limits oldlenp = NULL; } - if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) { + if (strcmp(cmd, "sysctlbyname") == 0) { + name = nvlist_get_string(nvlin, "name"); + error = sysctlbyname(name, oldp, oldlenp, newp, newlen); + } else { + mibp = nvlist_get_binary(nvlin, "mib", &size); + error = sysctl(mibp, size / sizeof(*mibp), oldp, oldlenp, newp, + newlen); + } + if (error != 0) { error = errno; free(oldp); return (error); Modified: head/lib/libcasper/services/cap_sysctl/cap_sysctl.h ============================================================================== --- head/lib/libcasper/services/cap_sysctl/cap_sysctl.h Mon May 13 17:48:16 2019 (r347533) +++ head/lib/libcasper/services/cap_sysctl/cap_sysctl.h Mon May 13 17:49:54 2019 (r347534) @@ -29,24 +29,47 @@ * $FreeBSD$ */ -#ifndef _CAP_SYSCTL_H_ +#ifndef _CAP_SYSCTL_H_ #define _CAP_SYSCTL_H_ #ifdef HAVE_CASPER -#define WITH_CASPER +#define WITH_CASPER #endif +#ifdef WITH_CASPER #define CAP_SYSCTL_READ 0x01 #define CAP_SYSCTL_WRITE 0x02 #define CAP_SYSCTL_RDWR (CAP_SYSCTL_READ | CAP_SYSCTL_WRITE) #define CAP_SYSCTL_RECURSIVE 0x04 -#ifdef WITH_CASPER +int cap_sysctl(cap_channel_t *chan, const int *name, u_int namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen); int cap_sysctlbyname(cap_channel_t *chan, const char *name, 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) -#endif +int cap_sysctlnametomib(cap_channel_t *chan, const char *name, int *mibp, + size_t *sizep); -#endif /* !_CAP_SYSCTL_H_ */ +struct cap_sysctl_limit; +typedef struct cap_sysctl_limit cap_sysctl_limit_t; + +cap_sysctl_limit_t *cap_sysctl_limit_init(cap_channel_t *); +cap_sysctl_limit_t *cap_sysctl_limit_name(cap_sysctl_limit_t *limit, + const char *name, int flags); +cap_sysctl_limit_t *cap_sysctl_limit_mib(cap_sysctl_limit_t *limit, int *mibp, + u_int miblen, int flags); +int cap_sysctl_limit(cap_sysctl_limit_t *limit); +#else /* !WITH_CASPER */ +#define cap_sysctl(chan, name, namelen, oldp, oldlenp, newp, newlen) \ + sysctl((name), (namelen), (oldp), (oldlenp), (newp), (newlen)) +#define cap_sysctlbyname(chan, name, oldp, oldlenp, newp, newlen) \ + sysctlbyname((name), (oldp), (oldlenp), (newp), (newlen)) +#define cap_sysctlnametomib(chan, name, mibp, sizep) \ + sysctlnametomib((name), (mibp), (sizep)) + +#define cap_sysctl_limit_init(chan) (NULL) +#define cap_sysctl_limit_name(limit, name, flags) (NULL) +#define cap_sysctl_limit_mib(limit, mibp, miblen, flags) (NULL) +#define cap_sysctl_limit(limit) (0) +#endif /* WITH_CASPER */ + +#endif /* !_CAP_SYSCTL_H_ */ Modified: head/lib/libcasper/services/cap_sysctl/tests/sysctl_test.c ============================================================================== --- head/lib/libcasper/services/cap_sysctl/tests/sysctl_test.c Mon May 13 17:48:16 2019 (r347533) +++ head/lib/libcasper/services/cap_sysctl/tests/sysctl_test.c Mon May 13 17:49:54 2019 (r347534) @@ -1,12 +1,15 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2013, 2018 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * + * Portions of this software were developed by Mark Johnston + * 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: @@ -185,7 +188,7 @@ static void test_operation(cap_channel_t *origcapsysctl) { cap_channel_t *capsysctl; - nvlist_t *limits; + void *limit; /* * Allow: @@ -196,61 +199,63 @@ test_operation(cap_channel_t *origcapsysctl) capsysctl = cap_clone(origcapsysctl); CHECK(capsysctl != NULL); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_PARENT, + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == 0); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, + CHECK(cap_sysctl_limit(limit) == 0); + + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_PARENT, + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, "foo.bar", + (void)cap_sysctl_limit_name(limit, "foo.bar", CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); - limits = nvlist_create(0); - nvlist_add_number(limits, "foo.bar", + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); + + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, "foo.bar", CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 | SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE | SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE | SYSCTL1_READ_WRITE)); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_NAME, + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_NAME, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_NAME, + (void)cap_sysctl_limit_name(limit, SYSCTL1_NAME, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == 0); + CHECK(cap_sysctl_limit(limit) == 0); CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 | SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE | SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE | SYSCTL1_READ_WRITE)); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_NAME, + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_NAME, CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_NAME, + (void)cap_sysctl_limit_name(limit, SYSCTL1_NAME, CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == 0); + CHECK(cap_sysctl_limit(limit) == 0); CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE)); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ); - nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE); - CHECK(cap_limit_set(capsysctl, limits) == 0); + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_NAME, CAP_SYSCTL_READ); + (void)cap_sysctl_limit_name(limit, SYSCTL1_NAME, CAP_SYSCTL_WRITE); + CHECK(cap_sysctl_limit(limit) == 0); CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE)); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ); - CHECK(cap_limit_set(capsysctl, limits) == 0); + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_NAME, CAP_SYSCTL_READ); + CHECK(cap_sysctl_limit(limit) == 0); CHECK(runtest(capsysctl) == SYSCTL0_READ0); @@ -265,29 +270,30 @@ test_operation(cap_channel_t *origcapsysctl) capsysctl = cap_clone(origcapsysctl); CHECK(capsysctl != NULL); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_NAME, + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_NAME, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_NAME, + (void)cap_sysctl_limit_name(limit, SYSCTL1_NAME, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == 0); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, + CHECK(cap_sysctl_limit(limit) == 0); + + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - nvlist_add_number(limits, SYSCTL1_PARENT, + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR); - nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ); - nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ); - CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE); + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_RDWR); + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_RDWR); + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_READ); + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_WRITE); + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_READ); + CHECK(cap_sysctl_limit(limit) == -1 && errno == ENOTCAPABLE); CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 | SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE | @@ -305,26 +311,26 @@ test_operation(cap_channel_t *origcapsysctl) capsysctl = cap_clone(origcapsysctl); CHECK(capsysctl != NULL); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR); - nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR); - CHECK(cap_limit_set(capsysctl, limits) == 0); - limits = nvlist_create(0); - nvlist_add_number(limits, SYSCTL0_PARENT, + limit = cap_sysctl_limit_init(capsysctl); + (void)cap_sysctl_limit_name(limit, SYSCTL0_PARENT, CAP_SYSCTL_RDWR); + (void)cap_sysctl_limit_name(limit, SYSCTL1_PARENT, CAP_SYSCTL_RDWR); + CHECK(cap_sysctl_limit(limit) == 0); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905131749.x4DHnt1M020569>