Porting OpenBSD Pledge() to Linux (2022)
justine.lol
justine.lol
AppArmor and SELinux is perhaps better suited for "easy" retrofitting and the rules are frequently shipped by the developers, but both are much harder to use and somewhat error-prone. I've seen more clients simply turning of SELinux or AppArmor than I have clients dedicating time to develop proper configurations.
Pledge and unveil just works, no mucking around in obscure configuration language or wondering if the error is in your configuration, AppArmor/SELinux or the code.
That is very useful for those with that particular need, for others it is unnecessarily complex. A more common use case for regular users would rather be "run word processor without network access". That's where simpler systems shine. There used to be many access control mechanisms for Linux but they seemed to struggle to retain mindshare and remain a bit obscure.
I would guess that's because so much is achieved by the old way of running software under their own uid and a chroot, so anything else already is a special case.
Most qualified, certainly. But if all application developers were responsible, we wouldn't need security mechanisms in the first place. I may be misunderstanding how pledge works, but it seems to be actually a very poor security mechanism, since you could just write software which... doesn't pledge to only use certain capabilities. It seems like a great bug prevention mechanism, but not so much for security.
That's not true. I mean if developers could be infallibly perfect always, then yes we wouldn't need this kind of security mechanism.
But acknowledging that code always has bugs, it's a nice additional layer of protection. If someone comes up with a code injection bug and tries to use it to run attack code that gets blocked by a previous pledge, that's an improvement.
Pledge assumes that developers or maintainers will add pledge() and unveil() calls to the code. The software is no longer a blackbox, but given the tools to communicate intend to the kernel (e.g. i won't fork, exec, or create new sockets and will only access files in my /var/db/$name and /var/run/$name directories).. It doesn't change the intended usage of the existing APIs, but to get be able to use the tightest sandbox permissions you have to acquire capabilities as early as possible. This allows retrofitting useful pledge()/unveil() calls to existing code, get quick feedback and restructure the code over time.
An other interesting design to compare pledge()/unveil() against is FreeBSD's Capsicum. It's a fine grained capability mode (e.g. disable/keep specific ioctl() on a file descriptor) and can be used by normal FreeBSD processes as such, but the real sandbox mode is used by acquiring all file descriptors, restricting what is allowed on them, and entering the restrictive capability mode. Once inside capability mode there is no way back and you're only allowed to use existing capabilities to derive equal or weaker capabilities e.g. openat() relative to an open directory file descriptor instead of open() with an absolute path. It puts the burden purely on the developer. It's a very clean design, but correct to a fault. It's not harder to write new software to work inside it, but it's very hard to port software that wasn't written with it in mind to work at all, because it's all or nothing. As a consequence few software is written to take advantage of it.
OpenBSD's pledge()/unveil() is a pragmatic defense in depth tool. It works together with privilege separation and chroot. A good example is that new child processes intentionally are unrestricted and trusted/expected to apply their own restrictions whereas Capsicum mode is inherited to child processes.
Pledge() and unveil() are useful because they can provide additional safety and security at low cost, but they are less expressive. Porting it to Linux has the additional problem that Linux considers system calls to be the stable interface to the kernel instead of libc. The different versions of different libc implementations use different system calls on different architectures (e.g. sbrk() vs mmap()). To make matters worse some of them even depend of compile time flags (e.g. stat() vs stat64()). Each libc would have to implement its own pledge()/unveil() on top of a more flexible (aka complex and error prone) kernel interface.
SELinux has the better approach -- it's applied outside the application's control so it can't be subverted by some sort of environment manipulation. It's also modifiable, while pledge/unveil is hardcoded into the binary.
I really don't like the thought of hardcoding paths into the binary, it makes things extremely inflexible. Eg, say you have something that stores data. Under this model you can't run the program against an alternate data set because it'll refuse to work with anything but the official location.
I also think pledge/unveil has issues with process invocation. Either you can only restrict every process further than its parent, or an invoked process gets free reign. Neither is good.
The same applies for pledge.
Yes, it's perhaps not reasonable to compare pledge/unveil and something like SELinux. It really is different attack vectors the tools are defending against or mitigating.
You mean those developers who put in the telemetry code (or back-door or security vulnerability) in to begin with?
What do the application developers know about the user's organization's security policy?
The point is that they don't have to understand organizational policies, they just have to understand their program - does it use network, talk to the filesystem, etc.
If you want to enforce broader policies SELinux is not going anywhere.
While he's certainly in a position to give this estimate, I'm curious to know the factual basis of this opinion. That's a shockingly low statistic.
https://everything2.com/title/BSD+is+dying
(I've been using OpenBSD as my primary OS since 2000 so I guess I'm one of the 7000 OGs.)
Just one metric. /r/openbsd has 17k subscribers. Not sure with DaemonForums.
Process separation is already a success story that eliminates who classes of exploits.