4 ms·
Leaving the home directory accessible is the exact problem that needs to be solved. An attacker doesn't need to break out of a sandbox to access the rest of my
by ori_b 7y ago
Leaving the home directory accessible is the exact problem that needs to be solved. An attacker doesn't need to break out of a sandbox to access the rest of my system: they can download it from debian.org. Being able to open new files after initialization is a bug.
The solution is to initialize the application before it can touch untrusted input, and then drop any ability to do anything other than process the resources set up in the init phase. The program will ideally be running in a completely empty namespace when handling untrusted data.
You can think of FDs as capabilities. Dropping the namespace prevents the program from requesting new capabilities. It's perverse to tie owning capabilities to being able to request new ones.
- cyphar 7y agoIf you are passing file descriptors to a sandboxed process from the host filesystem, it is very hard to defend against all attacks (especially if you pass directory fds). If you just pass a single file that can work fine, but it does make mistakes far more serious. I apologise for misreading your original problem. But the solution is identical -- bind-mount the individual files or subdirectories that you need the process to open.
- ori_b 7y agoIt really isn't that hard, and is exactly how privsep works on all of the OpenBSD daemons, augmented by pledge. Your proposed alternative allows untrusted code to gain new capabilities. That's not a design I want to trust.
- cyphar 7y agoI am trying to outline how you would do this on Linux. I appreciate OpenBSD has different facilities, but this is like telling a Japanese chef that their technique for dry-aging fish isn't that great because you know about an amazing way to roll out croissant dough. Yeah, it's nice that you have pledge() and unveil() but that doesn't help Linux programs.
- ori_b 7y agoLinux has the facilities needed for this -- they've existed in POSIX for ages. Doing a better job of it would be nice, but the suggested approach seems like a pretty big regression. Unveil() is irrelevant to this discussion, because your program ideally has nothing in its namespace to unveil. Pledge() is a useful additional layer of protection, dropping access to things that can't be controlled through the file system -- but Linux has seccomp-bpf that fills the same role. It's also unnecessary for privilege separation: It wasn't implemented until about 2 decades after the methods I'm talking about were in widespread use. And not just in OpenBSD -- from what I remember, Solaris had a section on it in their programming manuals. The principle is simple: Start the program, acquire capabilities (ie, fds) needed to do the job. Then, drop the ability to request capabilities, drop root, and start processing untrusted user input.