porting linux pledge to go
I like using pledge and unveil in my web apps. Especially unveil offers a nice degree of protection against common web app problems, like the dreaded double dot traversal. For go, I use a simple wrapper which gets pasted into each project.
But what of the unfortunate linux users left out there?
For the current status of this project, refer to the README.
linux pledge
There is a version of pledge ported to linux. Using that, I can make a go module, which should work anywhere. Well, it will work on OpenBSD, mostly work on Linux, and cheerfully pretend to work everywhere else. Good enough.
The trick is we need to integrate this into go’s build process, without wrangling with another libc on the system.
The upstream for linux pledge we’re using is tied up in cosmopolitan libc, but there’s a standalone version extracted from it. From that, I extracted another, even simpler version. Double distilled, extra smooth.
A few quick hacks, and it all came together.
cosmo pledge
A few notes on behavioral differences using cosmo pledge.
At first, a pledge violation would only hang the go process. Apparently this is what happens when only a thread disappears unexpectedly. The easy fix was to switch to killing the process.
I also noticed unveil didn’t seem to work. As documented in the source, a null call is required to commit and seal the changes. On OpenBSD, they apply immediately, allowing one to skip the final unveil call and simply use pledge to prevent further changes. I just have the wrapper handle this.
There’s another difference regarding unveil and threads on linux, and I’m not entirely sure how it affects go. Ugh.
rseq
Linux has a system call rseq. What a name. Apparently glibc likes to use it, and if you don’t let it, it gets very cranky. “Fatal glibc error: rseq registration failed”
Looks like we will be punching a hole for that.
As documented by justine, glibc also wants to do some other tricksy business, which the linux port addresses by injecting a shared library. None of that code is here in the go port. Hopefully, we’re less reliant on glibc.
status
It’s close to done. Have switched honk to using this module, likely upping the protection level from 50% of users to 99% of users. See what breaks. (Narrator: stuff broke.)
I have some lingering concerns that the linux version can be bypassed in sneaky ways by someone with more knowledge of glibc. (Narrator: it’s not that hard.)
Read the README.