Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. OpenJev(openjev.com ↗)
    6comments
  2. Jemalloc 5.4.0(github.com/jemalloc ↗)
    40comments
  3. The scourge of x86 emulation(fex-emu.com ↗)
    26comments
  4. Astra for Law(openai.com ↗)
    555comments
  5. Bonsai 2 27B: Near-Lossless Compression in a 9x Smaller Footprint(prismml.com ↗)
    133comments
  6. Bend – A language that blocks AI mistakes via proof, on CPU and GPU(bend-lang.com ↗)
    221comments
  7. Qwen 3.8 Omni Flash(qwen.ai ↗)
    81comments
  8. Hister: A private search engine for the pages you visit and the files you keep(github.com/asciimoo ↗)
    169comments
  9. Wax motor(wikipedia.org ↗)
    70comments
  10. Pre-Greek: The lost language hidden within Ancient Greek(linguisticdiscovery.com ↗)
    34comments
  11. When the fractional part of a float fixes your shader(crocidb.com ↗)
    1comments
  12. Fujitsu launches made-in-Japan next-generation CPU FUJITSU-MONAKA(global.fujitsu ↗)
    231comments
  13. A heap overflow and SSO misconfiguration to compromise OpenAI internal repos(hacktron.ai ↗)
    155comments
  14. Replacing Pull Requests with Delta(zed.dev ↗)
    2comments
  15. Shapelearn Qwen 3.8 27B (13.1 GB VRAM)(byteshape.com ↗)
    11comments
  16. Microsoft exec called AI scraping 'the largest theft of labor in human history'(techcrunch.com ↗)
    2comments
  17. How to Write with an LLM(sockpuppet.org ↗)
    98comments
  18. Ask A Monk – A digital wilderness for thoughts with no immediate answer(askamonk.online ↗)
    24comments
  19. Speeding up gearhash on ARM64(sam.dev ↗)
    discuss
  20. Why Does the Universe Expand?(cosmicave.org ↗)
    55comments
  21. Telstra outage: The night a network decided the year was 2006(netnod.se ↗)
    26comments
  22. Flet 1.0 – Build cross-platform apps in Python(flet.dev ↗)
    58comments
  23. Diplodocus, Long Thought Exclusively American, Turns Up in Spain(sci.news ↗)
    41comments
  24. Why I didn’t sign the Fields medallists’ letter(gowers.wordpress.com ↗)
    368comments
  25. How do we prevent mathemathics from devolving into the Medieval Era of secrecy?(mathoverflow.net ↗)
    107comments
  26. Apple detectives solved mystery of ancient tree and rewrote the history of fruit(scientificamerican.com ↗)
    10comments
  27. CrowdSec Source Code Leak(crowdsec.net ↗)
    49comments
  28. The most important product decision is what you don't build(liamnugent.me ↗)
    39comments
  29. Fixing an NZXT Signal 4K30 part 2: the green/pink video bug(downtowndougbrown.com ↗)
    10comments
  30. How Uber Protects Against Retry Storms(uber.com ↗)
    42comments

Pledge and Unveil in OpenBSD [pdf]

125 pointsby 8y agoopenbsd.org
34 comments
8y agoHN ↗

Does anybody here know when the videos will be up?

8y agoHN ↗

The PDF has no introduction section, seems to be aimed at people who already know what it's talking about. Can anyone shed some light on what is the idea here? I honestly don't understand what's going on, apart from that it seems to be some security-related feature (or actually two of them?)

8y agoHN ↗

pledge(2) on OpenBSD is used to drop the privileges of a process. Processes are meant to call pledge(2) to drop their own privileges. The way pledge(2) works is that the system calls of that process get limited. If a process calls a system call outside the allowed range after calling pledge(2), it gets killed. Starting with OpenBSD 6.3, it is also possible to configure pledge to make the kernel return ENOSYS instead of killing the process when violating the pledge.

For example:

    /* Only the system calls required
     * for the standard I/O library and
     * for accessing /dev/tty are allowed
     * by the kernel from this point on.
     */
    pledge("stdio tty", NULL);

The second argument is the execpromises, i.e., the pledges enforced for child processes. This does not need to be specified if you pledge in a way that does not include any way of spawning a new process.

What's new in the slides linked is unveil(2). This seems to be used to limit the exact paths a process can access and with what access flags (rwxc).

