Opam's use of bwrap

So on linux systems, opam depends on bubblewrap / bwrap. That gives me a slightly unpleasant choice between enabling unprivileged user namespaces and making bwrap setuid root. All this is clearly linux specific, so I wonder how does opam manages to do its job on, say FreeBSD , or the other BSDs ?


Ian

opam init --disable-sandboxing
or
opam init --disable-sandboxing --reinit

I have not verified it.

I dont have enough insight on security matters and attack vectors. That is if you are worse off with this. Mac uses an osx native sandboxing/chroot alternative if I understand the documentation correctly.

from my understanding (excerpt of ~/.opam/config):

wrap-build-commands:
  ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"}
wrap-install-commands:
  ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"}
wrap-remove-commands:
  ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"}

Thus the sandbox.sh is only applied to macos and linux systems. On my FreeBSD, there’s not even a sandbox.sh being installed…

if anyone has ideas on how to have a no-configuration sandbox matching opam’s behaviour (system read-only, switch directory writeable, network access forbidden) on BSDs and Windows, similar to bubblewrap on Linux or sandbox-exec on macOS, feel free to open a ticket on the opam bugtracker:

2 Likes

I’ve no PR or a clean guideline in mind, but for FreeBSD I’d look into capsicum, and for OpenBSD into pledge – both allow to avoid system calls. I’m not sure whether this meets opam’s requirements.

Hypothetically if opam were to use eio, wouldn’t eio’s capabilities be able to provide these guarantees?

What opam needs is a way to execute arbitrary programs in restricted settings (a sandbox). I don’t know that much about eio capabilities but it looks like a way to not expose functionality to pieces of your code; it doesn’t prevent this code from getting that functionality in a different way.
So I believe it doesn’t help with opam’s problems.

1 Like

from what i understood from capsicum and pledge in the past and now looking at them again, this does not help for our sandboxing need.

For example even projects like capsicumizer which provides an interface similar to a simplified bubblewrap via a hack, requires functions that are used to access the system to be the ones that capsicum handles. Anything else will fail even though the necessary rights were given for it.

To me, this sort of lightweight system is only good for controlled C codebases and monolithic projects (e.g. freebsd-src/usr.bin, regular ports, …) and as soon as you need to execv some random binary with unknown behaviour in your program everything breaks down and it becomes very hard.

opam needs the later behaviour. To my knowledge the closest thing that we need on FreeBSD is going to be Jails. However afaik that requires some configuration from the root user to be usable and is not plug-and-play like the solutions for Linux & macOS are.

The situation is not that bad. As long as the program does not directly invoke the syscall assembly opcode, everything will work fine. So, one will encounter issues only with programs that have forcefully been statically linked against the libc or that have been compiled with the Go compiler. In most other cases, one can use a program unmodified by just preloading some trivial wrappers around system calls like open (cf the Preopen library).

The issue with Capsicum lies elsewhere. As I just wrote, you need to preload a wrapper, which means that your program supports dynamic libraries, which means that it relies on a runtime linker. Except that this runtime linker wants to traverse the filesystem to locate the shared libraries, which is forbidden by Capsicum. That is where things become a bit messy. Not only do you have to enable the current working directory, the temporary directory, etc, as you would with any sandbox, you also have to enable all the shared libraries that might later be loaded by the sandboxed program (and teach the runtime linker about them). This is fine for simple utility programs that rely purely on the libc, but it becomes quite tedious for larger programs.

1 Like