5 ms·
> There's been a few devs in the past who've tried this. I'm not going to name names, because most of these projects were never completed. Oh, I'll just name m
by gnoack 4y ago
> There's been a few devs in the past who've tried this. I'm not going to name names, because most of these projects were never completed.
Oh, I'll just name myself (see code link below), I'm not ashamed that this didn't complete.
There are more fundamental reasons why these projects don't complete, and they apply to the project linked above as well:
- Maintaining lists of allowed syscalls across kernel versions and architectures is unreasonable to do, and it's a moving target. An allowlist-based approach might break when doing a kernel or glibc upgrade, which breaks the API backwards compatibility that the kernel otherwise guarantees.
- Core parts of glibc are doing initialization work on demand, which complicates matters (should ideally be done before enabling the sandbox, but this is not generally possible)
- Some pledge() promises can't be mapped correctly; examples:
- the "dns" promise in cosmopolitan/pledge.c just permits all outgoing UDP connections, which is more than what OpenBSD permits, IIRC
- the "exec" promise cannot elevate privileges again, as it does in OpenBSD
- glibc name lookups as they are used for DNS are loading shared libraries on first use (libnss), and it's impossible to tell in advance what these will do unless you control the execution environment
- The pledge API itself is a moving target as well (compare https://man.openbsd.org/OpenBSD-6.0/pledge.2 https://man.openbsd.org/OpenBSD-6.0/pledge.2 and https://man.openbsd.org/OpenBSD-7.1/pledge.2 https://man.openbsd.org/OpenBSD-7.1/pledge.2)
- In OpenBSD, pledge was always path-aware, until they moved that part into the unveil() call. This is not possible on Linux with seccomp-bpf. (Well, yes yes, with signals that do syscall trampolines and very very tight control over the runtime environment, or with sidecar processes to do the supervision, but both of these require a lot more dedication and can't be just mapped to a call to "pledge()" on Linux.)
FWIW, my own (abandoned) implementation is at:
https://github.com/gnoack/seccomp-scopes/blob/master/pledge.c#L118 https://github.com/gnoack/seccomp-scopes/blob/master/pledge....
IMHO the better approach on Linux is going to be Landlock (https://landlock.io https://landlock.io) in the future. I'd encourage you to look into it.
- the8472 4y agoLandlock suffers from the same limitations as seccomp when it comes to pledge-emulation: you can't opt out of inheritance.
- staticassertion 4y agoThat's a good thing.
- mzs 4y agoNo that's a linux thing. The OpenBSD way is to do things that could be abused later early and then drop privs to prevent abuse. How is some program going to know what other programs you use will need? How is the dynamic linker of the later program supposed to deal?
- staticassertion 4y ago> The OpenBSD way is to do things that could be abused later early and then drop privs to prevent abuse. That is the approach if you can't regain privileges. In the OpenBSD way it is literally the opposite of waht you propose. > How is some program going to know what other programs you use will need? It doesn't? Same issue on linux/openbsd in that regard, with some aspects a bit different due to libc. > How is the dynamic linker of the later program supposed to deal? It obviously doesn't, again, same thing on Linux and OpenBSD. It also won't help you to be able to regain privileges via exec if the issue is a shared library. Allowing for privileges to not propagate is a cool feature that allows you to shell out to a binary that you can't write to (otherwise it's pointless) and have that binary manage its own permissions. That's sometimes important, and Apparmor supports that sort of thing (with child profiles). But it's also a big footgun that can easily allow a full sandbox bypass. You can implement the child profile concept easily enough with a privileged broker anyway.
- staticassertion 4y agoOh yeah, is this not a clear bypss? Write an executable file to disk and then... execute it. As far as I know that is all that's required to completely bypass pledge? I assume/ hope this is something you can control with better filesystem controls?
- 4y ago
- gnoack 4y agoI guess the TL;DR is: This is a cool project, don't get me wrong :) I just feel that it's difficult to do in Linux's heterogeneous environment where everyone uses their own kernel configuration and libc variant... the reason is not just the difficult C API (with BPF in it...) but it's also the surprises and weak guarantees in the environment where these programs run. We should at some point be able to do unprivileged sandboxing, but seccomp-bpf may not be the way to do this at scale.
- staticassertion 4y ago> - the "exec" promise cannot elevate privileges again, as it does in OpenBSD I agree with all of this fwiw, but I actually was very glad to see this. I find it really weird that the openbsd pledge lets you just escalate out of it.
- wahern 4y ago> I find it really weird that the openbsd pledge lets you just escalate out of it. It's only weird because the normal M.O. with facilities in other environments is to sandbox specific, high-exposure applications, which are typically run in isolation, such as system daemons or end-user GUI applications. The semantics of pledge and unveil were fine-tuned from OpenBSD developers systematically sandboxing almost the entire base system--most command-line utilities in OpenBSD are pledged, as are all daemons. Inheritance is only a "problem" if you're exec'ing other programs, but the vast majority of programs, even command-line utilities, never need to exec, at least not during runtime (as opposed to startup). Most programs using pledge drop the ability to exec entirely (i.e. don't specify the "exec" pledge), so inheritance is irrelevant as there could never be anything to inherit. (Note that upon the first call to pledge, you lose any capabilities you don't explicitly request.) But if you do need to exec other programs, then inheritance can quickly become a problem--counter-productive, even, as workarounds typically involve the parent program preserving permissions which it might not need directly. (Note that this is also why pledge and unveil are superior APIs to relying on the invoker--e.g. systemd--dropping permissions as only the program itself knows best which permissions it needs and when.) OpenBSD is developed as a comprehensive system, and it's in this context that you need to understand pledge and unveil. On OpenBSD, if program A exec's program B, program B should be making use of pledge and unveil itself, and if it's not then that can and will be fixed. Unlike in the cat-herding Linux ecosystem, OpenBSD developers have little reason for a security model that prioritizes the ability for program A to implement workarounds for deficiencies in program B; their habit is fixing program B or refactoring A and B so they can work better together.
- _wldu 4y agoHere's a landlock wrapper for FireFox: https://github.com/62726164/misc/tree/main/go/landlock/firefox https://github.com/62726164/misc/tree/main/go/landlock/firef... It's more restrictive than Firejail and is not suid.