CAP_FILEARGS(3)

πŸ“¦
version 15.1 Β· 2 versions
, in freebsd 15.1

πŸ’… CAP_FILEARGS(3) β€” your bestie's guide to the cap_fileargs library (Library Functions Manual) πŸ¦‹

okay so first things first, this is cap_fileargs(3) from the Library Functions Manual, and it's genuinely one of those pages that looks scary but is actually just "here's how to open files after you've locked yourself in the Capsicum sandbox." no cap. let's get into it πŸ’–


✨ NAME ✨

cap_fileargs, fileargs_cinit, fileargs_cinitnv, fileargs_init, fileargs_initnv, fileargs_free, fileargs_lstat, fileargs_open, fileargs_fopen β€” literally the whole library for handling files in capability mode πŸŽ€


🌸 SYNOPSIS 🌸

library β€œlibcap_fileargs” #include <sys/nv.h>
#include <libcasper.h>
#include <casper/cap_fileargs.h>

fileargs_t *
fileargs_init(int argc, char *argv[], int flags, mode_t mode,
    cap_rights_t *rightsp, int operations);

fileargs_t *
fileargs_cinit(cap_channel_t *cas, int argc, char *argv[], int flags,
    mode_t mode, cap_rights_t *rightsp, int operations);

fileargs_t *
fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits);

fileargs_t *
fileargs_initnv(nvlist_t *limits);

void
fileargs_free(fileargs_t *fa);

int
fileargs_lstat(fileargs_t *fa, const char *path, struct stat *sb);

int
fileargs_open(fileargs_t *fa, const char *name);

FILE *
fileargs_fopen(fileargs_t *fa, const char *name, const char *mode);

char *
fileargs_realpath(fileargs_t *fa, const char *pathname,
    char *reserved_path);

πŸ¦‹ DESCRIPTION πŸ¦‹

so the cap_fileargs library exists to make Capsicum-izing your tools so much easier when those tools touch the file system. the whole idea, and I'm obsessed with it honestly: you pass along what's left of argv (with the count in argc), which holds the list of files your program should open. the library then spins up a service that serves those files for you. it's giving "main character energy" for your file descriptors πŸ’…

🌈 fileargs_init()

The function fileargs_init() creates a service to the system.fileargs. here's the vibe check on every argument:

  • argv contains a list of files that should be opened. you can set it to NULL to create no service at all and prohibit every file from being opened β€” yes, that's a thing, and yes, it's on purpose.
  • argc is the number of files passed to the program.
  • flags specifies whether files can be opened for execution, for reading, and/or for writing.
  • mode specifies the permissions to use when creating new files if the O_CREAT flag is set.
  • for more info about the flags and mode arguments, go see open(2).
  • rightsp specifies the capability rights that will be applied to restrict access to the files. more on capability rights in cap_rights_init(3).
  • operations specifies which operations are permitted when using system.fileargs.

and these flags can be combined to form the operations value:

  • FA_OPEN β€” allow fileargs_open() and fileargs_fopen().
  • FA_LSTAT β€” allow fileargs_lstat().
  • FA_REALPATH β€” allow fileargs_realpath().

🧚 fileargs_cinit()

The function fileargs_cinit() behaves identically to fileargs_init(), but it requires an existing Casper connection to be passed as an argument. same energy, you just bring your own connection 🫢

⭐ fileargs_initnv() and fileargs_cinitnv()

The functions fileargs_initnv() and fileargs_cinitnv() are equivalent to fileargs_init() and fileargs_cinit() respectively, but they take their arguments in the form of an nvlist(9) structure. see the β€œLIMITS” section for the deets on the expected argument types and values.

πŸ’œ fileargs_free()

The fileargs_free() function closes the connection to the system.fileargs service and frees all associated data structures. and good news: it safely handles NULL arguments. icon behavior, honestly.

πŸŽ€ fileargs_lstat()

The function fileargs_lstat() provides the same functionality as lstat(2). that's it. that's the whole thing.

πŸ“ fileargs_open() and fileargs_fopen()