8y agoHN ↗

Systrace was removed because it's unsafe for multi-threaded programs because of TOCTOU.

8y agoHN ↗

The race only existed for path strings. systrace was no worse than seccomp in this respect (which doesn't even permit filtering on paths precisely because of the systrace exploit), yet still much easier to use.

systrace was removed because it went largely unused. Theoretically powerful, in practice it made the wrong compromises. seccomp recapitulated the same compromises, and it's not surprising seccomp uptake has been similarly weak.

8y agoHN ↗

How do other Unices such as Linux deal with this issue (IIRC systrace was ported to other Unices)? Is Pledge ported to other BSDs?

I don't believe pledge is ported to other BSD operating systems, for example FreeBSD uses their own framework, capsicum[1] instead of pledge.

[1]: https://www.freebsd.org/cgi/man.cgi?capsicum(4)

8y agoHN ↗

1) Like with Linux seccomp, systrace couldn't safely work with path strings because of TOCTTOU races. That made it much less appealing. Seccomp never permitted filtering path strings precisely because of the published systrace exploits.

2) To address #1, there's no avoiding intrusive changes deep in the kernel (e.g. into the dentry system, as opposed to a thin layer over syscalls). You need to copy path strings into kernel buffers to avoid the race. Once you accept that it's not possible to have a clean interface boundary in the kernel if you want to keep userland simple, offloading certain core concerns to the kernel makes more sense.

3) systrace, like SELinux, required an external configuration policies for each program. But they were never kept up-to-date, and there were few workable policies. For the most part the only people who understand a program--especially a complex program--well enough to know what privileges are needed are the developers themselves. An external privilege declaration policy is theoretically powerful but in practice it merely creates burdensome indirection and friction for the people best positioned to create and maintain the policy: developers. Moreover, if the policy is optional both users and developers will opt out, particularly during the critical development phase. If a feature doesn't fit neatly into the edit+compile+debug cycle than it's arguably broken by design, particularly for security-oriented features.

4) When doing privilege separation more often than not you _want_ privileges for a certain period of time before dropping them. The classic example is the privilege to open a port < 1024. Policy files that, e.g., let you open specific ports are actually too permissive because you don't want a process to be able to open a port for its entire lifetime. Solutions like inetd/systemd where you simply pass in privileged resources only work for the simplest cases, such as the aforementioned privileged port problem; they don't solve the problem of, e.g., privilege-separating access to the credential database that a program like sshd needs to handle (this is worse on PAM-based systems like Linux as BSDAuth uses groups and external helpers to privilege separate by design). Better but more intrusive interfaces like Capsicum that revolve around runtime privilege sharing have too high of an entry cost to spur widespread adoption. Some of the more complex OpenBSD daemons are obvious fits for Capsicum, but you can't ignore path dependency--they'd have never been ripe for easy Capsicum integration if these simpler mechanisms weren't available.

pledge() was designed to address all of these problems. The "dns" privilege, for example, implicitly permits read access to certain filesystem paths. The intrusive kernel changes are built into the kernel as needed, maximizing overall simplicity by splitting the burden between kernel logic and userland logic.

pledge() handled very simple path handling well (e.g. permit /dev/null, /etc/resolv.conf, etc) but a system for specifying generic filesystem namespace privileges was elusive. Elusive because OpenBSD wants, again, to maximize simplicity and utility while minimizing overall complexity. Apparently unveil() represents the semantic and implementation compromises they've been searching for through trial+error.

Compared to SELinux or seccomp, pledge has been a wild success. Both SELinux and seccomp are much more complex, while being simultaneously more burdensome on developers. In some respects they're more powerful, but often more powerful in the least useful ways. In other respects pledge is more powerful featurewise, and exactly in the ways you'd want. Very few projects or systems utilize SELinux or seccomp. Particularly seccomp as Red Hat put a ton of effort into SELinux for what better yet still meager usage its seen. Much more common is to see frameworks like systemd utilize the privilege systems on behalf of programs. But having systemd manage these things limits the extent to which daemons can make use of fine-grained privilege separation. And doing so makes all the complexity of SELinux and seccomp almost for naught.

