This Article IsCreated at 2023-11-19Last Modified at 2024-06-29Referenced as ia.www.b24

Writting Secure Programs using Capsicum on FreeBSD

Someone wrote an article about using openat in Capsicum. It has more words than this one. Maybe you want to read that too.

I made a joke using Capsicum!


Recently I heard this capability subsystem that I kept spelling as “Capsium” is supposed to easy to add to existing UNIX programs. The good news is, it is on FreeBSD right now, and I can use it! (You too!) The bad news is that it’s not on Linux, and probably never will be.

Reminder: Please apply the newest security patches on your FreeBSD installation before using Capsicum.

After installing FreeBSD, here’s the singular C program that I wrote to try out Capsicum.

#include <stdio.h> 
#include <sys/capsicum.h> 
 
int main() { 
    int cwd_fd = open(".", O_RDONLY|O_DIRECTORY); 
    cap_enter(); 
    puts("hello"); // write to stdout 
    int hello_c_fd = openat(cwd_fd, "hello.c", O_RDONLY); 
    int parent_fd = openat(cwd_fd, "..", O_RDONLY); 
    printf("%d %d %d\n", cwd_fd, hello_c_fd, parent_fd); 
}

Then, I ran it with root (cc cap_hello.c && ./a.out) and it gave me this output.

hello
3 4 -1

It works! Capsicum seems super easy to use!

What’s the errno when the fd has insufficient capability (in this case, openat(cwd_fd, "..", O_RDONLY))? It’s 93 ENOTCAPABLE. See errno(2).

For more usage of Capsicum, see my FreeBSD experimentation repo.

That’s it for now bye~

How Does This Works Exactly

After cap_enter, only file descriptors have access to OS resources. This makes access control very easy to reason about. .. is disallowed in openat(2), so you can’t navigate a fd upwards.

Every file descriptor (fd) stores a list of syscalls it is willing to be used with (see rights(4)). By default, all syscalls are allowed. There is one “capability” for each syscall, and the granularity is per fd.

Basically, you can limit the set of syscalls that can be used with a fd. When in doubt, use pipes for IPC and CAP_READ|CAP_WRITE|CAP_SHUTDOWN.

The complete list of “file” types can be found in FreeBSD’s source code.

Musing: proc fd cannot refer to the current process. To send signal to current process, use getpid+kill(2 syscalls!), which capsicum allows.