CAP_SYSCTL(3)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1

πŸ’… CAP_SYSCTL(3) β€” the cap_sysctl(3) library manual, bestie edition

okay so this is the manual for cap_sysctl, and honestly? it's a whole vibe. it's the library for getting or setting system information in capability mode. yes, that capability mode. we love a sandboxed queen πŸ‘‘


✨ NAME ✨

cap_sysctl β€” library for getting or setting system information in capability mode. that's it, that's the tweet πŸ’–


πŸ“š LIBRARY πŸ“š

library β€œlibcap_sysctl” β€” go ahead and link her, she's ready 🫢


πŸŽ€ SYNOPSIS πŸŽ€

like, include the headers first, obviously:

#include <libcasper.h>
#include <casper/cap_sysctl.h>

and then all the functions, in all their glory:

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);

int
cap_sysctlnametomib(cap_channel_t *chan, const char *name, int *mibp,
    size_t *sizep);

cap_sysctl_limit_t *
cap_sysctl_limit_init(cap_channel_t *chan);

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, const int *mibp,
    u_int miblen, int flags);

int
cap_sysctl_limit(cap_sysctl_limit_t *limit);

πŸ’– DESCRIPTION πŸ’–

so cap_sysctl(), cap_sysctlbyname() and cap_sysctlnametomib() are literally the same energy as sysctl(3), sysctlbyname(3) and sysctlnametomib(3) β€” like, same functions, same behaviour β€” EXCEPT they're implemented by the β€˜system.sysctl’ libcasper(3) service and they need a corresponding libcasper(3) capability. no capability, no service, no vibes. periodt.

now listen up, because this is the important part πŸ‘‡

all of these functions β€” with the exceptions of cap_sysctl_limit_init() and cap_sysctl_limit_mib() β€” are reentrant but not thread-safe. so like, you can call them from separate threads, but only with different cap_channel_t arguments, or with synchronization. do not come for me if you skip the sync, bestie, it's giving undefined chaos 😭


πŸ”’ LIMITS πŸ”’

by default, the cap_sysctl capability gives you unrestricted access to the sysctl namespace. the whole thing. no cap. but like, most applications only need a tiny handful of sysctl variables, so the cap_sysctl_limit() interface exists to restrict which sysctls you can touch through the cap_sysctl capability. it's giving ✨boundaries✨ and we respect them.

cap_sysctl_limit_init() returns an opaque limit handle that stores a list of permitted sysctls and access rights. and the rights are encoded with these flags:

  • 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

so, cap_sysctl_limit_name() adds the sysctl identified by name to the limit list, and cap_sysctl_limit_mib() adds the sysctl identified by mibp to the limit list. the access rights for the sysctl go in the flags parameter, and you must specify at least one of CAP_SYSCTL_READ, CAP_SYSCTL_WRITE and CAP_SYSCTL_RDWR. no flags, no entry, no exceptions πŸ’…

then cap_sysctl_limit() applies a set of sysctl limits to the capability, denying access to sysctl variables that aren't in the set. it consumes the limit handle. and after either success or failure, you must not access the handle again. like, it's gone, she's moved on, do not text her πŸ™ˆ

once a set of limits is applied, subsequent calls to cap_sysctl_limit() will fail unless the new set is a subset of the current set. narrowing only, bestie. no take-backs.

and 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 too. package deal 🎁


πŸ¦‹ EXAMPLES πŸ¦‹

okay this example is iconic. it first opens a capability to casper, uses that capability to create the system.sysctl casper service, and then uses the cap_sysctl capability to get the value of kern.trap_enotcap. ate and left no crumbs:

cap_channel_t *capcas, *capsysctl;
const char *name = "kern.trap_enotcap";
void *limit;
size_t size;
bool value;

/* Open capability to Casper. */
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.sysctl service. */
capsysctl = cap_service_open(capcas, "system.sysctl");
if (capsysctl == NULL)
        err(1, "Unable to open system.sysctl service");

/* Close Casper capability, we don't need it anymore. */
cap_close(capcas);

/* Create limit for one MIB with read access only. */
limit = cap_sysctl_limit_init(capsysctl);
(void)cap_sysctl_limit_name(limit, name, CAP_SYSCTL_READ);

/* Limit system.sysctl. */
if (cap_sysctl_limit(limit) < 0)
        err(1, "Unable to set limits");

/* Fetch value. */
size = sizeof(value);
if (cap_sysctlbyname(capsysctl, name, &value, &size, NULL, 0) < 0)
        err(1, "Unable to get value of sysctl");

printf("The value of %s is %d.\n", name, value);

cap_close(capsysctl);

🌸 RETURN VALUES 🌸

so here's the tea on what each one hands back:

  • cap_sysctl_limit_init() returns a new limit handle on success, or NULL on failure, and sets errno.
  • cap_sysctl_limit_mib() and cap_sysctl_limit_name() return the modified limit handle on success, or NULL on failure and set errno. And after failure, the caller must not access the limit handle again. seriously. don't.
  • cap_sysctl_limit() returns -1 on failure and sets errno.
  • cap_sysctl(), cap_sysctlbyname(), and cap_sysctlnametomib() have the same return values as their non-capability-mode equivalents as documented in sysctl(3). same energy, different sandbox 🫢

πŸ‘€ SEE ALSO πŸ‘€

go read them, iykyk πŸ’œ


⭐ HISTORY ⭐

the cap_sysctl service first appeared in FreeBSD 10.3. a legend from the start πŸ‘‘


🌈 AUTHORS 🌈

the cap_sysctl service was implemented by Pawel Jakub Dawidek <pawel@dawidek.net> under sponsorship from the FreeBSD Foundation. slay πŸ’…

this manual page was written by Mariusz Zaborski <oshogbo@FreeBSD.org>. thank you for your service πŸŽ€


🧚 and that's the whole page, bestie! no notes, no cap. now go forth and sysctl responsibly ✨

Debian Β· December 6, 2023 Β· CAP_SYSCTL(3) β€” that's the source, the version and the date, all wrapped up with a bow πŸŽ€ bye bestie, love u, drink water πŸ’–

πŸ“¦ where this page comes from