By contrast, the OpenBSD developers have "pledge'd" vast swaths of the OpenBSD software ecosystem. Not just daemons but most command-line utilities. You could argue that it was easier for them, but that doesn't explain why Red Hat with considerably more people and money, and decades longer lead time, had such ridiculously meager results with SELinux and seccomp.

Another thing to keep in mind is that pledge() and unveil() aren't the only privilege separation changes OpenBSD has made. Another one is that, along the lines of getentropy(), they made syslog() a syscall so that you don't even need to worry about filesystem privileges for the common cases. Everything is a file is a powerful construct, but for various reasons it's _intrinsically_ handicapped in Unix because of core design elements. Sometimes it's better to simply rethink the best place to put a feature in order to maximize cost+benefit. Leveraging filesystem namespace semantics makes much more sense in Unix than in Windows, but less sense in Unix than in Plan 9. You have to appreciate the nuances and limitations.

pledge() in particular is a very pragmatic, very experience-driven compromise. I honestly don't know if it'd work well for Linux. Linux is a vastly different ecosystem, both in the kernel and in userland. But people would do well to appreciate and understand why pledge() works as well as it does.

8y agoHN ↗

Not really; seccomp(2) is for _specific_ system calls, pledge(2) is for more broad functionalities.

8y agoHN ↗

I didn’t say they are bug-for-bug compatible and 100% interchangeable. Seccomp was not mentioned anywhere in the thread. People who are interested can look up the specific details.

8y agoHN ↗

Not at all, for example you can't implement the ratcheting down semantics of pledge() using seccomp. Say starting with a broader promise set "stdio rpath recvfd", and then dropping to "stdio" after full init.

pledge() can also be found in over 85% of OpenBSD's base system.

8y agoHN ↗

brings me to the next question: are there linux equivalent ?

8y agoHN ↗

There's Capsicum for Linux[1]. Its a port of Capsicum[2] from FreeBSD to Linux. Capsicum was a joint project between the FreeBSD foundation, Cambridge and Google to create a hybrid capabilities framework. But Capsicum allows developers to do the same privilege dropping that pledge does. However Capsicum is more fine grained then pledge so its less easy to use. Also Capsicum for Linux is also out of tree currently.

[1]: http://www.capsicum-linux.org/ [2]: https://www.freebsd.org/cgi/man.cgi?capsicum(4)

8y agoHN ↗

Link #1 is neat for Linux users, but Google seems to have stopped updating Capsicum after v4.11 (which was released April 2017).

8y agoHN ↗

On linux you can use firejail if it's necessary (or a container if it's needed).

8y agoHN ↗

This doesn't address what they just said - dropping privileges incrementally. Firejail is just a whole process filter applied at process start.

8y agoHN ↗

Awesome!

Given the Chrome example starting on page 6, here's my guess as to how pledge and unveil will contain Chrome to e.g. protect SSH keys. First, 3 of the 5 Chrome processes are already pledged to disallow filesystem reads. The two remaining ones (RenderProcess and UtilityProcess) can be unveiled to allow directories like

  * ~/.config/chromium
  * ~/.cache/chromium
  * ~/Downloads
  * /tmp
  * and anything important I don't know of

Additionally, if unveil works like pledge and can be further restricted after e.g. reading files into memory, unveils can then be undone. Anyone know if the following would work to first allow access to /tmp and then revoke that access?

  unveil("/tmp", "rw");
  /* do some work */
  unveil("/tmp", "");
8y agoHN ↗

Indeed! The full unveil semantics aren't known yet, may be worth proposing! But for the specific case of /tmp, there is already a tmppath promise.

8y agoHN ↗

The idea is that everything is "veiled" and you "unveil" the stuff you need access to.

8y agoHN ↗

Yes, but the weird thing is that before you call unveil, everything is already unveiled, which is not in sync with the dictionary definition of unveiling. I hope a better name is found.

8y agoHN ↗

It's unveiling in the context of pledge, as you explicitly declare the things to be unveiled.

8y agoHN ↗

Your comment made me try to look up the exact semantics of unveil(2). It was a bit hard to find (I could only find something on its predecessor pledgepath), but apparently, unveil doesn't take effect immediately, but only at an invocation of pledge(2) (which usually follows immediately after it). That was not at all clear from TFA.

8y agoHN ↗

I wouldn't expect your /tmp example to work, because if unveil is anything like pledge, additional calls can only add restrictions, not take them away.