Writting Secure Programs with Capsicum on FreeBSD
Note: this article is very simple. I’ll add more to this article when I try more stuff with Capsicum.
Update: Someone wrote an article about using openat
in Capsicum. It has more words than this one.
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 hello.c && ./a.out
) and it gave me this output.
hello
3 4 -1
It works! Capsicum seems super easy to use!
For more usage of Capsicum, see my experimentation repo.
That’s it for now bye~
How Does This Works Exactly
This is best explained by rights(4). Basically, you can limit the set of syscalls that can be used with a file descriptor. When in doubt, CAP_READ|CAP_WRITE|CAP_SHUTDOWN
.
..
is not allowed in openat(2).
The complete list of “file” types can be found in FreeBSD’s source code.
- zero (i dunno what this is)
- vnode (file or directory)
- socket
- pipe
- fifo
- kqueue
- crypto (hardware-accelerated cryptography device)
- mqueue
- shm (shared memory (shm_open(2)))
- ksem (POSIX P1003.1B semaphores support (sem(4)))
Does anyone use this nowadays? - pts
- dev
- proc
- eventfd (wait/notify)
More people should use this! - timerfd
And I quote from timerfd(2): All timerfd descriptors possess traditional file descriptor semantics; they may be passed to other processes, preserved across fork(2), and monitored via kevent(2), poll(2), or select(2).
Remember this property of file descriptors, as this is very useful when used with capsicum.
Musing: proc fd cannot refer to the current process. To send signal to current process, use getpid
+kill
(2 syscalls!), which capsicum allows.