The functions fileargs_open() and fileargs_fopen() behave identically to open(2) and fopen(3) respectively, except they retrieve their arguments from the fileargs_t structure. slay.

πŸ”₯ fileargs_realpath()

The function fileargs_realpath() provides the same functionality as the standard C library function realpath(3), resolving all symbolic links and references in a pathname. so many symlinks, so little time πŸ’«

πŸ’€ thread safety (read this one, bestie)

The following functions are reentrant but require synchronization for thread safety: fileargs_open(), fileargs_lstat(), fileargs_realpath(), fileargs_cinitnv(), fileargs_initnv(), and fileargs_fopen(). Multiple threads can call these functions safely only if they use different cap_channel_t arguments or proper synchronization mechanisms.

no cap: if you're going multi-threaded and you're not doing one of those two things, you're gonna have a bad time 😭

πŸ‘‘ LIMITS πŸ‘‘

This section describes the required and optional arguments that must be passed to system.fileargs via the fileargs_initnv() and fileargs_cinitnv() functions using an nvlist(9) structure.

🌟 The required ones (non-negotiable)

  • flags (NV_TYPE_NUMBER) β€” specifies access permissions for opened files.
  • mode (NV_TYPE_NUMBER) β€” required when the O_CREATE flag is set in flags. specifies the permissions to use when creating new files.
  • operations (NV_TYPE_NUMBER) β€” specifies which operations are allowed for system.fileargs. see the description of the operations argument in fileargs_init() for possible values.

🌸 The optional ones (choose your own adventure)

  • cap_rights (NV_TYPE_BINARY) β€” the cap_rights argument specifies the capability rights that will be applied to restrict access to opened files.
  • filenames (NV_TYPE_NULL) β€” multiple NV_TYPE_NULL elements can be provided, where each element's name represents a file path that is allowed to be opened.

🧚 EXAMPLES 🧚

okay here's a full example, and it's honestly kind of cute β€” look at this thing go:

int ch, fd, i;
cap_rights_t rights;
fileargs_t *fa;

while ((ch = getopt(argc, argv, "h")) != -1) {
        switch (ch) {
                case 'h':
                default:
                        usage();
        }
}

argc -= optind;
argv += optind;

/* Create capability to the system.fileargs service. */
fa = fileargs_init(argc, argv, O_RDONLY, 0,
    cap_rights_init(&rights, CAP_READ), FA_OPEN);
if (fa == NULL)
        err(1, "unable to open system.fileargs service");

/* Enter capability mode sandbox. */
if (cap_enter() < 0 && errno != ENOSYS)
        err(1, "unable to enter capability mode");

/* Open files. */
for (i = 0; i < argc; i++) {
        fd = fileargs_open(fa, argv[i]);
        if (fd < 0)
                err(1, "unable to open file %s", argv[i]);
        printf("File %s opened in capability mode\n", argv[i]);
        close(fd);
}

fileargs_free(fa);

like, look at that. sandboxed, files opened, everything cleaned up with fileargs_free(fa). periodt πŸ’…βœ¨


🫢 SEE ALSO 🫢

cap_enter(2), lstat(2), open(2), cap_rights_init(3), err(3), fopen(3), getopt(3), realpath(3), capsicum(4), nv(9)


⭐ HISTORY ⭐

The cap_fileargs service first appeared in FreeBSD 10.3. a lil throwback moment πŸŽ€


πŸ’– AUTHORS πŸ’–

Mariusz Zaborski <oshogbo@FreeBSD.org> β€” thank you for your service, king πŸ‘‘


πŸ™ˆ BUGS πŸ™ˆ

The cap_fileargs service is considered experimental and should be thoroughly evaluated for risks before deploying in production environments.

listen to me: experimental means experimental. do your homework before you ship this to prod, bestie, I'm begging πŸ˜­πŸ’€


and that's the page!! this one's from Debian, dated August 8, 2025 β€” go forth and sandbox responsibly, ily, bye πŸ’œπŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms