This article contains a lot of errors, for example Chromium on FreeBSD does NOT use Capsicum, it never has. That was experimental and invasive work done 17 years ago that was NEVER committed to their official ports repository. In fact, not a single browser in FreeBSD uses Capsicum or any form of sandboxing at all.
Contrast that with OpenBSD, where the Chromium port has used pledge(2) since January 2016, and unveil(2) since 2018. Both are enabled by default. Mozilla Firefox ports also use both pledge and unveil since 2018-2019.
OpenBSD's fork of tcpdump has been privsep for ~22 years, and its packet parser runs with no privileges. It's pledged tightly "stdio" and has no network/filesystem access, and uses OpenBSD specific innovations like bpf descriptor locking (BIOCLOCK) missing from both FreeBSD/Linux tcpdump today.
In the years since it was added, the reason Capsicum has only been applied to a handful of utilities is because it's a tree barren of decades worth of incremental work on privilege separation and security research.
Interesting article, but it compares apples to a fruit stand: The approach could be improved by comparing Capsicum to using seccomp in the same way.
Sometime ago I wrote a library for a customer that did exactly that: Open a number of resources, e.g., stdin, stdout, stderr, a pipe or two, a socket or two, make the seccomp calls necessary to restrict the use of read/write/etc. to the associated file descriptors, then lock out all other system calls - which includes seccomp-related calls.
Basically, the library took a very Capsicum-like approach of whitelisting specific actions then sealing itself against further changes.
This is a LOT of work, of course, and the available APIs don't make it particularly easy or elegant, but it is definitely doable. I chose this approach because the docker whitelist approach was far too open ended and "uncurated", if you will, for the use-case we were targeting.
In this particular case, I was aided by the fact the library was written to support the very specific use-case of filters running in containers using FIFOs for IPC, logging, and reporting: Every filter saw exactly the same interfaces to the world, so it was relatively easier to lock things down.
Having said that, I wish Linux had a Capsicum-equivalent call, or, even better for the approach I took, a friendlier way to whitelist specific calls.
A problem with that approach is that libc can after an upgrade decide to start doing syscalls you were not expecting. Like the first time you call `printf()` it calls `newfstatat()`. Only the first time. Maybe in the future it'll call it more often than that, and then your binary breaks.
I'm not sure what glibc's latest policy is on linking statically, but at least it used to be basically unsupported and bugs about it were ignored. But even if supported, you can't know if it under some configurations or runtime circumstances uses dlopen for something.
Or maybe once you juggle more than X file descriptors some code switches from using `poll()` to using `select()` (or `epoll()`).
That's the approach I meant by "that approach", the library the parent commenter was talking about writing for a customer. Compare this to Landlock or OpenBSDs pledge/unveil.
“The goal of Landlock is to enable restriction of ambient rights (e.g. global filesystem or network access) for a set of processes. Because Landlock is a stackable LSM [(Linux Security Model)], it makes it possible to create safe security sandboxes as new security layers in addition to the existing system-wide access-controls. ... Landlock empowers any process, including unprivileged ones, to securely restrict themselves.”
I've actually found it pretty fine. It doesn't have full coverage, but they have a system of adding coverage (ABI versions), and it covers a lot of the important stuff.
The one restriction I'm not sure about is that you can't say "~/ except ~/.gnupg". You have to actually enumerate everything you do want to allow. But maybe that's for the best. Both because it mandates rules not becoming too complex to reason about, and because that's a weird requirement in general. Like did you really mean to give access to ~/.gnupg.backup/? Probably not. Probably best to enumerate the allowlist.
And if you really want to, I guess you can listdir() and compose the exhaustive list manually, after subtracting the "except X".
I find seccomp unusable and not fit for purpose, but landlock closes many doors.
Maybe you know better? I'd love to hear your take.
I definitely don't know better, and after taking a few more looks at landlock, I'm not even sure what my objections were, probably got it confused with something else entirely. Confusion and ignorance on my part I guess.
You can make seccomp mimic Capsicum by whitelisting syscalls and checking FD arguments with libseccomp, but that quickly becomes error prone once you factor in syscall variants and helper calls. Read and write take the FD as arg0 while pread and pwrite shift it, and sendfile, splice and io_uring change semantics, and ioctl or fcntl can defeat naive filters, so you wind up with a huge BPF program and still miss corner cases.
Capsicum attaches rights to descriptors and gives kernel enforced primitives like cap_enter and cap_rights_limit, so delegation is explicit and easier to reason about. If you want Linux parity, use libseccomp to shrink the syscall surface, combine it with mount and user namespaces and Landlock for filesystem constraints, and design your app around FD based delegation instead of trying to encode every policy into BPF.
One question I've always had about these capability systems is: why isn't there a way to set capabilities from the parent process when execing? Why trust a program to set its own capabilities? I know that having a process set capabilities on itself doesn't break existing tools, but it seems like if you really wanted a robust system it would make sense to have the parent process, the user's shell for example, set the capabilities on its children, and have those capabilities be inheritable so the child could spawn other processes with the same or fewer capabilities (if it's allowed to do that at all). Is there an existing system that works this way, in or outside of the UNIX family? Or maybe some research paper written on the subject? I'd love to know.
I've only really messed with capsicum. You can certainly cap_enter between fork and exec, but depending on exactly what your target does, it's really not simple to do anything meaningful beyond the basic capsicum mode without changes to the program.
The way capabilities usually work is you more or less turn off the usual do whatever you want syscalls, and have to do restricted things through FDs that have the capability to do them. So like, no more open any path, you have to use openat with a FD in your directory of interest. But that requires the program to understand how to use the capabilities and how to be passed them. It's not something that you can just impose.
My understanding of SELinux, is it can be imposed on a program without the knowledge of the program, because it's more or less matching rules for syscalls... rather than giving a restricted FD to use with openat, you restrict the options for open.
This is essentially what containers are. Bubblewrap / Docker / Podman. I think the primary issue is very few applications on Desktop systems are actually designed with sandboxing in mind unlike say something on a phone.
I'm not terrible familiar with Linux container systems, cgroups and all that, but I have been down the rabbit-hole with FreeBSD's jails, and I definitely wouldn't call them a capabilities system. You can lock down the environment quite a bit, and limit or even virtualize the network stack, but you can't say, "Here process, have your standard IO streams and nothing more. Go forth and compute." The process isn't blind to it's environment. You're still in the same basic UNIX user security model. It's really somewhere between chroot and full virtualization.
A default container seccomp profile will let you do quite a few things but you can use a different profile some json and limit to just a few system calls if you want such as doing IO on open FDs without the ability to open them. I think the runtime opens the FDs before the child process starts and are inherited.
Landlock right now doesn't offer a lot for things that aren't file system access. Other than that it's great, you can have different restrictions per-thread if you want to.
Yeah, but the file system is where I put most of my files. :-)
Between file system, bind/connect, and sending signals, that covers most of it. Probably the biggest remaining risk is any unpatched bugs in the kernel itself.
So one would need to first gain execution in the process, and then elevate that access inside the kernel, in a way that doesn't just grant you root but still Landlocked, and with a much smaller effective syscall attack surface. Like even if there's a kernel bug in ioctl on devs, landlock can turn that off too.
I've seen AI written blog posts before, but this is one step above: the entire blog (~90 articles) have been AI generated over the past three months.
I already find it very frustrating that most open source projects spawning on HN's front page are resume-boosting AI slop but if blogs start being the same the internet is definitely dead.
Edit: it doesn't even looks like it's resume-boosting in this case, the “person” behind it doesn't even appear to exist. We can only speculate about the intent behind this.
It reminds me the pinnacle of design - Microsoft Authenticator. On Android, out of the blue, it displays global overlay to select one of the 3 numbers to confirm login.
1. The post mainly reiterates a single idea (Capsicum enumerates what the process can do, seccomp provides a configurable filter) in many different ways. There is not much actual depth, code samples notwithstanding. Nothing on why different designs were chosen, how easy each is to use, outcomes besides the Chrome example, etc.
2. There are a lot of AI writing tells, like staccato sentences, parallelism ("Same browser. Same threat model. Same problem."), pointless summary tables, "it's not X, it's Y" contradiction ("This is not a bug. It is the original Unix security model"), etc.
3. The author has roughly a blog post a day, all with similar style and on widely varied topics, and in the same writing style. Unless the author has deep expertise on a remarkably wide range of topics and spends all their time writing, these can't reflect deep insight or experience, but minimal editing of AI output.
It's pretty obvious. Lots of LLM signs. Short sentences that keep repeating the same idea. It's not x, it's this. In fact, the entire blog seems to be LLM-generated.
https://github.com/rwatson/chromium-capsicum
https://www.freshports.org/www/chromium/
Contrast that with OpenBSD, where the Chromium port has used pledge(2) since January 2016, and unveil(2) since 2018. Both are enabled by default. Mozilla Firefox ports also use both pledge and unveil since 2018-2019.
OpenBSD's fork of tcpdump has been privsep for ~22 years, and its packet parser runs with no privileges. It's pledged tightly "stdio" and has no network/filesystem access, and uses OpenBSD specific innovations like bpf descriptor locking (BIOCLOCK) missing from both FreeBSD/Linux tcpdump today.
In the years since it was added, the reason Capsicum has only been applied to a handful of utilities is because it's a tree barren of decades worth of incremental work on privilege separation and security research.
Sometime ago I wrote a library for a customer that did exactly that: Open a number of resources, e.g., stdin, stdout, stderr, a pipe or two, a socket or two, make the seccomp calls necessary to restrict the use of read/write/etc. to the associated file descriptors, then lock out all other system calls - which includes seccomp-related calls.
Basically, the library took a very Capsicum-like approach of whitelisting specific actions then sealing itself against further changes.
This is a LOT of work, of course, and the available APIs don't make it particularly easy or elegant, but it is definitely doable. I chose this approach because the docker whitelist approach was far too open ended and "uncurated", if you will, for the use-case we were targeting.
In this particular case, I was aided by the fact the library was written to support the very specific use-case of filters running in containers using FIFOs for IPC, logging, and reporting: Every filter saw exactly the same interfaces to the world, so it was relatively easier to lock things down.
Having said that, I wish Linux had a Capsicum-equivalent call, or, even better for the approach I took, a friendlier way to whitelist specific calls.
I'm not sure what glibc's latest policy is on linking statically, but at least it used to be basically unsupported and bugs about it were ignored. But even if supported, you can't know if it under some configurations or runtime circumstances uses dlopen for something.
Or maybe once you juggle more than X file descriptors some code switches from using `poll()` to using `select()` (or `epoll()`).
My thoughts last time I looked at seccomp: https://blog.habets.se/2022/03/seccomp-unsafe-at-any-speed.h...
That would break capsicum, too, so I don’t see how that’s a problem when “comparing Capsicum to using seccomp in the same way”.
“The goal of Landlock is to enable restriction of ambient rights (e.g. global filesystem or network access) for a set of processes. Because Landlock is a stackable LSM [(Linux Security Model)], it makes it possible to create safe security sandboxes as new security layers in addition to the existing system-wide access-controls. ... Landlock empowers any process, including unprivileged ones, to securely restrict themselves.”
https://docs.kernel.org/userspace-api/landlock.html
The one restriction I'm not sure about is that you can't say "~/ except ~/.gnupg". You have to actually enumerate everything you do want to allow. But maybe that's for the best. Both because it mandates rules not becoming too complex to reason about, and because that's a weird requirement in general. Like did you really mean to give access to ~/.gnupg.backup/? Probably not. Probably best to enumerate the allowlist.
And if you really want to, I guess you can listdir() and compose the exhaustive list manually, after subtracting the "except X".
I find seccomp unusable and not fit for purpose, but landlock closes many doors.
Maybe you know better? I'd love to hear your take.
Capsicum attaches rights to descriptors and gives kernel enforced primitives like cap_enter and cap_rights_limit, so delegation is explicit and easier to reason about. If you want Linux parity, use libseccomp to shrink the syscall surface, combine it with mount and user namespaces and Landlock for filesystem constraints, and design your app around FD based delegation instead of trying to encode every policy into BPF.
> Why trust a program to set its own capabilities?
An example may be that a program starts needing a wide range of capabilties but can then ratchet down to a reduced set once running, aka "privdrop".
> why isn't there a way to set capabilities from the parent process when execing?
There have been replies on other systems so just to stick with pledge which provides the abiliy to set "execpromises" to do this.
[1] https://man.openbsd.org/pledge
[2] https://www.openbsd.org/papers/eurobsdcon2017-pledge.pdf
[3] https://www.openbsd.org/papers/BeckPledgeUnveilBSDCan2018.pd...
[1] https://bsdb0y.github.io/posts/openbsd-intro-to-update-on-pl...
The way capabilities usually work is you more or less turn off the usual do whatever you want syscalls, and have to do restricted things through FDs that have the capability to do them. So like, no more open any path, you have to use openat with a FD in your directory of interest. But that requires the program to understand how to use the capabilities and how to be passed them. It's not something that you can just impose.
My understanding of SELinux, is it can be imposed on a program without the knowledge of the program, because it's more or less matching rules for syscalls... rather than giving a restricted FD to use with openat, you restrict the options for open.
But I am pretty sure you CAN get your capabilities from a patent process using capsicum, since they are just file descriptors.
On Linux I understand that Landlock is the way to go.
Between file system, bind/connect, and sending signals, that covers most of it. Probably the biggest remaining risk is any unpatched bugs in the kernel itself.
So one would need to first gain execution in the process, and then elevate that access inside the kernel, in a way that doesn't just grant you root but still Landlocked, and with a much smaller effective syscall attack surface. Like even if there's a kernel bug in ioctl on devs, landlock can turn that off too.
I already find it very frustrating that most open source projects spawning on HN's front page are resume-boosting AI slop but if blogs start being the same the internet is definitely dead.
Edit: it doesn't even looks like it's resume-boosting in this case, the “person” behind it doesn't even appear to exist. We can only speculate about the intent behind this.
https://news.ycombinator.com/item?id=47268574
But hey, it's a game!
It reminds me the pinnacle of design - Microsoft Authenticator. On Android, out of the blue, it displays global overlay to select one of the 3 numbers to confirm login.
The overlay is ... transparent.
The UI is fun but unreadable, but content is solid. Explain how this is slop please.
1. The post mainly reiterates a single idea (Capsicum enumerates what the process can do, seccomp provides a configurable filter) in many different ways. There is not much actual depth, code samples notwithstanding. Nothing on why different designs were chosen, how easy each is to use, outcomes besides the Chrome example, etc.
2. There are a lot of AI writing tells, like staccato sentences, parallelism ("Same browser. Same threat model. Same problem."), pointless summary tables, "it's not X, it's Y" contradiction ("This is not a bug. It is the original Unix security model"), etc.
3. The author has roughly a blog post a day, all with similar style and on widely varied topics, and in the same writing style. Unless the author has deep expertise on a remarkably wide range of topics and spends all their time writing, these can't reflect deep insight or experience, but minimal editing of AI output.
So yes, it's pretty sloppy.