I’m using void linux and I’m looking to use nix as a “container” supplier for a sandboxing application such as bubblewrap (bwrap). Basically use nix as a source of packages since they are well packaged and nix has many unavailable on void.
So the objective is to have nix install/build the package and all its dependencies and have no further involvement in its operation. If that’s possible.
I wasn’t able to find in the documentation how nix is constituted so as to facilitate this behavior.
The way tools like bwrap operate is that they unshare most/all namespaces and read-only bind various binaries, libraries, and sockets into the freshly constructed environment before running the intended executable in it.
1 Like
I’m using void linux and I’m looking to use nix as a “container” supplier for a sandboxing application such as bubblewrap (bwrap). Basically use nix as a source of packages since they are well packaged and nix has many unavailable on void.
So the objective is to have nix install/build the package and all its dependencies and have no further involvement in its operation. If that’s possible.
I wasn’t able to find in the documentation how nix is constituted so as to facilitate this behavior.
The way tools like bwrap operate is that they unshare most/all namespaces and read-only bind various binaries, libraries, and sockets into the freshly constructed environment before running the intended executable in it.
I am not sure what exactly you are asking for, but I have definitely sent tarballs of runtime closures of Nix packages to be unpacked and used on machines with no Nix installed (it worked fine), and indeed bind-mounting Nix store as a whole or all of the paths in the closure one by one into a container-like environment also works fine without explicit interaction with Nix needed (Nix also does that for build sandboxing, but I can say I do such mounts with nsjail with no Nix-specific issues to handle)
So most probably what you want should be easy, and you want to read about build-time vs run-time dependency tracking in Nix, or maybe make the question more precise
Do you have an example of how you create the tarball and the nsjail config you use with it?
After you install a package with nix, I wasn’t able to find documentation on what happens when you launch the application, how are the pieces stitched together to be run etc. To be able to replicate this functionality with bwrap/nsjail/minijail/etc.
Do you have an example of how you create the tarball and the nsjail config you use with it?
Just tar -c $(nix-store -qR $(which command))
No nsjail config, just -B /nix/store
After you install a package with nix, I wasn’t able to find documentation on what happens when you launch the application, how are the pieces stitched together to be run etc. To be able to replicate this functionality with bwrap/nsjail/minijail/etc.
Nothing needing special support.
Kernel reads dynamic interpreter ELF entry, which happens to be inside Nix store, feeds the dynamic interpreter the program, the interpreter reads the completely standard RPATH entries from the binary, which happen to point into Nix store, loads necessary libraries, with the usual respect to RPATH. That’s it.
Perhaps my understanding of how Nix works is poor but what you are suggesting is that every binary was build with the awareness of every dependency’s precise path so that all you really have to do is launch an executable and it will know exactly where to load libraries and shared resources from within the /store/?
I had incorrectly assumed that Nix had to construct an traditional environment for every executable piecing together its dependencies from the /store/ with its own binds.
Perhaps my understanding of how Nix works is poor but what you are suggesting is that every binary was build with the awareness of every dependency’s precise path so that all you really have to do is launch an executable and it will know exactly where to load libraries and shared resources from within the /store/?
Do you know how RPATH works? Technically speaking, the precise path to all the dynamic libraries is not hardcoded; a set of library paths is hardcoded and then the libraries are searched there.
A lot of other shared resources are hardcoded as absolute paths at the build time anyway, or loaded relative to the executable’s path, so there we either just need to pass a configure option or put a symlink.
Sure, there are things loaded via environment variables like icon themes fort example, but then you go into the area of specific applications needing special environment.
I had incorrectly assumed that Nix had to construct an traditional environment for every executable piecing together its dependencies from the /store/ with its own binds.
There is support for such scripts in Nixpkgs but only for executables that resist being patched to provide a library path (buildFHSEnv) and there are enough problems with this approach that it is only used for proprietary stuff that actively interferes with our ability to use better ways.
I mean, you surely could read Eelco Dolstra’s PhD thesis after the Nix manual to make sure you do not miss basic assumptions of Nix, but then please make sure you read the documentation of the «normal» capabilities of the dynamic loader first, to have the context.
Does this mean that the approach to unshare-all and ro-bind /nix/store/ and just launch an executable from the store will not work for some proprietary packages? They must be launched by a nix binary from inside the sandbox?
I think the meaning is that this approach is reserved for the case where the program is very difficult to patch. Moreover, Nix is not involved in creating this sandbox, and there’s just a wrapper over the original executable, not unlike how bwrap
works.
This approach probably isn’t what you need as it is intended for compatibility not security.
1 Like
It is for packages that insist on /usr/lib
and resist this path being patched out to point into the Nix store; indeed, Nix is not involved in setting up the environment for them.